最近上班開始寫一些部署在 Kubernetes 的 service,在研究 Kubernetes Deployment 時,發現 Pod 可以設定 livenessProbe 和 readinessProbe。
一開始我搞不太清楚兩者之間的差異,以為它們只是不同名字而已,畢竟兩個都是去檢查應用程式有沒有活著。但看了許多網路上的範例,發現它們倆時常一起出現在 deployment.yml。
其實,它們回答的是兩個完全不同的問題:
- Liveness:你的程式是不是死掉了?
- Readiness:你的程式準備好提供服務了嗎?
雖然都叫做 Probe,但用途完全不同。如果沒有理解這個概念,很容易造成 Deployment 一直重啟,或是流量被送到還沒準備好的 Pod。
什麼是 Probe?
在 Kubernetes 中,Probe 是一種健康檢查(Health Check)機制,用來讓 Kubernetes 主動確認 Container 目前的運行狀態。
你可以把它想成 Kubernetes 定期向你的應用程式發送一個「你現在還好嗎?」的詢問,也就是 Kubernetes 版的 Health Check。
那既然 Kubernetes 已經知道 Pod 是否處於 Running 狀態,為什麼還需要 Probe 呢?
原因是 Pod 處於 Running,只代表 Container 已經成功啟動,而且裡面的 Process 仍然存在,並不代表應用程式已經可以正常提供服務。
例如:
- 資料庫連線可能尚未建立完成。
- 對外依賴的服務(如 Elasticsearch、Prometheus)可能暫時無法存取。
- 應用程式可能發生 Deadlock,導致 API 沒有回應。
- 某些 Thread 可能已經卡住,但 Process 仍然存在。
這些情況下,Pod 仍然會顯示為 Running,但實際上服務已經無法正常運作。
因此,Kubernetes 提供了 Probe,讓它能夠主動檢查應用程式真正的健康狀態,而不是只看 Container 是否存在。
最常見的 Probe 方式是透過 HTTP GET。開發者需要在程式中提供對應的 API Endpoint,Kubernetes 則會依照 deployment.yaml 中的設定,定期向這些 Endpoint 發送 HTTP Request,並根據回傳的 HTTP Status Code 判斷目前的健康狀態。
Liveness Probe vs. Readiness Probe
就以我最近在開發的服務為例。
我有一個使用 FastAPI 搭配 Uvicorn 啟動的 Python 專案,對外提供一支 /api/v1/test API。當使用者呼叫這支 API 時,它會先向 Prometheus 與 Elasticsearch 取得資料,經過轉換後,再寫入 MariaDB。
如果在 Kubernetes 中設定了 livenessProbe 與 readinessProbe,就需要額外提供兩個健康檢查用的 API Endpoint,例如 /healthz 和 /ready(名稱可以自行定義)。
Liveness Probe
livenessProbe 會定期呼叫 /healthz。
這支 API 的目的非常單純:確認應用程式本身是否仍然正常運作。
因此,大部分情況下,只要應用程式能正常處理請求,就回傳 200 OK 即可。
原因在於,Liveness Probe 回答的問題只有一個:「這個 Container 裡的應用程式還活著嗎?」
只要 /healthz 能持續正常回應,Kubernetes 就會認為這個 Container 仍然健康,不需要重新啟動。
用 Python,我們可以很簡單地寫:
@app.get("/healthz")
async def healthz():
return {"status": "OK"}ReadinessProbe
相比之下,Readiness Probe 的邏輯就比較複雜一些。
除了應用程式本身需要正常運作之外,我們還必須確認所有提供服務所需的依賴也都處於可用狀態。
以我的服務為例,在處理 /api/v1/test 時,需要依賴 Prometheus、Elasticsearch 以及 MariaDB。因此,/ready這支 API 會額外檢查這三個服務的健康狀態:確認 Prometheus 和 Elasticsearch 的 Ready API 可以正常回應,同時確認 MariaDB 可以成功建立連線。
只有當所有依賴都處於正常狀態時,/ready 才會回傳 200 OK;只要其中任何一個檢查失敗,就會回傳 503 Service Unavailable。
當 Kubernetes 收到 200 OK 時,便會認為這個 Pod 已經準備好提供服務,並開始將流量導向它;反之,如果收到 503,則會暫時停止將新的 Request 導向這個 Pod,直到下一次檢查通過為止。
@app.get("/ready")
async def ready():
checks = {
"elasticsearch": await check_es(),
"prometheus": await check_prometheus(),
"mariadb": await check_mariadb(),
}
if all(checks.values()):
return {"status": "ready"}
return JSONResponse(
status_code=503,
content={
"status": "not ready",
"dependencies": checks,
},
)Kubernetes Deployment 定義
有了 /healthz 和 /ready 之後,我們就可以在 Deployment 中定義對應的 Probe。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-python-service
spec:
replicas: 1
selector:
matchLabels:
app: my-python-service
template:
metadata:
labels:
app: my-python-service
spec:
containers:
- name: my-python-service
image: my-python-service:latest
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5path 就是 Kubernetes 要去呼叫的 API Endpoint,而 periodSeconds 則代表每隔幾秒重新檢查一次。
以下是常用的參數定義:
| 參數 | 説明 |
|---|---|
initialDelaySeconds | Container 啟動後,等待幾秒才開始第一次 Probe |
periodSeconds | 每隔幾秒檢查一次 |
timeoutSeconds | 每次 Probe 最多等待多久 |
failureThreshold | 連續失敗幾次才算真正失敗 |
successThreshold | (Readiness Probe 常用)連續成功幾次才恢復 Ready |
設定完成後,Kubernetes 就會定期呼叫這兩支 API,並依照回傳的 HTTP Status Code 決定接下來要採取什麼動作。
那 Kubernetes 收到結果後會做什麼?
Liveness Probe 和 Readiness Probe 最大的差別在於 檢查失敗後 Kubernetes 的處理方式完全不同。
Liveness Probe 失敗
如果 /healthz 一直沒有回傳 200,例如程式發生 Deadlock、無限迴圈、Memory Leak,或是 API 已經完全沒有回應,Kubernetes 就會認為這個 Container 已經無法正常運作。
這時候 Kubelet 會重新啟動 Container,希望透過 Restart 的方式恢復服務。
也就是說,Liveness Probe 決定的是 Container 要不要被重新啟動。
Readiness Probe 失敗
Readiness Probe 則不同。
假設今天 Elasticsearch 因為維護暫時無法連線,/ready 回傳了 503。
這並不代表我的 API 壞掉了,只是它目前沒有能力完成使用者的請求。
因此 Kubernetes 不會重新啟動 Container,而是把這個 Pod 從 Service 的 Endpoints 中暫時移除,不再將新的流量導向它。
等到 Elasticsearch 恢復正常,/ready 再次回傳 200 後,Kubernetes 就會自動把這個 Pod 加回 Service,重新開始接收流量,整個過程不需要重新部署,也不需要重新啟動 Container。
為什麼不能把兩個 Probe 都寫成一樣?
既然 /ready 已經檢查了所有 dependency,為什麼不直接把 Liveness Probe 也指向 /ready?
原因就在於兩者的目的不同。
如果今天 Elasticsearch 暫時掛掉,/ready 會回傳 503。
假如 Liveness Probe 也去檢查 /ready,Kubernetes 就會誤以為是整個 Container 壞掉,開始不停地重新啟動服務。
但問題是,就算重啟了十次、一百次,只要 Elasticsearch 還沒有恢復,/ready 一樣還是會回傳 503。
最後很可能讓 Pod 一直陷入 CrashLoopBackOff。
因此,Liveness Probe 應該只檢查應用程式本身是否仍然正常運作;而 Readiness Probe 則負責檢查整個服務是否已具備提供功能所需要的所有依賴。
總結
雖然 Liveness Probe 和 Readiness Probe 都屬於 Kubernetes 的健康檢查(Health Check),但它們解決的是完全不同的問題。
- Liveness Probe:確認程式是否還活著。如果檢查失敗,Kubernetes 會重新啟動 Container。
- Readiness Probe:確認程式是否已經準備好提供服務。如果檢查失敗,Kubernetes 只會停止將流量導向這個 Pod,不會重新啟動它。
理解這兩種 Probe 的差異後,在設計 API 或部署微服務時,就能更清楚知道哪些檢查應該放在 /healthz,哪些則應該放在 /ready,也能避免因為 Probe 設定錯誤而造成不必要的重啟或服務中斷。

發表留言