問題

在本機架 ELK 日誌平台(Elasticsearch/Kibana/Filebeat 9.5.4,安全機制打開、只收一般應用日誌),收一個 kotlin-ktor 服務的單行 JSON log。過程卡了六次,每一次的錯誤訊息都指向錯的方向。

解法

#症狀真正原因解法
1拉 9.5.5 的 image 失敗版本清單(artifacts API)列出的版本,image 還沒發用 docker manifest inspect 逐一確認三個 image 都在,挑都在的最新版(9.5.4)
29.5.4、9.5.3 也「拉不到」指令包了 60 秒 timeout,1–2GB 的 image 拉不完,逾時被當成不存在存在與否用 manifest 查;真的拉放背景、不設短逾時
3怕收到同一台機器上別的開發棧預設 autodiscover 會收所有容器hints.default_config.enabled: false,只收貼了 label 的容器(opt-in)。label 放在 ELK 自己的 override 檔,不改來源服務的 repo
4驗收突然出現 53 筆 stack 碎片來源服務一啟動就當掉,JVM 在 logger 之外印出多行純文字 stack這不是管線的錯:「應用程式 log 一律是單行 JSON」這條規則,只管得到經過 logger 的輸出,管不到程序在 logger 之外直接印的東西。啟動失敗靠容器狀態與告警抓;碎片檢查只看這一輪之後的文件
5來源服務第二次啟動就當祕密每次隨機產生,舊 MySQL volume 還是舊密碼 → Access denied拋棄式來源每次 down -v 再起
6「錯誤行都要有 stack」驗不過一個失敗請求有兩筆 ERROR:APP channel 帶完整 stack,ACCESS channel 只用 stackTraceId 指過去驗「至少一筆完整多行 stack、沒有碎片」,不是每筆都要有

第 3 點的設定,官方文件的說法是:把 hints.default_config.enabled 設成 false,就只會收貼了啟用 hint(co.elastic.logs/enabled)的容器(Filebeat autodiscover hints)。我在驗收裡實測,同一台機器上另一個沒貼 label 的開發棧是 0 筆。

做對了、也驗過的設計:

  • 收集端重啟不掉資料:Filebeat 停掉期間的 log,重啟後從 registry 記的位置補回。官方文件寫的是 Filebeat 會把每個檔案的讀取位置定期寫進 registry,重啟後從最後已知位置繼續(How Filebeat works)。我的驗收是反向做的:停掉 Filebeat 再送請求,驗收必紅;重新啟動、不重送請求,同一個 requestId 的 3 筆與錯誤行自己補回來,驗收轉綠。
  • 最小權限要反向驗:收集帳號讀資料、刪資料流、看帳號清單都必須回 403,不是只驗「寫得進去」。

為什麼這樣解

  • 第 1、2 點是同一種錯:「查不到」有好幾種原因(不存在、沒權限、逾時),工具常常回一樣的失敗。要用能區分原因的方法查,而不是重試同一個指令——這跟比錯基準是同一族:檢查跑了、有輸出,但量的不是你以為的東西。
  • 第 3 點:不收不該收的,比收了再過濾可靠,也不會把別人的資料拉進這個平台的稽核範圍。
  • 第 4、6 點:驗收條件要跟資料的真實形狀對齊。寫得太鬆會假綠,寫得太嚴會把正常設計判成錯。
  • 第 5 點:「每次都產生新祕密」和「資料保留」不能同時成立,要選一個。拋棄式環境選前者。

怎麼預防再次發生

  • 選版本:版本清單只是候選。真正能用的版本,以 registry 上所有用到的 image 都存在為準。
  • 「失敗」先分清楚原因:逾時、不存在、沒權限,用不同的指令確認,不要拿同一個失敗結果下結論。
  • 日誌收集預設 opt-in,並把「沒貼 label 的容器 0 筆」寫進驗收。
  • 驗收要附反向驗證:停掉收集端必紅;權限檢查驗「被拒」。
  • 帶隨機祕密的拋棄式環境,啟動前一律清乾淨。

相關