返回文章列表

集中式日誌記錄與監控最佳實踐

本文探討如何利用 Filebeat 和 Logstash 建立集中式日誌記錄與監控系統,涵蓋 Logstash 解析日誌、Filebeat 輕量級收集、Docker 日誌驅動整合以及 rsyslog 的組態,提供逐步操作和最佳實踐,有效提升系統可觀測性和問題排查效率。

系統管理 DevOps

隨著系統規模擴大,集中管理與分析日誌資料變得至關重要。本文將逐步闡述如何使用 Filebeat 和 Logstash 建構高效的集中式日誌系統,從單機日誌解析到多節點日誌收集,最終實作 Docker 容器日誌的整合與集中管理。我們將探討 Logstash 的 Grok 過濾器和日期過濾器外掛,以及如何組態 Logstash 以接收 Filebeat 傳輸的日誌。此外,我們將比較 Filebeat 和 Logstash 的優缺點,並解釋為何 Filebeat 更適合資源有限的環境。最後,我們將討論如何使用 Docker 的 syslog 日誌驅動程式,將容器日誌整合到集中式日誌系統中,並簡要介紹 rsyslog 的作用。

集中式日誌記錄與監控的進階實踐

在前面的章節中,我們已經實作了單一伺服器上的日誌集中管理。現在,我們將進一步探討如何解析日誌條目以提升查詢效率,並介紹如何將日誌傳送到中央 LogStash 例項。

解析日誌條目

LogStash 組態包含三個主要部分:輸入(input)、輸出(output)和過濾器(filters)。前面的範例僅使用了輸入和輸出部分,現在我們將介紹過濾器的使用。

LogStash 組態範例

input {
  file {
    path => "/logs/**/*"
  }
}

filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
  date {
    match => [ "timestamp" , "dd/MMM/yyyy:HH:mm:ss Z" ]
  }
}

output {
  stdout {
    codec => rubydebug
  }
  elasticsearch {
    hosts => db
  }
}

Grok 過濾器外掛

Grok 是 LogStash 中用於解析非結構化日誌資料的最佳工具。它根據正規表示式,並提供了許多預定義的模式。在我們的範例中,使用了 COMBINEDAPACHELOG 模式來解析 Apache 日誌。

日期過濾器外掛

日期過濾器外掛用於將日誌條目中的時間戳轉換為 LogStash 格式。

更新 LogStash 組態並測試

  1. 複製新的組態檔案到 LogStash 組態目錄:

    sudo cp /data/logstash/conf/file-with-filters.conf /data/logstash/conf/file.conf
    
  2. 重啟 LogStash:

    docker restart logstash
    
  3. 新增新的 Apache 日誌條目:

    cat /tmp/apache2.log >> /data/logstash/logs/apache.log
    
  4. 檢視 LogStash 日誌輸出:

    docker logs logstash
    

日誌輸出範例

{
  "message": "127.0.0.1 - - [12/Dec/2015:00:01:59 -0800] \"GET /api/v1/books/_id/5 HTTP/1.1\" 200 3891 \"http://cadenza/xampp/navi.php\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0\"",
  "@version": "1",
  "@timestamp": "2015-12-12T08:01:59+08:00",
  "host": "logging",
  "path": "/logs/apache.log",
  "clientip": "127.0.0.1",
  "ident": "-",
  "auth": "-",
  "timestamp": "12/Dec/2015:00:01:59 -0800",
  "verb": "GET",
  "request": "/api/v1/books/_id/5",
  "httpversion": "1.1",
  "response": "200",
  "bytes": "3891",
  "referrer": "\"http://cadenza/xampp/navi.php\"",
  "agent": "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0\""
}

在 Kibana 中檢視解析後的日誌

