系統環境:
- kubernetes 版本:1.19.0
Kubernetes 官方文檔地址:
一、Pod 的整個生命階段
- Pending: 正在創建 Pod,但是 Pod 中的容器還沒有全部被創建完成,這其中也包含集群為容器創建網絡,或者下載鏡像的過程。
- Running: Pod 內所有的容器都已經被創建,且至少一個容器正在處於運行狀態、正在啟動狀態或者重啟狀態。
- Succeeded: Pod 中所以容器都執行成功后退出,並且沒有處於重啟的容器。
- Failed: Pod 中所以容器都已退出,但是至少還有一個容器退出時為失敗狀態。
- Unknown: 由於一些原因,Pod 的狀態無法獲取,通常是與 Pod 通信時出錯導致的。
二、Pod 重啟策略
Pod的重啟策略包括Always、OnFailure和Never,默認值為Always。
- Always:當容器失效時,由kubelet自動重啟該容器;
- OnFailure:當容器終止運行且退出碼不為0時,由kubelet自動重啟該容器;
- Never:不論容器運行狀態如何,kubelet都不會重啟該容器。
kubelet重啟失效容器的時間間隔以sync-frequency乘以2n來計算,例如1/2/4/8倍等,最長延時5min,並且在成功重啟后的10min后重置該時間。
Pod的重啟策略與控制方式關聯,當前可用於管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接管理kubelet管理(靜態Pod)。
- RC和DaemonSet:必須設置為Always,需要保證該容器持續運行;
- Job:OnFailure或Never,確保容器執行完成后不再重啟;
- kubelet:在Pod失效時重啟,不論將RestartPolicy設置為何值,也不會對Pod進行健康檢查。
三、Pod 常見狀態轉換場景
Pod中的容器數 | Pod狀態 | 發生事件 | 不同重啟策略下的結果狀態 | ||
Always | OnFailure | Never | |||
包含一個容器 | Running | 容器成功退出 | Running | Succeeded | Succeeded |
包含一個容器 | Running | 容器失敗退出 | Running | Running | Failed |
包含兩個容器 | Running | 1個容器失敗退出 | Running | Running | Running |
包含兩個容器 | Running | 容器內存溢出掛掉 | Running | Running | Failed |
四、Pod 的活性與就緒探針
1、Pod 探針機制
在 Kubernetes 中 Pod 是最小的計算單元,而一個 Pod 又由多個容器組成,相當於每個容器就是一個應用,應用在運行期間,可能因為某也意外情況致使程序掛掉。那么如何監控這些容器狀態穩定性,保證服務在運行期間不會發生問題,發生問題后進行重啟等機制,就成為了重中之重的事情,考慮到這點 kubernetes 推出了活性探針機制。
有了活性探針后能保證程序在運行中如果掛掉能夠自動重啟,但是還有個經常遇到的問題,比如說,在 Kubernetes 中啟動 Pod,顯示明明 Pod 已經啟動成功,且能訪問里面的端口,但是卻返回錯誤信息。還有就是在執行滾動更新時候,總會出現一段時間,Pod 對外提供網絡訪問,但是訪問卻發生 404,這兩個原因,都是因為 Pod 已經成功啟動,但是 Pod 的的容器中應用程序還在啟動中導致,考慮到這點 Kubernetes 推出了就緒探針機制。
2、Pod 兩種探針簡介
- LivenessProbe(存活探針): 存活探針主要作用是,用指定的方式進入容器檢測容器中的應用是否正常運行,如果檢測失敗,則認為容器不健康,那么 Kubelet 將根據 Pod 中設置的 restartPolicy (重啟策略)來判斷,Pod 是否要進行重啟操作,如果容器配置中沒有配置 livenessProbe 存活探針,Kubelet 將認為存活探針探測一直為成功狀態。
- ReadinessProbe(就緒探針): 用於判斷容器中應用是否啟動完成,當探測成功后才使 Pod 對外提供網絡訪問,設置容器 Ready 狀態為 true,如果探測失敗,則設置容器的 Ready 狀態為 false。對於被 Service 管理的 Pod,Service 與 Pod、EndPoint 的關聯關系也將基於 Pod 是否為 Ready 狀態進行設置,如果 Pod 運行過程中 Ready 狀態變為 false,則系統自動從 Service 關聯的 EndPoint 列表中移除,如果 Pod 恢復為 Ready 狀態。將再會被加回 Endpoint 列表。通過這種機制就能防止將流量轉發到不可用的 Pod 上。
3、Pod 探針的探測方式與結果
目前 LivenessProbe 和 ReadinessProbe 兩種探針都支持下面三種探測方法:
- ExecAction: 在容器中執行指定的命令,如果執行成功,退出碼為 0 則探測成功。
- HTTPGetAction: 通過容器的IP地址、端口號及路徑調用 HTTP Get方法,如果響應的狀態碼大於等於200且小於400,則認為容器 健康。
- TCPSocketAction: 通過容器的 IP 地址和端口號執行 TCP 檢 查,如果能夠建立 TCP 連接,則表明容器健康。
探針探測結果有以下值:
- Success:表示通過檢測。
- Failure:表示未通過檢測。
- Unknown:表示檢測沒有正常進行。
4、Pod 探針的相關屬性
探針(Probe)有許多可選字段,可以用來更加精確的控制Liveness和Readiness兩種探針的行為(Probe):
- initialDelaySeconds: Pod 啟動后首次進行檢查的等待時間,單位“秒”。
- periodSeconds: 檢查的間隔時間,默認為 10s,單位“秒”。
- timeoutSeconds: 探針執行檢測請求后,等待響應的超時時間,默認為 1s,單位“秒”。
- successThreshold: 探針檢測失敗后認為成功的最小連接成功次數,默認為 1s,在 Liveness 探針中必須為 1s,最小值為 1s。
- failureThreshold: 探測失敗的重試次數,重試一定次數后將認為失敗,在 readiness 探針中,Pod會被標記為未就緒,默認為 3s,最小值為 1s。
5、兩種探針的區別
ReadinessProbe 和 livenessProbe 可以使用相同探測方式,只是對 Pod 的處置方式不同:
- readinessProbe 當檢測失敗后,將 Pod 的 IP:Port 從對應的 EndPoint 列表中刪除。
- livenessProbe 當檢測失敗后,將殺死容器並根據 Pod 的重啟策略來決定作出對應的措施。
五、探針使用示例
1、LivenessProbe 探針使用示例
1)通過exec方式做健康探測
示例文件 liveness-exec.yaml
apiVersion: v1 kind: Pod metadata: name: liveness-exec labels: app: liveness spec: containers: - name: liveness image: busybox args: #創建測試探針探測的文件 - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 livenessProbe: initialDelaySeconds: 10 #延遲檢測時間 periodSeconds: 5 #檢測時間間隔 exec: command: - cat - /tmp/healthy
查看Pod日志詳情
[root@k8s-master yaml]# kubectl describe pod liveness-exec Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 7m4s Successfully assigned default/liveness-exec to k8s-node1 Normal Pulled 6m47s kubelet, k8s-node1 Successfully pulled image "busybox" in 16.176728723s Normal Pulled 5m20s kubelet, k8s-node1 Successfully pulled image "busybox" in 15.640787963s Normal Created 3m50s (x3 over 6m47s) kubelet, k8s-node1 Created container liveness Normal Started 3m50s (x3 over 6m47s) kubelet, k8s-node1 Started container liveness Normal Pulled 3m50s kubelet, k8s-node1 Successfully pulled image "busybox" in 15.626708424s Normal Killing 3m6s (x3 over 6m6s) kubelet, k8s-node1 Container liveness failed liveness probe, will be restarted Normal Pulling 2m35s (x4 over 7m4s) kubelet, k8s-node1 Pulling image "busybox" Warning Unhealthy 2m1s (x10 over 6m16s) kubelet, k8s-node1 Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory [root@k8s-master yaml]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liveness-exec 1/1 Running 4 7m8s 10.244.36.75 k8s-node1 <none> <none>
容器在初始化后,首先創建一個 /tmp/healthy 文件,然后執行睡眠命令,睡眠 30 秒,到時間后執行刪除 /tmp/healthy 文件命令。而設置的存活探針檢檢測方式為執行 shell 命令,用 cat 命令輸出 healthy 文件的內容,如果能成功執行這條命令,存活探針就認為探測成功,否則探測失敗。在前 30 秒內,由於文件存在,所以存活探針探測時執行 cat /tmp/healthy 命令成功執行。30 秒后 healthy 文件被刪除,所以執行命令失敗,Kubernetes 會根據 Pod 設置的重啟策略來判斷,是否重啟 Pod。
2)通過HTTP方式做健康探測
示例文件 liveness-http.yaml
apiVersion: v1 kind: Pod metadata: name: liveness-http labels: test: liveness spec: containers: - name: liveness image: wuxinchun/springboot-helloworld:v1 livenessProbe: initialDelaySeconds: 20 #延遲加載時間 periodSeconds: 5 #重試時間間隔 timeoutSeconds: 10 #超時時間設置 httpGet: scheme: HTTP port: 8081 path: /actuator/healthtest #這是測試path,正確的地址為:/actuator/health
查看Pod日志
[root@k8s-master yaml]# kubectl describe pod liveness-http Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m28s Successfully assigned default/liveness-http to k8s-node1 Normal Pulled 46s (x4 over 2m28s) kubelet, k8s-node1 Container image "mydlqclub/springboot-helloworld:0.0.1" already present on machine Normal Created 46s (x4 over 2m28s) kubelet, k8s-node1 Created container liveness Normal Killing 46s (x3 over 116s) kubelet, k8s-node1 Container liveness failed liveness probe, will be restarted Normal Started 45s (x4 over 2m28s) kubelet, k8s-node1 Started container liveness Warning Unhealthy 21s (x10 over 2m6s) kubelet, k8s-node1 Liveness probe failed: HTTP probe failed with statuscode: 404 [root@k8s-master yaml]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liveness-http 1/1 Running 4 2m33s 10.244.36.77 k8s-node1 <none> <none> nginx-6799fc88d8-s4nqr 1/1 Running 0 3d3h 10.244.36.65 k8s-node1 <none> <none>
上面 Pod 中啟動的容器是一個 SpringBoot 應用,其中引用了 Actuator 組件,提供了 /actuator/health 健康檢查地址,存活探針可以使用 HTTPGet 方式向服務發起請求,請求 8081 端口的 /actuator/health 路徑來進行存活判斷:
- 任何大於或等於200且小於400的代碼表示探測成功。
- 任何其他代碼表示失敗。
如果探測失敗,則會殺死 Pod 進行重啟操作。
httpGet探測方式有如下可選的控制字段:
- scheme: 用於連接host的協議,默認為HTTP。
- host: 要連接的主機名,默認為Pod IP,可以在http request head中設置host頭部。
- port: 容器上要訪問端口號或名稱。
- path: http服務器上的訪問URI。
- httpHeaders: 自定義HTTP請求headers,HTTP允許重復headers。
3)通過TCP方式做健康探測
示例文件 liveness-tcp.yaml
apiVersion: v1 kind: Pod metadata: name: liveness-tcp labels: app: liveness spec: containers: - name: liveness image: nginx livenessProbe: initialDelaySeconds: 15 #執行第一次探測之前等待15秒 periodSeconds: 20 #每20秒執行一次活躍度探測 tcpSocket: port: 81 #測試端口81,實際端口為80
查看Pod日志
[root@k8s-master yaml]# kubectl describe pod liveness-tcp Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 77s Successfully assigned default/liveness-tcp to k8s-node1 Normal Pulled 72s kubelet, k8s-node1 Successfully pulled image "nginx" in 4.873943634s Normal Created 72s kubelet, k8s-node1 Created container liveness Normal Started 72s kubelet, k8s-node1 Started container liveness Normal Pulling 4s (x2 over 77s) kubelet, k8s-node1 Pulling image "nginx" Warning Unhealthy 4s (x3 over 44s) kubelet, k8s-node1 Liveness probe failed: dial tcp 10.244.36.79:81: connect: connection refused Normal Killing 4s kubelet, k8s-node1 Container liveness failed liveness probe, will be restarted #探針檢測失敗嘗試重啟容器 [root@k8s-master yaml]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liveness-tcp 1/1 Running 0 83s 10.244.36.79 k8s-node1 <none> <none>
TCP 檢查方式和 HTTP 檢查方式非常相似,在容器啟動 initialDelaySeconds
參數設定的時間后,kubelet
將發送第一個 livenessProbe
探針,嘗試連接容器的 80 端口,如果連接失敗則將殺死 Pod 重啟容器。
2、ReadinessProbe 探針使用示例
Pod 的 ReadinessProbe 探針使用方式和 LivenessProbe 探針探測方法一樣,也是支持三種,只是一個是用於探測應用的存活,一個是判斷是否對外提供流量的條件。這里用一個 Springboot 項目,設置 ReadinessProbe 探測 SpringBoot 項目的 8081 端口下的 /actuator/health 接口,如果探測成功則代表內部程序以及啟動,就開放對外提供接口訪問,否則內部應用沒有成功啟動,暫不對外提供訪問,直到就緒探針探測成功。
示例文件 readiness-exec.yaml
apiVersion: v1 kind: Service metadata: name: springboot labels: app: springboot spec: type: NodePort ports: - name: server port: 8080 targetPort: 8080 nodePort: 31180 - name: management port: 8081 targetPort: 8081 nodePort: 31181 selector: app: springboot --- apiVersion: v1 kind: Pod metadata: name: springboot labels: app: springboot spec: containers: - name: springboot image: wuxinchun/springboot-helloworld:v1 ports: - name: server containerPort: 8080 - name: management containerPort: 8081 readinessProbe: initialDelaySeconds: 20 periodSeconds: 5 timeoutSeconds: 10 httpGet: scheme: HTTP port: 8081 path: /actuator/healthtest #測試地址,實際path為:/actuator/health
查看日志
[root@k8s-master yaml]# kubectl describe pod springboot Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 20m Successfully assigned default/springboot to k8s-node1 Normal Pulled 20m kubelet, k8s-node1 Container image "mydlqclub/springboot-helloworld:0.0.1" already present on machine Normal Created 20m kubelet, k8s-node1 Created container springboot Normal Started 20m kubelet, k8s-node1 Started container springboot Warning Unhealthy 53s (x237 over 20m) kubelet, k8s-node1 Readiness probe failed: HTTP probe failed with statuscode: 404 [root@k8s-master yaml]# kubectl get ep NAME ENDPOINTS AGE springboot 21m
readinessProbe探測失敗,會將 Pod 的 IP:Port 從對應的 EndPoint 列表中刪除
3、ReadinessProbe + LivenessProbe 配合使用示例
一般程序中需要設置兩種探針結合使用,並且也要結合實際情況,來配置初始化檢查時間和檢測間隔,下面列一個簡單的 SpringBoot 項目的 Deployment 例子。
apiVersion: v1 kind: Service metadata: name: springboot labels: app: springboot spec: type: NodePort ports: - name: server port: 8080 targetPort: 8080 nodePort: 31180 - name: management port: 8081 targetPort: 8081 nodePort: 31181 selector: app: springboot --- apiVersion: apps/v1 kind: Deployment metadata: name: springboot labels: app: springboot spec: replicas: 1 selector: matchLabels: app: springboot template: metadata: name: springboot labels: app: springboot spec: containers: - name: readiness image: wuxinchun/springboot-helloworld:v1 ports: - name: server containerPort: 8080 - name: management containerPort: 8081 readinessProbe: initialDelaySeconds: 20 periodSeconds: 5 timeoutSeconds: 10 httpGet: scheme: HTTP port: 8081 path: /actuator/health livenessProbe: initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 httpGet: scheme: HTTP port: 8081 path: /actuator/health