隨著系統規模擴大,集中管理與分析日誌資料變得至關重要。本文將逐步闡述如何使用 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 組態並測試
複製新的組態檔案到 LogStash 組態目錄:
sudo cp /data/logstash/conf/file-with-filters.conf /data/logstash/conf/file.conf重啟 LogStash:
docker restart logstash新增新的 Apache 日誌條目:
cat /tmp/apache2.log >> /data/logstash/logs/apache.log檢視 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
}
}
內容解密:
input部分指定了使用beats外掛來監聽 5044 埠,以接收來自Filebeat的日誌。output部分設定了兩個輸出目標:stdout和elasticsearch。stdout使用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"]
內容解密:
filebeat.prospectors部分定義了日誌檔案的探勘路徑。在本例中,Filebeat會查詢/var/log/目錄及其子目錄下所有以.log結尾的檔案。output.logstash部分指定了將日誌傳送到LogStash,目標地址為elk_ip:5044,即我們之前組態的LogStash例項。
集中式日誌記錄與監控
執行Filebeat並驗證日誌傳輸
在前面的章節中,我們已經探討瞭如何利用Filebeat將日誌從生產節點傳送到LogStash。現在,讓我們實際執行這個過程。首先,我們需要執行ansible-playbook命令來在生產節點上安裝和組態Filebeat。
ansible-playbook /vagrant/ansible/prod3.yml \
-i /vagrant/ansible/hosts/prod
內容解密:
ansible-playbook:這是Ansible用來執行playbook的命令。/vagrant/ansible/prod3.yml:這是定義了在生產節點上安裝和組態Filebeat的playbook檔案路徑。-i /vagrant/ansible/hosts/prod:這個選項指定了Ansible用來識別目標主機的inventory檔案。
執行完上述命令後,Filebeat就已經在生產節點上執行了。接下來,我們可以檢查LogStash的日誌輸出,以驗證Filebeat是否成功地將日誌傳送到了LogStash。
docker -H tcp://logging:2375 \
logs logstash
內容解密:
docker:這是Docker的命令列工具。-H tcp://logging:2375:這個選項指定了Docker守護程式的連線地址和埠。logs logstash:這個命令用於取得LogStash容器的日誌輸出。
從LogStash的日誌輸出中,我們可以看到Filebeat成功地將日誌從生產節點傳送到了LogStash。日誌條目包含了諸如日誌來源、時間戳等重要資訊。
驗證Kibana中的日誌資料
現在,讓我們開啟Kibana的網頁介面,驗證日誌資料是否已經被成功地索引和儲存。
請存取 http://10.100.198.202:5601/。如果沒有看到任何日誌條目,可能需要調整時間範圍。
內容解密:
- Kibana網頁介面地址:
http://10.100.198.202:5601/是用來存取Kibana的URL。 - 時間範圍調整:如果沒有看到日誌條目,需要檢查時間範圍是否正確。
提升方案:將日誌傳送到集中式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 外掛,並設定了兩個引數:type 和 port。type 引數為所有由此輸入處理的事件增加了一個型別欄位,有助於區分來自 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_address 和 upstream_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 軟體包已安裝並更新至最新版本。