開啟 Kibana(例如:http://10.100.198.202:5601/),並調整時間範圍以檢視解析後的日誌條目。

將日誌條目傳送到中央 LogStash 例項

目前的解決方案仍然侷限於單一伺服器。為了實作跨伺服器的日誌集中管理,我們需要將日誌傳送到中央 LogStash 例項。

圖示:單一伺服器上的 ELK 堆積疊

此圖示展示了 ELK 堆積疊在單一伺服器上的佈署情況。

後續步驟

在下一章節中,我們將探討如何實作分散式日誌收集和集中式日誌解析,以滿足多伺服器環境下的日誌管理需求。

集中式日誌記錄與監控的最佳實踐

在現代化的IT基礎架構中,集中式日誌記錄與監控是至關重要的組成部分。它不僅能夠幫助我們更好地理解系統的執行狀態,還能在出現問題時提供寶貴的除錯資訊。本文將探討如何使用Filebeat和LogStash來實作高效的集中式日誌記錄與監控。

為什麼選擇Filebeat而非LogStash?

大多數公司可能會選擇在每台伺服器上安裝LogStash,並將日誌條目傳送到遠端的ElasticSearch。然而,這種做法存在一個重大問題:LogStash本身會消耗大量的系統資源。為了避免資源浪費,我們選擇了Filebeat作為日誌收集的工具。

Filebeat是一個輕量級的日誌檔案傳輸工具,是LogStash Forwarder的下一代產品。與LogStash相比,Filebeat具有以下優勢:

  • 資源效率高:Filebeat是用Go語言編寫的,並且針對日誌檔案的尾隨和傳送進行了最佳化,不會進行任何解析,因此佔用資源極少。
  • 易於佈署:由於其資源佔用小,可以安全地在所有伺服器上執行Filebeat,而不會對系統效能產生明顯影響。

組態LogStash以接收Filebeat的日誌

在使用Filebeat之前,我們需要修改LogStash的輸入組態。新的組態位於roles/logstash/files/beats.conf檔案中,其內容如下:

input {
  beats {
    port => 5044
  }
}

output {
  stdout {
    codec => rubydebug
  }
  elasticsearch {
    hosts => db
  }
}

內容解密:

  1. input 部分指定了使用 beats 外掛來監聽 5044 埠,以接收來自Filebeat的日誌。
  2. output 部分設定了兩個輸出目標:stdoutelasticsearchstdout 使用 rubydebug 編解碼器輸出到控制檯,便於除錯;elasticsearch 將日誌儲存到指定的ElasticSearch叢集中。

透過這個組態,我們可以執行單個LogStash例項,並讓所有其他伺服器將日誌傳送到這個埠。

佈署LogStash和Filebeat

首先,使用以下命令佈署LogStash:

ansible-playbook /vagrant/ansible/elk.yml \
  -i /vagrant/ansible/hosts/prod \
  --extra-vars "logstash_config=beats.conf"

接下來,我們需要在生產節點上佈署Filebeat。為此,我們使用了prod3.yml playbook,其中新增了filebeat角色。該角色的任務定義在roles/filebeat/tasks/main.yml檔案中,主要包括下載、安裝Filebeat包,複製組態檔案,以及啟動Filebeat服務。

Filebeat的組態檔案範例如下:

filebeat:
  prospectors:
    -
      paths:
        - "/var/log/**/*.log"

output:
  logstash:
    hosts: ["{{ elk_ip }}:5044"]

內容解密:

  1. filebeat.prospectors 部分定義了日誌檔案的探勘路徑。在本例中,Filebeat會查詢/var/log/目錄及其子目錄下所有以.log結尾的檔案。
  2. output.logstash 部分指定了將日誌傳送到LogStash,目標地址為 elk_ip:5044,即我們之前組態的LogStash例項。

集中式日誌記錄與監控

執行Filebeat並驗證日誌傳輸

在前面的章節中,我們已經探討瞭如何利用Filebeat將日誌從生產節點傳送到LogStash。現在,讓我們實際執行這個過程。首先,我們需要執行ansible-playbook命令來在生產節點上安裝和組態Filebeat。

ansible-playbook /vagrant/ansible/prod3.yml \
-i /vagrant/ansible/hosts/prod

內容解密:

  1. ansible-playbook:這是Ansible用來執行playbook的命令。
  2. /vagrant/ansible/prod3.yml:這是定義了在生產節點上安裝和組態Filebeat的playbook檔案路徑。
  3. -i /vagrant/ansible/hosts/prod:這個選項指定了Ansible用來識別目標主機的inventory檔案。

執行完上述命令後,Filebeat就已經在生產節點上執行了。接下來,我們可以檢查LogStash的日誌輸出,以驗證Filebeat是否成功地將日誌傳送到了LogStash。

docker -H tcp://logging:2375 \
logs logstash

內容解密:

  1. docker:這是Docker的命令列工具。
  2. -H tcp://logging:2375:這個選項指定了Docker守護程式的連線地址和埠。
  3. logs logstash:這個命令用於取得LogStash容器的日誌輸出。

從LogStash的日誌輸出中,我們可以看到Filebeat成功地將日誌從生產節點傳送到了LogStash。日誌條目包含了諸如日誌來源、時間戳等重要資訊。

驗證Kibana中的日誌資料

現在,讓我們開啟Kibana的網頁介面,驗證日誌資料是否已經被成功地索引和儲存。

請存取 http://10.100.198.202:5601/。如果沒有看到任何日誌條目,可能需要調整時間範圍。

內容解密:

  1. Kibana網頁介面地址:http://10.100.198.202:5601/是用來存取Kibana的URL。
  2. 時間範圍調整:如果沒有看到日誌條目,需要檢查時間範圍是否正確。

提升方案:將日誌傳送到集中式LogStash

既然我們已經成功地將主機的日誌傳送到LogStash,接下來讓我們探討如何將Docker容器的日誌也傳送到集中式的LogStash例項中。

為什麼不直接分享容器日誌目錄?

直接分享容器日誌目錄作為卷(volume)並不是最佳實踐。原因在於,這樣會增加容器與宿主機之間的耦合度,使得容器的可移植性降低。

Docker日誌驅動的優勢

Docker從1.6版本開始引入了日誌驅動(logging driver)的特性,這為Docker環境下的日誌管理提供了更靈活的解決方案。除了預設的json-file驅動外,還有syslog、journald、gelf、fluentd、splunk和awslogs等多種驅動可供選擇。

選擇適合的日誌驅動

GELF(Greylog Extended Log Format)驅動是一個不錯的選擇,因為它支援LogStash。然而,如果我們不僅需要收集容器內服務的日誌,還需要收集系統其他部分的日誌,那麼就需要考慮其他方案。

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 集中式日誌記錄與監控最佳實踐

package "Docker 架構" {
    actor "開發者" as dev

    package "Docker Engine" {
        component [Docker Daemon] as daemon
        component [Docker CLI] as cli
        component [REST API] as api
    }

    package "容器運行時" {
        component [containerd] as containerd
        component [runc] as runc
    }

    package "儲存" {
        database [Images] as images
        database [Volumes] as volumes
        database [Networks] as networks
    }

    cloud "Registry" as registry
}

dev --> cli : 命令操作
cli --> api : API 呼叫
api --> daemon : 處理請求
daemon --> containerd : 容器管理
containerd --> runc : 執行容器
daemon --> images : 映像檔管理
daemon --> registry : 拉取/推送
daemon --> volumes : 資料持久化
daemon --> networks : 網路配置

@enduml

此圖示展示了利用Docker Logging Driver將容器日誌傳送到LogStash的流程。

集中式日誌記錄與監控

在集中式日誌記錄與監控的架構中,選擇適當的日誌收集工具至關重要。我們可能會選擇 JournalD 或 syslog 來收集日誌。這樣一來,我們不僅能獲得容器內的日誌,還能收集整個作業系統層級的日誌資訊。後者(JournalD 或 syslog)是較佳的選擇,尤其是當 ElasticSearch 有足夠的記憶體可用時(因為日誌量越大,記憶體消耗越多)。本文將探討後者的實作。

LogStash 組態詳解

首先,我們使用 roles/logstash/files/syslog.conf 檔案作為 LogStash 的組態檔案。下面將逐一解析該組態檔案的各個部分。

輸入區段

input {
  syslog {
    type => "syslog"
    port => 25826
  }
}

此區段定義了 LogStash 的輸入來源。我們使用了 syslog 外掛,並設定了兩個引數:typeporttype 引數為所有由此輸入處理的事件增加了一個型別欄位,有助於區分來自 syslog 的日誌和其他來源的日誌。port 引數指定了 LogStash 監聽 syslog 事件的埠為 25826。

篩選區段

filter {
  if "docker/" in [program] {
    mutate {
      add_field => {
        "container_id" => "%{program}"
      }
    }
    mutate {
      gsub => [
        "container_id", "docker/", ""
      ]
    }
    mutate {
      update => [
        "program", "docker"
      ]
    }
  }
  if [container_id] == "nginx" {
    grok {
      match => [ "message" , "%{COMBINEDAPACHELOG} %{HOSTPORT:upstream_address} %{NOTSPACE:upstream_response_time}"]
    }
    mutate {
      convert => ["upstream_response_time", "float"]
    }
  }
}

此區段首先檢查 program 欄位是否包含 docker/。如果是,則進行一系列的變換操作:新增一個名為 container_id 的欄位、移除 container_id 中的 docker/ 字首、以及將 program 欄位的值更新為 docker。接著,如果 container_id 等於 nginx,則使用 grok 篩選器解析訊息欄位,並新增 upstream_addressupstream_response_time 兩個欄位。最後,將 upstream_response_time 欄位從字串轉換為浮點數。

輸出區段

output {
  stdout {
    codec => rubydebug
  }
  elasticsearch {
    hosts => db
  }
}

此區段定義了 LogStash 的輸出目的地。我們將篩選後的日誌事件輸出到標準輸出(使用 rubydebug 編碼)和 ElasticSearch。

佈署 LogStash 與組態 syslog

在瞭解組態檔案後,我們可以透過 Ansible playbook elk.yml 佈署 LogStash。

ansible-playbook /vagrant/ansible/elk.yml \
  -i /vagrant/ansible/hosts/prod \
  --extra-vars "logstash_config=syslog.conf"

接著,我們需要移除目前執行的 nginx 例項,並重新執行它,同時設定 Docker 日誌驅動程式為 syslog。此外,我們還會在 prod 節點上佈署 syslog。使用的 playbook 是 prod4.yml

- hosts: prod
  remote_user: vagrant
  serial: 1
  vars:
    - log_to_syslog: yes
  roles:
    - common
    - docker
    - docker-compose
    - consul
    - registrator
    - consul-template
    - nginx
    - rsyslog

roles/nginx/tasks/main.yml 中,與日誌相關的設定如下:

- name: Container is running
  docker:
    image: nginx
    name: nginx
    state: running
    ports: "{{ ports }}"
    volumes: "{{ volumes }}"
    log_driver: syslog
    log_opt:
      syslog-tag: nginx
  when: log_to_syslog is defined
  tags: [nginx]

這裡設定了 Docker 日誌驅動程式為 syslog,並指定了 syslog 標籤為 nginx

rsyslog 設定

roles/rsyslog/tasks/main.yml 中,相關任務如下:

- name: Packages are present
  apt:
    name: "{{ item }}"
    state: latest
    install_recommends: no
  with_items:
    - rsyslog
    - logrotate
  tags: [rsyslog]

這確保了 rsyslog 和 logrotate 軟體包已安裝並更新至最新版本。