19.2 ELK 套件
ELK (Elasticsearch,Logstash,Kibana) 是目前業界最流行的開源日誌解決方案。而在容器領域,由於 Fluentd 更加輕量級且對容器支援更好,EFK (Elasticsearch,Fluentd,Kibana) 組合也變得非常流行。
19.2.1 方案架構
我們將採用以下架構:
- Docker Container:容器將日誌輸出到標準輸出 (stdout/stderr)。
- Fluentd:作為 Docker 的 Logging Driver 或執行為守護容器,收集容器日誌。
- Elasticsearch:儲存從 Fluentd 接收到的日誌資料。
- Kibana:從 Elasticsearch 讀取資料並進行視覺化展示。
19.2.2 部署流程
我們將使用 Docker Compose 來一鍵部署整個日誌堆疊。
1. 編寫 Compose 檔案
- 編寫
compose.yaml(或docker-compose.yml) 設定如下。版本提示:本範例使用 Elasticsearch 9.x、Kibana 9.x、Fluentd 等元件的特定版本號,僅作為參考。生產環境部署前,請查閱 Elastic 官方文件 和 Fluentd 官方文件 確認最新版本與設定相容性。
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:9.4.0
container_name: elasticsearch
environment:
- "discovery.type=single-node"
- "xpack.security.enabled=false"
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- logging
kibana:
image: docker.elastic.co/kibana/kibana:9.4.0
container_name: kibana
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
networks:
- logging
fluentd:
# elasticsearch8 外掛透過 REST API 與 ES 9.x 相容
image: fluent/fluentd-kubernetes-daemonset:v1.17-debian-elasticsearch8-1
container_name: fluentd
environment:
- "FLUENT_ELASTICSEARCH_HOST=elasticsearch"
- "FLUENT_ELASTICSEARCH_PORT=9200"
- "FLUENT_ELASTICSEARCH_SCHEME=http"
- "FLUENT_UID=0"
ports:
- "24224:24224"
- "24224:24224/udp"
volumes:
- ./fluentd/conf:/fluentd/etc
networks:
- logging
volumes:
es_data:
networks:
logging:
2. 設定 Fluentd
建立 fluentd/conf/fluent.conf:
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
<match *.**>
@type copy
<store>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix docker
logstash_dateformat %Y%m%d
include_tag_key true
tag_key @log_name
flush_interval 1s
</store>
<store>
@type stdout
</store>
</match>
3. 設定應用容器使用 fluentd 驅動
啟動一個測試容器,指定日誌驅動為 fluentd:
docker run -d \
--log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag=nginx-test \
--name nginx-test \
nginx
注意:確保 fluentd 容器已經啟動並監聽在 localhost:24224。在生產環境中,如果你是在不同機器上,需要將 localhost 替換為執行 fluentd 的主機 IP。
4. 在 Kibana 中檢視日誌
- 訪問
http://localhost:5601。 - 進入 Management->Kibana->Index Patterns。
- 建立新的 Index Pattern,輸入
docker-*(我們在 fluent.conf 中設定的字首)。 - 選擇
@timestamp作為時間欄位。 - 去 Discover 頁面,你就能看到 Nginx 容器的日誌了。
Kibana 建索引模式常見坑
首次接入 EFK/ELK 時,『Elasticsearch 有數據但 Kibana 看不到』很常見,通常是 Kibana 設定或時間視窗問題:
- Index Pattern 不對應:確認 Kibana 的 Index Pattern 與實際索引字首一致。可以先用
_cat/indices檢視真實索引名。 - 時間欄位選擇錯誤:若索引裡包含
@timestamp,一般選擇它;如果選擇了錯誤的欄位,會導致 Discover 無法按時間篩選。 - 時間視窗/時區:Discover 右上角的時間範圍預設可能是最近 15 分鐘,且時區可能影響顯示。建議先把範圍擴大到最近 24 小時再驗證。
- 資料解析失敗:若日誌是非結構化文字,仍可入庫但欄位不可用;生產環境建議輸出 JSON 並在採集端解析。
5. 驗證日誌是否寫入 Elasticsearch:生產排錯必備
當你在 Kibana 看不到日誌時,建議先跳過 UI,從儲存端直接驗證『日誌是否入庫』。
-
檢視索引是否建立:
curl -s http://localhost:9200/_cat/indices?v如果 Fluentd 使用了
logstash_format true且logstash_prefix docker,通常會看到形如docker-YYYY.MM.DD的索引。 -
檢視最近一段時間的日誌文件:
curl -s -H 'Content-Type: application/json' \ http://localhost:9200/docker-*/_search \ -d '{"size":1,"sort":[{"@timestamp":"desc"}]}'
如果 Elasticsearch 中已經有文件,但 Kibana 仍然為空,常見原因是:
- Index Pattern 沒對應到索引 (例如寫成了
docker-*但實際索引字首不同)。 - 時間欄位沒選對或時區不一致,導致 Discover 時間視窗內看不到資料。
19.2.3 總結
透過 Docker 的日誌驅動機制,結合 ELK/EFK 強大的收集和分析能力,我們可以輕鬆建立一個能夠處理海量日誌的監控平台,這對於排查生產問題至關重要。
19.2.4 生產要點
在生產環境中,日誌系統往往比監控系統更容易因為『容量與寫入壓力』出問題,建議特別關注:
- 容量規劃:日誌增長速度與磁碟佔用直接相關。建議設定日誌保留週期與索引生命週期策略 (ILM),避免 Elasticsearch 因磁碟水位觸發只讀或不可用。
- 資源設定:Elasticsearch 對 JVM Heap 較敏感。除範例中的
ES_JAVA_OPTS外,生產環境需要結合節點記憶體、分片規模、查詢壓力做評估。 - 鏈路可靠性:採集端到儲存端要考慮網路抖動、背壓與重試策略;當 Elasticsearch 寫入變慢時,採集端的緩衝與落盤策略決定了是否會丟日誌。
- 日誌格式:推薦應用輸出結構化日誌 (JSON) 幷包含關鍵字段 (如
trace_id、request_id、service、env),以便快速過濾與關聯分析。
索引與保留策略的落地建議
無論是 EFK 還是 ELK,生產上都需要回答兩個問題:
- 日誌保留多久?
- 保留期內的日誌如何保證可查詢、不過度佔用儲存?
建議按環境與業務重要性對日誌分層,並制定不同的保留週期,例如:
- 生產環境:7~30 天
- 測試環境:1~7 天
實現方式通常有兩類:
- 按天捲動索引:如
docker-YYYY.MM.DD,再定期刪除過期索引。 - 使用 ILM:定義 Hot/Warm/Cold/刪除階段,按時間與容量自動捲動與回收。
對於中小規模叢集,先把『按天捲動 + 過期刪除』做紮實,往往就能解決 80% 的容量問題;當日志量上來、查詢壓力變大後,再逐步引入 ILM、分層儲存與更精細的分片規劃。
最小可用的『過期索引清理』範例
如果你採用按天捲動索引 (例如 docker-YYYY.MM.DD),可以透過 Elasticsearch API 定期清理過期索引。
下面範例僅用於示範思路:獲取所有 docker- 字首索引並刪除指定索引。生產環境建議基於日期計算、灰度驗證與許可權控制後再執行自動化清理。
-
列出索引:
curl -s http://localhost:9200/_cat/indices/docker-*?v -
刪除某個過期索引 (範例):
curl -X DELETE http://localhost:9200/docker-2026.02.01
如果你希望更自動化的治理能力,可以進一步使用 ILM 為索引設定捲動與刪除策略。