K8s · 維運與部署 · 第 30 課 · · 11min read

K8s Probe 完整教學:Liveness、Readiness、Startup 三種健康檢查

Pod 顯示 Running 不代表服務正常。Probe 是 K8s 的「敲門檢查」:Liveness 看活著沒、Readiness 看能接流量沒、Startup 給慢啟動程式緩衝。

#Kubernetes #Probe #Liveness #Readiness #健康檢查
章節目錄 · 10

Pod Running ≠ 服務正常

凌晨三點,你的 API 服務「Running」狀態,但客戶反映:首頁打不開

\\\bash
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-api-xxx 1/1 Running 0 3h
\
\\

看起來一切正常。但你 curl 一下:

\\\bash
curl http://my-api/health
# (沒回應,hang 住...)
\
\\

Pod 是活的,但程式卡死了。可能是:

  • Java 應用 OOM 但沒有 crash,只是 GC 不停
  • Node.js event loop 卡住(同步阻塞)
  • 死鎖、無窮迴圈
  • 連到外部資料庫的連線池耗盡
K8s 怎麼知道?答案就是 Probe(健康檢查)

三種 Probe,各司其職

K8s 提供三種 Probe,每一種解決不同的問題:

Probe問的問題失敗怎麼辦用在哪
livenessProbe你還活著嗎?重啟容器偵測死鎖、卡死
readinessProbe你準備好接流量了嗎?從 Service 摘下啟動中、暫時過載
startupProbe你啟動完了嗎?重啟容器啟動慢的應用(Java)
用餐廳比喻:
  • liveness = 廚師還有心跳嗎?沒有就換一個。
  • readiness = 廚師準備好出菜沒?還沒好就先不送單進去。
  • startup = 廚師還在熱鍋嗎?等他熱好再檢查其他的。

三種檢查方式

每種 Probe 都可以用以下三種方式來檢查:

方式說明適合
httpGet打 HTTP,回 200-399 算過Web API
tcpSocket嘗試連線該 portMySQL、Redis 等非 HTTP
exec在容器內執行指令,exit 0 算過自訂檢查邏輯

YAML 寫法

\\\yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-probe-demo
spec:
template:
spec:
containers:
- name: api
image: my-api:1.0
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
startupProbe:
httpGet:
path: /healthz
port: 80
failureThreshold: 30
periodSeconds: 10
\
\\

關鍵參數

參數意義
\initialDelaySeconds\啟動後等多久才開始檢查
\periodSeconds\多久檢查一次
\timeoutSeconds\等多久算超時
\failureThreshold\連續失敗幾次才算掛
\successThreshold\連續成功幾次算恢復(readiness 用)

Liveness 失敗會怎樣?

實作一次給你看:

\\\bash
# 進去 Pod,把 /healthz 端點故意搞壞
POD=$(kubectl get pods -l app=api-probe-demo -o jsonpath='{.items[0].metadata.name}')
kubectl exec $POD -- rm /app/healthz

# 觀察 Pod 狀態
kubectl get pods -l app=api-probe-demo -w
\
\\

你會看到:

\\\
NAME READY STATUS RESTARTS
api-probe-demo 1/1 Running 0
api-probe-demo 0/1 Running 1 ← 重啟了!
api-probe-demo 1/1 Running 1 ← 恢復
\
\\

RESTARTS 變成 1——K8s 偵測到 liveness 失敗,自動重啟容器。

Readiness 失敗會怎樣?

關鍵差別:不重啟,但摘掉流量

\\\bash
# 看 Service 的 Endpoints
kubectl get endpoints my-api-svc
# NAME ENDPOINTS AGE
# my-api-svc 10.42.0.5:80,10.42.0.6:80 5m

# 把 10.42.0.5 的 readiness 弄壞
# 等 5 秒後再看:
kubectl get endpoints my-api-svc
# NAME ENDPOINTS AGE
# my-api-svc 10.42.0.6:80 5m ← 10.42.0.5 不見了!
\
\\

這就是 readiness 的精髓——程式還活著,但暫時不健康(如資料庫連線斷了),K8s 就先不要把流量送過來,等它恢復再說。

為什麼要 startupProbe?

Java / Spring Boot 啟動可能要 30-60 秒。如果只設 livenessProbe:

\\\yaml
livenessProbe:
httpGet:
path: /healthz
initialDelaySeconds: 5 # ← 5 秒後就開始檢查
failureThreshold: 3 # ← 連續失敗 3 次就重啟
\
\\

結果:

  • Pod 啟動,5 秒後開始檢查

  • Spring Boot 還沒啟動完,每次檢查都失敗

  • 連續失敗 3 次,K8s 把容器重啟

  • 永遠啟動不起來——陷入「啟動 → 失敗 → 重啟」迴圈
  • 解法是 startupProbe

    \\\yaml
    startupProbe:
    httpGet:
    path: /healthz
    failureThreshold: 30 # 失敗 30 次才放棄
    periodSeconds: 10 # 每 10 秒一次 → 最多容忍 5 分鐘啟動
    \
    \\

    startupProbe 沒過之前,liveness 和 readiness 都不會跑。等啟動好了,才換成正常的 liveness 監控。

    三個 Probe 該怎麼配?

    最佳實踐:

    \\\yaml
    # 啟動慢 → startupProbe 寬鬆
    startupProbe:
    failureThreshold: 30
    periodSeconds: 10

    # 活著就好 → liveness 簡單一點
    livenessProbe:
    failureThreshold: 3
    periodSeconds: 10

    # 流量精細控制 → readiness 嚴格
    readinessProbe:
    failureThreshold: 1
    periodSeconds: 5
    \
    \\

    Liveness 不要設太嚴格——容易誤殺正在處理請求的 Pod。Readiness 要敏感——出問題趕快摘流量,恢復後再回來。

    重點整理

    • Pod Running ≠ 程式正常,要有 Probe 才知道
    • Liveness 失敗 → 重啟Readiness 失敗 → 摘流量Startup 給慢啟動緩衝
    • 三種檢查方式:httpGet / tcpSocket / exec
    • Java 應用幾乎都需要 startupProbe,避免啟動迴圈
    • Liveness 寬鬆、Readiness 敏感,避免誤殺

    下一步

    健康檢查有了,但程式還是會吃光記憶體 / CPU。一個 Pod 失控吃掉 16GB 記憶體,會把整個 Node 拖垮,其他 Pod 全部跟著掛。

    下一篇:Resource Limits 與 OOMKilled — 怎麼防止單一 Pod 拖垮整個 Node

    📅 下一篇Resource Limits 與 OOMKilled:怎麼防止單一 Pod 拖垮整個 Node
    requests / limits 兩個欄位設好,Pod 互不打架——順便看 K8s QoS 三層級。
    📚 完整系列總覽K8s 系列教學首頁(共 40 課,按學習路徑順序排)