配置 Liveness、Readiness 和 Startup 探針
此頁面展示瞭如何為容器配置存活探針、就緒探針和啟動探針。
有關探針的更多資訊,請參閱存活探針、就緒探針和啟動探針
kubelet 使用存活探針來知道何時重啟容器。例如,存活探針可以捕獲死鎖,即應用程式正在執行,但無法取得進展。在這種狀態下重啟容器有助於使應用程式在存在 Bug 的情況下更可用。
存活探針的常見模式是使用與就緒探針相同的低成本 HTTP 端點,但具有更高的 failureThreshold。這確保了在 Pod 被硬殺死之前,它被觀察到在一段時間內處於非就緒狀態。
kubelet 使用就緒探針來知道容器何時準備好開始接收流量。此訊號的一個用途是控制哪些 Pod 用作 Service 的後端。當 Pod 的 Ready
Condition 為 true 時,它被認為是就緒的。當 Pod 未就緒時,它會從 Service 負載均衡器中移除。當 Pod 的節點的 Ready
Condition 不為 true 時,當 Pod 的一個 readinessGates
為 false 時,或者當其至少一個容器未就緒時,Pod 的 Ready
Condition 為 false。
kubelet 使用啟動探針來知道容器應用程式何時啟動。如果配置了此類探針,則存活探針和就緒探針不會開始,直到它成功,確保這些探針不會干擾應用程式啟動。這可用於在啟動緩慢的容器上採用存活檢查,避免它們在啟動並執行之前被 kubelet 殺死。
注意
存活探針是恢復應用程式故障的強大方式,但應謹慎使用。必須仔細配置存活探針,以確保它們真正指示不可恢復的應用程式故障,例如死鎖。注意
存活探針的錯誤實現可能導致級聯故障。這會導致容器在高負載下重啟;由於應用程式可伸縮性降低,客戶端請求失敗;以及由於某些失敗的 Pod,剩餘 Pod 的工作負載增加。瞭解就緒探針和存活探針之間的區別以及何時將它們應用於你的應用程式。準備工作
你需要有一個 Kubernetes 叢集,並且 kubectl 命令列工具已配置為與你的叢集通訊。建議在至少有兩個不作為控制平面主機的節點上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者你可以使用這些 Kubernetes 操場之一
定義存活命令
許多長時間執行的應用程式最終會進入損壞狀態,除了重啟之外無法恢復。Kubernetes 提供了存活探針來檢測和補救此類情況。
在本練習中,你將建立一個 Pod,它執行一個基於 registry.k8s.io/busybox:1.27.2
映象的容器。以下是 Pod 的配置檔案
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: registry.k8s.io/busybox:1.27.2
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
在配置檔案中,你可以看到 Pod 有一個 Container
。periodSeconds
欄位指定 kubelet 應該每 5 秒執行一次存活探針。initialDelaySeconds
欄位告訴 kubelet 它應該等待 5 秒鐘,然後執行第一次探針。為了執行探針,kubelet 在目標容器中執行命令 cat /tmp/healthy
。如果命令成功,它返回 0,kubelet 認為容器是存活且健康的。如果命令返回非零值,kubelet 會殺死容器並重新啟動它。
容器啟動時,它會執行此命令
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"
在容器生命的前 30 秒,存在一個 /tmp/healthy
檔案。因此,在前 30 秒內,命令 cat /tmp/healthy
返回成功程式碼。30 秒後,cat /tmp/healthy
返回失敗程式碼。
建立 Pod
kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml
在 30 秒內,檢視 Pod 事件
kubectl describe pod liveness-exec
輸出表明尚未有存活探針失敗
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 11s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulling 9s kubelet, node01 Pulling image "registry.k8s.io/busybox:1.27.2"
Normal Pulled 7s kubelet, node01 Successfully pulled image "registry.k8s.io/busybox:1.27.2"
Normal Created 7s kubelet, node01 Created container liveness
Normal Started 7s kubelet, node01 Started container liveness
35 秒後,再次檢視 Pod 事件
kubectl describe pod liveness-exec
在輸出底部,有訊息指示存活探針已失敗,並且失敗的容器已被殺死並重新建立。
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 57s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulling 55s kubelet, node01 Pulling image "registry.k8s.io/busybox:1.27.2"
Normal Pulled 53s kubelet, node01 Successfully pulled image "registry.k8s.io/busybox:1.27.2"
Normal Created 53s kubelet, node01 Created container liveness
Normal Started 53s kubelet, node01 Started container liveness
Warning Unhealthy 10s (x3 over 20s) kubelet, node01 Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing 10s kubelet, node01 Container liveness failed liveness probe, will be restarted
再等待 30 秒,並驗證容器已重新啟動
kubectl get pod liveness-exec
輸出顯示 RESTARTS
已增加。請注意,RESTARTS
計數器在失敗的容器返回到執行狀態後立即增加
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
定義存活 HTTP 請求
另一種存活探針使用 HTTP GET 請求。以下是一個 Pod 的配置檔案,該 Pod 執行一個基於 registry.k8s.io/e2e-test-images/agnhost
映象的容器。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: registry.k8s.io/e2e-test-images/agnhost:2.40
args:
- liveness
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
在配置檔案中,你可以看到 Pod 有一個容器。periodSeconds
欄位指定 kubelet 應該每 3 秒執行一次存活探針。initialDelaySeconds
欄位告訴 kubelet 它應該等待 3 秒鐘,然後執行第一次探針。為了執行探針,kubelet 會向容器中執行並在埠 8080 上監聽的伺服器傳送 HTTP GET 請求。如果伺服器的 /healthz
路徑的處理程式返回成功程式碼,kubelet 會認為容器是存活且健康的。如果處理程式返回失敗程式碼,kubelet 會殺死容器並重新啟動它。
任何大於或等於 200 且小於 400 的程式碼表示成功。任何其他程式碼表示失敗。
你可以在 server.go 中檢視伺服器的原始碼。
在容器存活的前 10 秒內,/healthz
處理程式返回狀態 200。之後,處理程式返回狀態 500。
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
kubelet 在容器啟動 3 秒後開始執行健康檢查。因此,最初的幾次健康檢查將成功。但 10 秒後,健康檢查將失敗,kubelet 將殺死並重新啟動容器。
要嘗試 HTTP 存活檢查,請建立一個 Pod
kubectl apply -f https://k8s.io/examples/pods/probe/http-liveness.yaml
10 秒後,檢視 Pod 事件以驗證存活探針已失敗且容器已重新啟動
kubectl describe pod liveness-http
在 v1.13 之後的版本中,本地 HTTP 代理環境變數設定不會影響 HTTP 存活探針。
定義 TCP 存活探針
第三種類型的存活探針使用 TCP 套接字。透過此配置,kubelet 將嘗試在指定埠上開啟與容器的套接字。如果能夠建立連線,則容器被認為是健康的;如果不能,則被認為是失敗的。
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: registry.k8s.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
如你所見,TCP 檢查的配置與 HTTP 檢查非常相似。此示例同時使用了就緒探針和存活探針。kubelet 將在容器啟動 15 秒後執行第一個存活探針。它將嘗試連線到 goproxy
容器的 8080 埠。如果存活探針失敗,容器將重新啟動。kubelet 將每 10 秒繼續執行此檢查。
除了存活探針,此配置還包括一個就緒探針。kubelet 將在容器啟動 15 秒後執行第一個就緒探針。與存活探針類似,它將嘗試連線到 goproxy
容器的 8080 埠。如果探針成功,Pod 將被標記為就緒並接收來自服務的流量。如果就緒探針失敗,Pod 將被標記為未就緒並且不會接收來自任何服務的流量。
要嘗試 TCP 存活檢查,請建立一個 Pod
kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml
15 秒後,檢視 Pod 事件以驗證存活探針
kubectl describe pod goproxy
定義 gRPC 存活探針
Kubernetes v1.27 [穩定]
如果你的應用程式實現了 gRPC 健康檢查協議,此示例展示瞭如何配置 Kubernetes 以將其用於應用程式存活檢查。同樣,你可以配置就緒探針和啟動探針。
這是一個示例清單
apiVersion: v1
kind: Pod
metadata:
name: etcd-with-grpc
spec:
containers:
- name: etcd
image: registry.k8s.io/etcd:3.5.1-0
command: [ "/usr/local/bin/etcd", "--data-dir", "/var/lib/etcd", "--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"]
ports:
- containerPort: 2379
livenessProbe:
grpc:
port: 2379
initialDelaySeconds: 10
要使用 gRPC 探針,必須配置 port
。如果你想區分不同型別的探針和不同功能的探針,可以使用 service
欄位。你可以將 service
設定為 liveness
,並使你的 gRPC 健康檢查端點對此請求的響應與將 service
設定為 readiness
時不同。這允許你為不同型別的容器健康檢查使用相同的端點,而不是監聽兩個不同的埠。如果你想指定自己的自定義服務名稱並同時指定探針型別,Kubernetes 專案建議你使用將這些名稱連線起來的名稱。例如:myservice-liveness
(使用 -
作為分隔符)。
注意
與 HTTP 或 TCP 探針不同,你不能按名稱指定健康檢查埠,也不能配置自定義主機名。配置問題(例如:埠或服務不正確,未實現的健康檢查協議)被視為探針失敗,類似於 HTTP 和 TCP 探針。
要嘗試 gRPC 存活檢查,請使用以下命令建立一個 Pod。在下面的示例中,etcd Pod 配置為使用 gRPC 存活探針。
kubectl apply -f https://k8s.io/examples/pods/probe/grpc-liveness.yaml
15 秒後,檢視 Pod 事件以驗證存活檢查未失敗
kubectl describe pod etcd-with-grpc
使用 gRPC 探針時,需要注意一些技術細節
- 探針針對 Pod IP 地址或其主機名執行。請務必將你的 gRPC 端點配置為監聽 Pod 的 IP 地址。
- 探針不支援任何身份驗證引數(如
-tls
)。 - 內建探針沒有錯誤程式碼。所有錯誤都被視為探針失敗。
- 如果
ExecProbeTimeout
功能門設定為false
,grpc-health-probe 將**不**遵守timeoutSeconds
設定(預設為 1 秒),而內建探針將在超時時失敗。
使用命名埠
你可以為 HTTP 和 TCP 探針使用命名 port
。gRPC 探針不支援命名埠。
例如
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
使用啟動探針保護啟動緩慢的容器
有時,你必須處理在首次初始化時需要額外啟動時間的應用程式。在這種情況下,很難設定存活探針引數,而不會影響死鎖的快速響應,這是此類探針的動機。解決方案是使用相同的命令、HTTP 或 TCP 檢查設定啟動探針,其中 failureThreshold * periodSeconds
足夠長以覆蓋最壞情況的啟動時間。
因此,前面的示例將變為
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 1
periodSeconds: 10
startupProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 30
periodSeconds: 10
由於啟動探針,應用程式將有最長 5 分鐘 (30 * 10 = 300s) 完成其啟動。一旦啟動探針成功一次,存活探針就會接管,以快速響應容器死鎖。如果啟動探針從未成功,容器將在 300 秒後被殺死並受 Pod 的 restartPolicy
約束。
定義就緒探針
有時,應用程式暫時無法提供流量。例如,應用程式可能需要在啟動期間載入大型資料或配置檔案,或者在啟動後依賴外部服務。在這種情況下,你不想殺死應用程式,但你也不想向它傳送請求。Kubernetes 提供了就緒探針來檢測和緩解這些情況。容器報告未就緒的 Pod 不會透過 Kubernetes Services 接收流量。
注意
就緒探針在容器的整個生命週期中執行。注意
就緒探針和存活探針的成功不相互依賴。如果你想在執行就緒探針之前等待,你應該使用initialDelaySeconds
或 startupProbe
。就緒探針的配置類似於存活探針。唯一的區別是你使用 readinessProbe
欄位而不是 livenessProbe
欄位。
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
HTTP 和 TCP 就緒探針的配置也與存活探針相同。
就緒探針和存活探針可以同時用於同一個容器。同時使用兩者可以確保流量不會到達尚未就緒的容器,並在容器失敗時重新啟動。
配置探針
探針有許多欄位,你可以使用它們更精確地控制啟動、存活和就緒檢查的行為
initialDelaySeconds
:容器啟動後,在啟動、存活或就緒探針啟動之前的秒數。如果定義了啟動探針,則存活和就緒探針的延遲不會開始,直到啟動探針成功。如果periodSeconds
的值大於initialDelaySeconds
,則initialDelaySeconds
將被忽略。預設為 0 秒。最小值為 0。periodSeconds
:執行探針的頻率(秒)。預設為 10 秒。最小值為 1。當容器未就緒時,ReadinessProbe
可能會在配置的periodSeconds
間隔之外的時間執行。這是為了更快地使 Pod 就緒。timeoutSeconds
:探針超時前的秒數。預設為 1 秒。最小值為 1。successThreshold
:探針在失敗後被認為是成功的最小連續成功次數。預設為 1。對於存活探針和啟動探針,必須為 1。最小值為 1。failureThreshold
:探針連續失敗failureThreshold
次後,Kubernetes 認為整體檢查已失敗:容器**未**就緒/健康/存活。預設為 3。最小值為 1。對於啟動或存活探針,如果至少有failureThreshold
次探針失敗,Kubernetes 會將容器視為不健康並觸發該特定容器的重啟。kubelet 遵守該容器的terminationGracePeriodSeconds
設定。對於失敗的就緒探針,kubelet 繼續執行失敗檢查的容器,並繼續執行更多探針;由於檢查失敗,kubelet 將 Pod 上的Ready
condition 設定為false
。terminationGracePeriodSeconds
:配置一個寬限期,讓 kubelet 在觸發關閉失敗容器和強制容器執行時停止該容器之間等待。預設為繼承 Pod 級別的terminationGracePeriodSeconds
值(如果未指定,則為 30 秒),最小值為 1。有關更多詳細資訊,請參閱探針級別的terminationGracePeriodSeconds
。
注意
就緒探針的錯誤實現可能導致容器中程序數量不斷增加,如果不對其進行檢查,則會導致資源耗盡。HTTP 探針
HTTP 探針有可以在 httpGet
上設定的附加欄位
host
:要連線的主機名,預設為 Pod IP。你可能希望在httpHeaders
中設定 "Host"。scheme
:用於連線主機的方案(HTTP 或 HTTPS)。預設為 "HTTP"。path
:HTTP 伺服器上要訪問的路徑。預設為 "/"。httpHeaders
:要在請求中設定的自定義頭部。HTTP 允許重複頭部。port
:容器上要訪問的埠的名稱或編號。編號必須在 1 到 65535 的範圍內。
對於 HTTP 探針,kubelet 向指定的埠和路徑傳送 HTTP 請求以執行檢查。kubelet 將探針傳送到 Pod 的 IP 地址,除非地址被 httpGet
中可選的 host
欄位覆蓋。如果 scheme
欄位設定為 HTTPS
,kubelet 會發送 HTTPS 請求,跳過證書驗證。在大多數情況下,你不需要設定 host
欄位。這裡有一個你會設定它的場景。假設容器監聽 127.0.0.1,並且 Pod 的 hostNetwork
欄位為 true。那麼 httpGet
下的 host
應該設定為 127.0.0.1。如果你的 Pod 依賴於虛擬主機(這可能是更常見的情況),則不應使用 host
,而應在 httpHeaders
中設定 Host
頭部。
對於 HTTP 探針,kubelet 除了強制性的 Host
頭部之外,還會發送兩個請求頭部
User-Agent
:預設值為kube-probe/1.34
,其中1.34
是 kubelet 的版本。Accept
:預設值為*/*
。
你可以透過為探針定義 httpHeaders
來覆蓋預設頭部。例如
livenessProbe:
httpGet:
httpHeaders:
- name: Accept
value: application/json
startupProbe:
httpGet:
httpHeaders:
- name: User-Agent
value: MyUserAgent
你也可以透過將這兩個頭定義為空值來移除它們。
livenessProbe:
httpGet:
httpHeaders:
- name: Accept
value: ""
startupProbe:
httpGet:
httpHeaders:
- name: User-Agent
value: ""
注意
當 kubelet 使用 HTTP 探測 Pod 時,它只在重定向到同一主機時才遵循重定向。如果 kubelet 在探測期間收到 11 次或更多重定向,則認為探測成功並建立相關事件
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 29m default-scheduler Successfully assigned default/httpbin-7b8bc9cb85-bjzwn to daocloud
Normal Pulling 29m kubelet Pulling image "docker.io/kennethreitz/httpbin"
Normal Pulled 24m kubelet Successfully pulled image "docker.io/kennethreitz/httpbin" in 5m12.402735213s
Normal Created 24m kubelet Created container httpbin
Normal Started 24m kubelet Started container httpbin
Warning ProbeWarning 4m11s (x1197 over 24m) kubelet Readiness probe warning: Probe terminated redirects
如果 kubelet 收到重定向,其中主機名與請求不同,則探針的結果被視為成功,kubelet 建立一個事件來報告重定向失敗。
TCP 探針
對於 TCP 探針,kubelet 在節點上建立探針連線,而不是在 Pod 中,這意味著你不能在 host
引數中使用服務名稱,因為 kubelet 無法解析它。
探針級別 terminationGracePeriodSeconds
Kubernetes v1.28 [stable]
在 1.25 及更高版本中,使用者可以在探針規範中指定探針級別的 terminationGracePeriodSeconds
。當同時設定了 Pod 級別和探針級別的 terminationGracePeriodSeconds
時,kubelet 將使用探針級別的值。
設定 terminationGracePeriodSeconds
時,請注意以下事項
如果 Pod 上存在探針級別的
terminationGracePeriodSeconds
欄位,kubelet 總是會遵守它。如果你有已設定
terminationGracePeriodSeconds
欄位的現有 Pod,並且你不再希望使用每個探針的終止寬限期,則必須刪除這些現有 Pod。
例如
spec:
terminationGracePeriodSeconds: 3600 # pod-level
containers:
- name: test
image: ...
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 1
periodSeconds: 60
# Override pod-level terminationGracePeriodSeconds #
terminationGracePeriodSeconds: 60
就緒探針不能設定探針級別的 terminationGracePeriodSeconds
。它將被 API 伺服器拒絕。
下一步
- 瞭解有關容器探針的更多資訊。
你還可以閱讀以下 API 參考