強大的自愈能力是Kubernetes這一類容器編排管理引擎的一個重要特性。通常情況下,Kubernetes通過重啟發(fā)生故障的容器來實現(xiàn)自愈。除此之外,我們還有其他方式來實現(xiàn)基于Kubernetes編排的容器的健康檢查嗎?Liveness和Readiness就是不錯的選擇。
創(chuàng)新互聯(lián)專注于調(diào)兵山網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供調(diào)兵山營銷型網(wǎng)站建設(shè),調(diào)兵山網(wǎng)站制作、調(diào)兵山網(wǎng)頁設(shè)計、調(diào)兵山網(wǎng)站官網(wǎng)定制、成都小程序開發(fā)服務(wù),打造調(diào)兵山網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供調(diào)兵山網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
2.1 系統(tǒng)默認的健康檢查。
apiVersion: v1
kind: Pod
metadata:
labels:
test: healthcheck
name: healthcheck
spec:
restartPolicy: OnFailure
containers:
- name: healthcheck
image: busybox
args:
- /bin/sh
- -c
- sleep 10;exit 1
創(chuàng)建一個內(nèi)容如上所述的yaml文件,命名為HealthCheck.yaml,apply:
[root@k8s-m health-check]# kubectl apply -f HealthCheck.yaml
pod/healthcheck created
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
healthcheck 0/1 CrashLoopBackOff 3 4m52s
我們可以看到,這個pod并未正常運行,重啟了3次。具體的重啟日志我們可以通過describe命令來查看,此處不再贅述。我們來執(zhí)行一下以下命令:
[root@k8s-m health-check]# sh -c "sleep 2;exit 1"
[root@k8s-m health-check]# echo $?
1
我們可以看到,命令正常執(zhí)行,返回值為1。默認情況下,Linux命令執(zhí)行之后返回值為0說明命令執(zhí)行成功。因為執(zhí)行成功后的返回值不為0,Kubernetes默認為容器發(fā)生故障,不斷重啟。然而,也有不少情況是服務(wù)實際發(fā)生了故障,但是進程未退出。這種情況下,重啟往往是簡單而有效的手段。例如:訪問web服務(wù)時顯示500服務(wù)器內(nèi)部錯誤,很多原因會造成這樣的故障,重啟可能就能迅速修復故障。
2.2 在Kubernetes中,可以通過Liveness探測告訴kebernetes什么時候?qū)崿F(xiàn)重啟自愈。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness
spec:
restartPolicy: OnFailure
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthcheck;sleep 30; rm -rf /tmp/healthcheck;sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthcheck
initialDelaySeconds: 10
periodSeconds: 5
創(chuàng)建名為Liveness.yaml的文件,創(chuàng)建Pod:
[root@k8s-m health-check]# kubectl apply -f Liveness.yaml
pod/liveness created
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
liveness 1/1 Running 1 5m50s
從yaml文件中,我們可以看出,容器啟動后創(chuàng)建/tmp/healthcheck文件,30s后刪除,刪除后sleep該進程600s。通過cat /tmp/healthcheck來探測容器是否發(fā)生故障。如果該文件存在,則說明容器正常,該文件不存在,則殺該容器并重啟。
initialDelaySeconds:10指定容器啟動10s之后執(zhí)行探測。一般該值要大于容器的啟動時間。periodSeconds:5表示每5s執(zhí)行一次探測,如果連續(xù)三次執(zhí)行Liveness探測均失敗,那么會殺死該容器并重啟。
2.3 Readiness則可以告訴Kubenentes什么時候可以將容器加入到Service的負載均衡池中,對外提供服務(wù)。
apiVersion: v1
kind: Pod
metadata:
labels:
test: readiness
name: readiness
spec:
restartPolicy: OnFailure
containers:
- name: readiness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthcheck;sleep 30; rm -rf /tmp/healthcheck;sleep 600
readinessProbe:
exec:
command:
- cat
- /tmp/healthcheck
initialDelaySeconds: 10
periodSeconds: 5
apply該文件:
[root@k8s-m health-check]# kubectl apply -f Readiness.yaml
pod/readiness created
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness 0/1 Running 0 84s
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness 0/1 Completed 0 23m
從yaml文件中我們可以看出,Readiness和Liveness兩種探測的配置基本是一樣的,只需稍加改動就可以套用。通過kubectl get pod我們發(fā)現(xiàn)這兩種Health Check主要不同在于輸出的第二列和第三列。Readiness第三列一直都是running,第二列一段時間后由1/1變?yōu)?/1。當?shù)诙袨?/1時,則說明容器不可用。具體可以通過以下命令來查看一下:
[root@k8s-m health-check]# while true;do kubectl describe pod readiness;done
Liveness和Readiness是兩種Health Check機制,不互相依賴,可以同時使用。
3.1 Health Check在Scale Up中的應(yīng)用。
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
template:
metadata:
labels:
run: web
spec:
containers:
- name: web
image: httpd
ports:
- containerPort: 8080
readinessProbe:
httpGet:
scheme: HTTP
path: /health-check
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: web-svc
spec:
selector:
run: web
ports:
- protocol: TCP
port: 8080
targetPort: 80
通過以上yaml,創(chuàng)建了一個名為web-svc的服務(wù)和名為web的Deployment。
[root@k8s-m health-check]# kubectl apply -f HealthCheck-web-deployment.yaml
deployment.apps/web unchanged
service/web-svc created
[root@k8s-m health-check]# kubectl get service web-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web-svc ClusterIP 10.101.1.6 8080/TCP 2m20s
[root@k8s-m health-check]# kubectl get deployment web
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
web 3 3 3 0 3m26s
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-7d96585f7f-q5p4d 0/1 Running 0 3m35s
web-7d96585f7f-w6tqx 0/1 Running 0 3m35s
web-7d96585f7f-xrqwm 0/1 Running 0 3m35s
重點關(guān)注一下17-23行,第17行指出本案例中使用的Health Check機制為Readiness,探測方法為httpGet。Kubernetes對于該方法探測成功的判斷條件時http請求返回值在200-400之間。schema指定了協(xié)議,可以為http(默認)和https。path指定訪問路徑,port指定端口。
容器啟動10s后開始探測,如果 http://container_ip:8080/health-check 的返回值不是200-400,表示容器沒有準備就緒,不接收Service web-svc的請求。/health-check則是我們實現(xiàn)探測的代碼。探測結(jié)果示例如下:
[root@k8s-m health-check]# kubectl describe pod web
Warning Unhealthy 57s (x219 over 19m) kubelet, k8s-n2 Readiness probe failed: Get http://10.244.2.61:8080/healthy: dial tcp 10.244.2.61:8080: connect: connection refused
3.2 Health Check在滾動更新(Rolling Update)中的應(yīng)用。
默認情況下,在Rolling Update過程中,Kubernetes會認為容器已經(jīng)準備就緒,進而會逐步替換舊副本。如果新版本的容器出現(xiàn)故障,那么在版本更新完成之后可能導致整個應(yīng)用無法處理請求,無法對外提供服務(wù)。此類事件若發(fā)生在生產(chǎn)環(huán)境中,后果會非常嚴重。正確配置了Health Check,只有通過了Readiness探測的新副本才能添加到Service,如果沒有通過探測,現(xiàn)有副本就不會唄替換,業(yè)務(wù)依然正常運行。
接下來,我們分別創(chuàng)建yaml文件app.v1.yaml和app.v2.yaml:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: app
spec:
replicas: 8
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
image: busybox
args:
- /bin/sh
- -c
- sleep 10;touch /tmp/health-check;sleep 30000
readinessProbe:
exec:
command:
- cat
- /tmp/health-check
initialDelaySeconds: 10
periodSeconds: 5
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: app
spec:
replicas: 8
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
image: busybox
args:
- /bin/sh
- -c
- sleep 3000
readinessProbe:
exec:
command:
- cat
- /tmp/health-check
initialDelaySeconds: 10
periodSeconds: 5
apply文件app.v1.yaml:
[root@k8s-m health-check]# kubectl apply -f app.v1.yaml --record
deployment.apps/app created
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
app-844b9b5bf-9nnrb 1/1 Running 0 2m52s
app-844b9b5bf-b8tw2 1/1 Running 0 2m52s
app-844b9b5bf-j2n9c 1/1 Running 0 2m52s
app-844b9b5bf-ml8c5 1/1 Running 0 2m52s
app-844b9b5bf-mtgr9 1/1 Running 0 2m52s
app-844b9b5bf-n4dn8 1/1 Running 0 2m52s
app-844b9b5bf-ppzh7 1/1 Running 0 2m52s
app-844b9b5bf-z55d4 1/1 Running 0 2m52s
更新到app.v2.yaml:
[root@k8s-m health-check]# kubectl apply -f app.v2.yaml --record
deployment.apps/app configured
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
app-844b9b5bf-9nnrb 1/1 Running 0 3m30s
app-844b9b5bf-b8tw2 1/1 Running 0 3m30s
app-844b9b5bf-j2n9c 1/1 Running 0 3m30s
app-844b9b5bf-ml8c5 1/1 Terminating 0 3m30s
app-844b9b5bf-mtgr9 1/1 Running 0 3m30s
app-844b9b5bf-n4dn8 1/1 Running 0 3m30s
app-844b9b5bf-ppzh7 1/1 Terminating 0 3m30s
app-844b9b5bf-z55d4 1/1 Running 0 3m30s
app-cd49b84-bxvtc 0/1 ContainerCreating 0 6s
app-cd49b84-gkkj8 0/1 ContainerCreating 0 6s
app-cd49b84-jfzcm 0/1 ContainerCreating 0 6s
app-cd49b84-xl8ws 0/1 ContainerCreating 0 6s
稍后再觀察:
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
app-844b9b5bf-9nnrb 1/1 Running 0 4m59s
app-844b9b5bf-b8tw2 1/1 Running 0 4m59s
app-844b9b5bf-j2n9c 1/1 Running 0 4m59s
app-844b9b5bf-mtgr9 1/1 Running 0 4m59s
app-844b9b5bf-n4dn8 1/1 Running 0 4m59s
app-844b9b5bf-z55d4 1/1 Running 0 4m59s
app-cd49b84-bxvtc 0/1 Running 0 95s
app-cd49b84-gkkj8 0/1 Running 0 95s
app-cd49b84-jfzcm 0/1 Running 0 95s
app-cd49b84-xl8ws 0/1 Running 0 95s
此刻狀態(tài)全部為running,但是依然有4個Pod的READY為0/1,再看一下:
[root@k8s-m health-check]# kubectl get deployment app
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
app 8 10 4 6 7m20s
DESIRED表示期待的副本數(shù)為8,CURRENT表示當前副本數(shù)為10,UP-TO-DATE表示升級了的副本數(shù)為4,AVAILABLE表示可用的副本數(shù)為6。如果不進行更改,該狀態(tài)將一直保持下去。在此,需要注意的是,Rolling Update中刪除了2個舊副本,創(chuàng)建建了4個新副本。這里留到最后再討論。
版本回滾到v1:
[root@k8s-m health-check]# kubectl rollout history deployment app
deployment.extensions/app
REVISION CHANGE-CAUSE
1 kubectl apply --filename=app.v1.yaml --record=true
2 kubectl apply --filename=app.v2.yaml --record=true
[root@k8s-m health-check]# kubectl rollout undo deployment app --to-revision=1
deployment.extensions/app
[root@k8s-m health-check]# kubectl get pod
NAME READY STATUS RESTARTS AGE
app-844b9b5bf-8qqhk 1/1 Running 0 2m37s
app-844b9b5bf-9nnrb 1/1 Running 0 18m
app-844b9b5bf-b8tw2 1/1 Running 0 18m
app-844b9b5bf-j2n9c 1/1 Running 0 18m
app-844b9b5bf-mtgr9 1/1 Running 0 18m
app-844b9b5bf-n4dn8 1/1 Running 0 18m
app-844b9b5bf-pqpm5 1/1 Running 0 2m37s
app-844b9b5bf-z55d4 1/1 Running 0 18m
4.1 Liveness和Readiness是Kubernetes中兩種不同的Health Check方式,他們非常類似,但又有區(qū)別??梢詢烧咄瑫r使用,也可以單獨使用。具體差異在上文已經(jīng)提及。
4.2 在上一篇關(guān)于Rolling Update的文章中,我曾經(jīng)提到滾動更新過程中的替換規(guī)則。在本文中我們依然使用了默認方式進行更新。maxSurge和maxUnavailable兩個參數(shù)決定了更新過程中各個狀態(tài)下的副本個數(shù),這兩個參數(shù)的默認值都是25%。更新后,總副本數(shù)=8+8*0.25=10;可用副本數(shù):8-8*0.25=6。此過程中,銷毀了2個副本,創(chuàng)建了4個新副本。
4.3 在一般生產(chǎn)環(huán)境上線時,盡量使用Health Check來確保業(yè)務(wù)不受影響。這個過程的實現(xiàn)手段多樣化,需要根據(jù)實際情況進行總結(jié)和選用。
5.1 官方文檔:關(guān)于Liveness和Readiness
5.2 官方文檔:關(guān)于maxSurge和maxUnavailable
5.3 文中涉及到的代碼