一、Health Check介紹
強大的自愈能力是k8s容器編排引擎一個重要特性,自愈能力的默認實現方式為自動重啟發生故障的容器,另外還可以利用Liveness和Readiness探測機制設置更精細的健康檢查。
- 零停機部署
- 避免部署無效的鏡像
- 更加安全的滾動升級
二、K8S健康檢查方式
1、k8s默認的健康檢查
每個容器啟動時都會執行一個進程,此進程由Dockerfile的CMD或ENTRYPOINT指定。如果進程退出返回碼為非0,則認為容器發生故障,k8s會根據restartPolicy重啟容器。
①創建應用測試
apiVersion: v1 kind: Pod metadata: name: healthcheck labels: test: healthcheck spec: restartPolicy: OnFailure containers: - name: healthcheck image: busybox args: - /bin/sh - -c - sleep 10;exit 1
②Pod的restartPolicy設置為OnFailure,默認策略為Always,執行創建Pod
kubectl apply -f healthcheck.yaml
③過幾分鍾查看Pod狀態,發現容器已經重啟了3次
[root@k8s-node1 health_check]# kubectl get pods healthcheck NAME READY STATUS RESTARTS AGE healthcheck 0/1 Error 3 2m
容器進程返回值非0,k8s則認為容器發生故障,需要重啟,有不少場景下發生故障,但進程不會退出,比如訪問web服務時發生500內部錯誤,可能是負載過高,也可能是資源死鎖,此時httpd進程並沒有異常退出,在這種情況下重啟容器可能是最直接、最有效的解決方案,處理此類場景那就用到了k8s的Liveness探測。
2、Liveness探測
Liveness探測讓用戶可以自定義判斷容器是否健康的條件,如果探測失敗,k8s就會重啟容器。
①創建應用演示
apiVersion: v1 kind: Pod metadata: name: liveness labels: test: liveness spec: restartPolicy: OnFailure containers: - name: liveness image: busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600 livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 10 periodSeconds: 5
以上yaml文件說明:啟動Pod后首先創建文件/tmp/healthy,30秒后刪除,如果文件/tmp/healthy存在,則認為容器處於正常狀態,反之發生故障。
探測方法:
- 通過cat命令檢查/tmp/healthy文件是否存在,如果命令執行成功,返回值為0,k8s會認為本次Liveness探測成功;如果命令返回值非0,本次Liveness探測失敗
- initialDelaySeconds: 10 指容器啟動10秒后開始執行Liveness探測,如果你的應用啟動要花30秒,那么initialDelaySeconds的值就應該大於30。
- periodSeconds: 5 指每5秒執行一次Liveness探測,k8s如果連續執行3次Liveness探測均失敗,則會殺掉重啟容器
②創建Pod並查看
kubectl apply -f liveness.yaml
kubectl describe pod liveness
③35秒之后,日志顯示/tmp/healthy已經不存在了,Liveness連續幾次探測失敗,容器會被重啟
④再次查看pod,發現已經重啟1次
[root@k8s-node1 health_check]# kubectl get pods liveness NAME READY STATUS RESTARTS AGE liveness 1/1 Running 1 1m
3、Readiness探測
Liveness探測可以告訴k8s什么時候通過重啟容器實現自愈;Readiness探測告訴k8s什么時候可以將容器加入到service負載均衡池中,對外提供服務。
①Readiness探測配置與Liveness探測完全一樣
apiVersion: v1 kind: Pod metadata: name: readiness labels: test: readiness spec: restartPolicy: OnFailure containers: - name: readiness image: busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600 readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 10 periodSeconds: 5
②創建並查看
kubectl apply -f readiness.yaml
[root@k8s-node1 health_check]# kubectl get pod readiness NAME READY STATUS RESTARTS AGE readiness 0/1 Running 0 8s [root@k8s-node1 health_check]# kubectl get pod readiness NAME READY STATUS RESTARTS AGE readiness 1/1 Running 0 18s [root@k8s-node1 health_check]# kubectl get pod readiness NAME READY STATUS RESTARTS AGE readiness 0/1 Running 0 49s
探測方法:
- 剛創建時,READY狀態不可用
- 15秒后,第一次進行Readiness探測並成功返回,設置READY為可用
- 30秒后,/tmp/healthy被刪除,連續3次Readiness探測失敗后,READY被設置為不可用
③查看日志詳情
kubectl describe pod readiness
4、Readiness探測與Liveness探測區別
- Readiness探測與Liveness探測是兩種Health Check機制,如果不特意配置,k8s對兩種探測采取相同的默認行為,均通過判斷容器啟動進程的返回值是否為0判斷探測是否成功。
- 兩種探測配置方法完全一樣,支持的配置參數也一樣,不同在於探測失敗后,Liveness探測是重啟容器,Readiness探測則將容器設置為不可用,不接收service轉發的請求
- Readiness探測與Liveness探測是獨立執行的,二者之間沒有依賴,可以單獨使用,也可以同時使用,用Liveness探測判斷容器是否需要重啟以實現自愈,用Readiness探測判斷容器是否已經准備好對外提供服務
三、Health Check在Scale UP中的應用
在多副本應用中,當執行Scale Up新增一個副本的場景中,考慮到應用啟動需要一些時間,比如加載緩存數據、連接數據庫等,這里就可以通過Readiness探測判斷容器是否就緒,避免將請求發送到還沒准備好的
后端。
1、創建應用測試
apiVersion: apps/v1beta2 kind: Deployment metadata: name: web spec: replicas: 3 template: metadata: labels: app: web spec: containers: - name: web image: httpd ports: - containerPort: 8080 readinessProbe: httpGet: scheme: HTTP #指定協議,默認為HTTP path: /healthy #訪問路徑 port: 8080 initialDelaySeconfs: 10 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: name: web-svc spec: selector: app: web ports: - protocol: TCP port: 8080 targetPort: 80
注:這里使用了不同與exec的另一種探測方法httpGet,k8s對該方法探測成功的判斷是http請求返回碼在200~400之間
2、上面配置作用
- 容器啟動10秒后開始探測
- 如果http://[container_ip]:8080/healthy返回碼不是200~400,表示容器沒有就緒,不接收Service web-svc的請求。
- 每隔5秒探測一次
- 直到返回碼為200~400,表明容器已經就緒,然后將其加入到web-svc的負載中,開始處理請求。
- 探測繼續以5秒的間隔執行,如果連續3次失敗,容器會從負載中移除,直到再次探測成功后重新加入負載
四、Health Check在滾動更新中的應用
Health Check另一個重要場景就是滾動更新,現有一個正常運行的多副本應用,接下來要對應用進行更新,比如升級成高版本的image,k8s會啟動新副本的過程如下:
- 正常情況一下啟動的新副本需要10秒左右完成准備工作,在此之前無法響應業務請求
- 由於人為配置錯誤,副本始終無法完成准備工作,比如無法連接后端的數據庫
生產環境中,如果沒有配置Health Check,默認Health Check機制會認為容器已經就緒,進行會逐步用新副本替換現有副本,當所有舊副本都被替換后,整個應用將無法處理請求,無法提供服務,
如果正確配置了Health Check,新副本只有通過了Readiness探測才會被添加到Service,如果探測不成功,現有副本不會被會部替換,業務仍然正常進行。
1、創建應用測試
kubectl apply -f app-v1.yaml --record
apiVersion: apps/v1beta1 kind: Deployment metadata: name: app spec: replicas: 10 template: metadata: labels: run: app spec: containers: - name: app image: busybox args: - /bin/sh - -c - sleep 10; touch /tmp/healthy; sleep 30000 readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 10 periodSeconds: 5
2、10秒后查看所有副本通過了Readiness探測
[root@k8s-node1 health_check]# kubectl get deployment app NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE app 10 10 10 10 7m [root@k8s-node1 health_check]# kubectl get pods NAME READY STATUS RESTARTS AGE app-58594c894-4bfzn 1/1 Running 0 6m app-58594c894-5wnxv 1/1 Running 0 6m app-58594c894-9jspd 1/1 Running 0 6m app-58594c894-bmgp9 1/1 Running 0 6m app-58594c894-d8r72 1/1 Running 0 6m app-58594c894-k42zf 1/1 Running 0 6m app-58594c894-rvnpl 1/1 Running 0 6m app-58594c894-ssg9w 1/1 Running 0 6m app-58594c894-z2qd6 1/1 Running 0 6m app-58594c894-zb6d8 1/1 Running 0 6m
3、進行滾動更新,創建app-v2.yaml
apiVersion: apps/v1beta1 kind: Deployment metadata: name: app spec: replicas: 10 template: metadata: labels: run: app spec: containers: - name: app image: busybox args: - /bin/sh - -c - sleep 3000 readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 10 periodSeconds: 5
4、驗證新副本中不存在/tmp/healthy,能否通過Readiness探測
[root@k8s-node1 health_check]# kubectl get deployment app NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE app 10 13 5 8 1h
#DESIRED 10:表示期望狀態是10個副本
#CURRENT 13: 表示當前副本總數,8個舊副本+5個新副本
#UP-TO-DATE 5:表示當前已完成更新的副本數
#AVAILABLE 8:表示當前處於可用的副本數 [root@k8s-node1 health_check]# kubectl get pods NAME READY STATUS RESTARTS AGE app-58594c894-4bfzn 1/1 Running 0 1h app-58594c894-5wnxv 1/1 Running 0 1h app-58594c894-9jspd 1/1 Running 0 1h app-58594c894-bmgp9 1/1 Running 0 1h app-58594c894-d8r72 1/1 Running 0 1h app-58594c894-k42zf 1/1 Running 0 1h app-58594c894-ssg9w 1/1 Running 0 1h app-58594c894-z2qd6 1/1 Running 0 1h app-67f89fbd77-4fkq5 0/1 Running 0 1m app-67f89fbd77-7fgjg 0/1 Running 0 1m app-67f89fbd77-krf8w 0/1 Running 0 1m app-67f89fbd77-r25rx 0/1 Running 0 1m app-67f89fbd77-wdrsr 0/1 Running 0 1m
5、為什么新創建副本數是5個,同時只銷毀2個舊副本
- 1、maxSurge
- 此參數控制滾動更新過程中副本總數超過DESIRED的上限,默認值為25%,也可以是具體的整數,上面例子中,DESIRED為10,副本總數CURRENT最大值即為:10+10*25%=13,maxSurge值越大,初始創建的新副本就越多。
- 2、maxUnavailable
- 此參數控制滾動更新過程中,不可用的副本占DESIRED的最大比例。同樣maxUnavailable默認值也為25%,那么可用的副本至少為10-10*25%=8,maxUnavailable值越大,初始銷毀的副本數量就越多
6、正常滾動更新過程
- 創建3個新副本使副本總數達到13個
- 銷毀2個舊副本使可用的副本數降到8個
- 當2個舊副本成功銷毀后,再創建2個新副本,保持副本總數為13個
- 當新副本通過Readiness探測后,會使可用副本數增加,超過8個
- 進而可以繼續銷毀更多的副本,使可用副本數回到8
- 舊副本的銷毀使副本總數低於13,這樣可以繼續創建新的副本
- 這個過程一直持續進行,最終所有的舊副本被新副本替換,滾動更新完成
- 如果滾動更新失敗,使用命令kubectl rollout undo deployment app快速回滾到上一版本
7、自定義maxSurge和maxUnavailable
apiVersion: apps/v1beta1 kind: Deployment metadata: name: app spec: strategy: rollingUpdate: maxSurge: 35% maxUnavailable: 35% replicas: 10 template: metadata: labels: run: app spec: containers: - name: app image: busybox args: - /bin/sh - -c - sleep 10; touch /tmp/healthy; sleep 30000 readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 10 periodSeconds: 5