事故筆記
一次探針誤判,如何把服務打進重啟循環
有些事故不是程式壞掉,而是健康檢查把原本能活下來的服務判成該重啟。這篇記一個很典型的坑。
有些生產事故很戲劇化。
有些則比較陰,因為服務本來不一定會死,結果是我們自己用探針把它推下去的。
事故長相通常長這樣
- 新版本上線
- 應用啟動比平常慢一點
- liveness probe 太早開始打
- 探針連續失敗
- kubelet 幫你重啟
- 重啟之後 cache 又沒熱、依賴又重新連,於是更慢
- 然後你得到一個漂亮的 restart loop
這類問題最煩的地方,是表面上看起來像「程式一直掛掉」,但其實程式根本還在努力啟動。
真正的問題通常不是探針本身
通常是這三件事組合起來:
- 我們沒有分清楚 readiness 跟 liveness 的責任
- 啟動時間的假設太樂觀
- rollout 速度快到來不及觀察異常
如果 livenessProbe 太激進,它就會把「只是慢」誤判成「已經死了」。
我會先看什麼
kubectl describe pod <pod-name> -n <ns>
kubectl logs <pod-name> -n <ns> --previous
kubectl get events -n <ns> --sort-by=.lastTimestamp
我要確認的是:
- 是 readiness fail 還是 liveness fail?
- 重啟前最後的 log 在做什麼?
- 事件裡有沒有明確寫 probe failed / killing container?
比較穩的做法
- readiness 嚴格一點,避免還沒準備好就接流量
- liveness 保守一點,避免太早重啟
- 啟動真的慢的服務,先考慮
startupProbe - rollout 不要衝太快,給自己看圖和看 log 的時間
我自己的偏見
健康檢查不是越兇越好。
在 production,錯把慢服務殺掉,很多時候比暫時等它恢復更糟。
探針的目的不是展現你多會寫 YAML,而是幫系統在不確定裡做出比較不蠢的判斷。