cover

Metrics 告訴你「發生了什麼」,Logs 告訴你「為什麼發生」。如果每次事故都要 SSH 進 5 台機器用 grep 翻 log,那不是排查,是在大海撈針。

先講結論

所有服務的 log 進同一個系統、用結構化 JSON 格式、有 request_id 可以跨服務追蹤、設好 ILM(生命週期管理)避免磁碟爆掉。EFK(Elasticsearch + Fluentd + Kibana)是一套經典的組合,但核心觀念比工具重要。

結構化日誌:不要只印一段字

ERROR: something went wrong

這行 log 告訴你什麼?幾乎什麼都沒有。誰觸發的?哪個服務?什麼 request?

{
  "level": "error",
  "service": "order-api",
  "request_id": "req-abc123",
  "user_id": "u-456",
  "message": "payment gateway timeout",
  "duration_ms": 3200
}

JSON log 讓你可以在 Kibana 裡用 service:order-api AND level:error 精準查詢,而不是用 grep 猜關鍵字。

stdout 為優先

容器世界最穩定的 log 方式就是寫到 stdout。不依賴 file mount、log driver 可以統一設定、Docker 原生就會幫你收。

不要在容器裡面自己寫 log 到檔案——你還得設 log rotation、mount volume、然後擔心磁碟滿。直接 stdout,讓外面的 collector 去處理。

EFK 基本部署

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
    ports:
      - "127.0.0.1:9200:9200"
    volumes:
      - es-data:/usr/share/elasticsearch/data
 
  kibana:
    image: docker.elastic.co/kibana/kibana:8.12.0
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
 
  fluentd:
    image: fluent/fluentd:latest
    volumes:
      - ./fluentd.conf:/fluentd/etc/fluentd.conf
    ports:
      - "24224:24224"
 
volumes:
  es-data:

Docker 服務的 log 透過 fluentd driver 送過去:

services:
  api:
    image: registry.example.com/app/api:v1.8.0
    logging:
      driver: fluentd
      options:
        fluentd-address: "localhost:24224"
        tag: "api"

ILM:不設 retention 等於等著爆

Elasticsearch 不會自動清資料。你的 log 只會越來越多,直到磁碟滿、ES 掛掉、Kibana 開不起來。

基線策略:hot 7 天、warm 30 天、delete 60 天。實際時間依流量調整,但一定要設。我看過有人跑了半年沒設 ILM,ES 吃了 500GB,然後某天突然 read-only 因為磁碟 watermark 到了。

最重要的欄位:request_id

如果你只能在 log 裡加一個欄位,加 request_id

一個 HTTP request 從 API gateway 進來,經過 auth service、order service、payment service。有 request_id 的話,你可以在 Kibana 搜一次就看到整條鏈路。沒有的話?你在每台機器上用時間戳去對——而且你永遠不確定對的是不是同一個 request。


Log 就像監視器錄影。平常沒人看,但出事的時候它是你唯一能還原現場的東西。前提是你有裝、有錄、而且沒有被覆蓋掉。