您好,登錄后才能下訂單哦!
強大的自愈能力是 Kubernetes 這類容器編排引擎的一個重要特性。自愈的默認實現方式是自動重啟發生故障的容器。除此之外,用戶還可以利用 Liveness
和 Readiness
探測機制設置更精細的健康檢查,進而實現如下需求:
Liveness 探測讓用戶可以自定義判斷容器是否健康的條件。如果探測失敗,Kubernetes 就會重啟容器。
我們創建一個 Pod 的配置文件liveness.yaml
,可以使用命令kubectl explain pod.spec.containers.livenessProbe
查看其使用方法。
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 -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
啟動進程首先創建文件 /tmp/healthy,30 秒后刪除,在我們的設定中,如果 /tmp/healthy 文件存在,則認為容器處于正常狀態,反正則發生故障。
livenessProbe
部分定義如何執行 Liveness 探測:
cat
命令檢查 /tmp/healthy 文件是否存在。如果命令執行成功,返回值為零,Kubernetes 則認為本次 Liveness 探測成功;如果命令返回值非零,本次 Liveness 探測失敗。initialDelaySeconds: 10
指定容器啟動 10 之后開始執行 Liveness 探測,我們一般會根據應用啟動的準備時間來設置。比如某個應用正常啟動要花 30 秒,那么initialDelaySeconds
的值就應該大于 30。periodSeconds: 5
指定每 5 秒執行一次 Liveness 探測。Kubernetes 如果連續執行 3 次 Liveness 探測均失敗,則會殺掉并重啟容器。下面創建 Pod liveness:
[root@master ~]# kubectl apply -f liveness.yaml
pod/liveness created
從配置文件可知,最開始的 30 秒,/tmp/healthy
存在,cat 命令返回 0,Liveness 探測成功,這段時間 kubectl describe pod liveness
的 Events部分會顯示正常的日志。
[root@master ~]# kubectl describe pod liveness
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulling 25s kubelet, node02 pulling image "busybox"
Normal Pulled 24s kubelet, node02 Successfully pulled image "busybox"
Normal Created 24s kubelet, node02 Created container
Normal Started 23s kubelet, node02 Started container
Normal Scheduled 23s default-scheduler Successfully assigned default/liveness to node02
35 秒之后,日志會顯示 /tmp/healthy
已經不存在,Liveness 探測失敗。再過幾十秒,幾次探測都失敗后,容器會被重啟。
[root@master ~]# kubectl describe pod liveness
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m9s default-scheduler Successfully assigned default/liveness to node02
Normal Pulled 3m41s (x3 over 6m10s) kubelet, node02 Successfully pulled image "busybox"
Normal Created 3m41s (x3 over 6m10s) kubelet, node02 Created container
Normal Started 3m40s (x3 over 6m9s) kubelet, node02 Started container
Warning Unhealthy 2m57s (x9 over 5m37s) kubelet, node02 Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Pulling 2m27s (x4 over 6m11s) kubelet, node02 pulling image "busybox"
Normal Killing 60s (x4 over 4m57s) kubelet, node02 Killing container with id docker://liveness:Container failed liveness probe.. Container will be killed and recreated.
然后我們查看容器,已經重啟了一次。
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
liveness 1/1 Running 3 5m13s
用戶通過 Liveness 探測可以告訴 Kubernetes 什么時候通過重啟容器實現自愈;Readiness 探測則是告訴 Kubernetes 什么時候可以將容器加入到 Service 負載均衡池中,對外提供服務。
Readiness 探測的配置語法與 Liveness 探測完全一樣,我們創建配置文件readiness.yaml
。
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 -rf /tmp/healthy; sleep 600
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
創建 Pod,然后查看其狀態。
[root@master ~]# kubectl apply -f readiness.yaml
pod/readiness created
剛剛創建時,READY
狀態為不可用。
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness 0/1 Running 0 21s
15 秒后(initialDelaySeconds + periodSeconds),第一次進行 Readiness 探測并成功返回,設置 READY
為可用。
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness 1/1 Running 0 38s
30 秒后,/tmp/healthy 被刪除,連續 3 次 Readiness 探測均失敗后,READY
被設置為不可用。
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness 0/1 Running 0 63s
通過 kubectl describe pod readiness
也可以看到 Readiness 探測失敗的日志。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulling 5m29s kubelet, node01 pulling image "busybox"
Normal Scheduled 5m25s default-scheduler Successfully assigned default/readiness to node01
Normal Pulled 5m13s kubelet, node01 Successfully pulled image "busybox"
Normal Created 5m12s kubelet, node01 Created container
Normal Started 5m12s kubelet, node01 Started container
Warning Unhealthy 28s (x51 over 4m38s) kubelet, node01 Readiness probe failed: cat: can't open '/tmp/healthy': No such file or directory
下面對 Liveness 探測和 Readiness 探測做個比較:
對于多副本應用,當執行 Scale Up 操作時,新副本會作為 backend 被添加到 Service 的負責均衡中,與已有副本一起處理客戶的請求。考慮到應用啟動通常都需要一個準備階段,比如加載緩存數據,連接數據庫等,從容器啟動到正真能夠提供服務是需要一段時間的。我們可以通過 Readiness 探測判斷容器是否就緒,避免將請求發送到還沒有 ready 的 backend。
下面我們創建一個配置文件來說明這種情況。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
template:
metadata:
labels:
run: web
spec:
containers:
- name: web
images: myhttpd
ports:
- containerPort: 8080
readinessProbe:
httpGet:
scheme: HTTP
path: /health
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
重點關注 readinessProbe
部分。這里我們使用了不同于 exec
的另一種探測方法 -- httpGet
。Kubernetes 對于該方法探測成功的判斷條件是 http 請求的返回代碼在 200-400 之間。
schema
指定協議,支持 HTTP(默認值)和 HTTPS。path
指定訪問路徑。port
指定端口。上面配置的作用是:
對于生產環境中重要的應用都建議配置 Health Check,保證處理客戶請求的容器都是準備就緒的 Service backend。
Health Check 另一個重要的應用場景是 Rolling Update。試想一下下面的情況,現有一個正常運行的多副本應用,接下來對應用進行更新(比如使用更高版本的 image),Kubernetes 會啟動新副本,然后發生了如下事件:
因為新副本本身沒有異常退出,默認的 Health Check 機制會認為容器已經就緒,進而會逐步用新副本替換現有副本,其結果就是:當所有舊副本都被替換后,整個應用將無法處理請求,無法對外提供服務。如果這是發生在重要的生產系統上,后果會非常嚴重。
如果正確配置了 Health Check,新副本只有通過了 Readiness 探測,才會被添加到 Service;如果沒有通過探測,現有副本不會被全部替換,業務仍然正常進行。
下面通過例子來實踐 Health Check 在 Rolling Update 中的應用。
用如下配置文件 app.v1.yml 模擬一個 10 副本的應用:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: app
spec:
replicas: 10
template:
metadata:
labels:
run: app
spec:
containers:
- name: app
images: busybox
args:
- /bin/sh
- -c
- sleep 10; touch /tmp/healthy; sleep 30000
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
10 秒后副本能夠通過 Readiness 探測。
[root@master ~]# kubectl apply -f app.v1.yaml
deployment.extensions/app created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
app-56878b4676-4rftg 1/1 Running 0 34s
app-56878b4676-6jtn4 1/1 Running 0 34s
app-56878b4676-6smfj 1/1 Running 0 34s
app-56878b4676-8pnc2 1/1 Running 0 34s
app-56878b4676-hxzjk 1/1 Running 0 34s
app-56878b4676-mglht 1/1 Running 0 34s
app-56878b4676-t2qs6 1/1 Running 0 34s
app-56878b4676-vgw44 1/1 Running 0 34s
app-56878b4676-vnxfx 1/1 Running 0 34s
app-56878b4676-wb9rh 1/1 Running 0 34s
接下來滾動更新應用,配置文件 app.v2.yml
如下:
apiVersion: extensions/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 30000
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
很顯然,由于新副本中不存在 /tmp/healthy,是無法通過 Readiness 探測的。驗證如下:
[root@master ~]# kubectl apply -f app.v2.yaml
deployment.extensions/app configured
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
app-56878b4676-4rftg 1/1 Running 0 4m42s
app-56878b4676-6jtn4 1/1 Running 0 4m42s
app-56878b4676-6smfj 1/1 Running 0 4m42s
app-56878b4676-hxzjk 1/1 Running 0 4m42s
app-56878b4676-mglht 1/1 Running 0 4m42s
app-56878b4676-t2qs6 1/1 Running 0 4m42s
app-56878b4676-vgw44 1/1 Running 0 4m42s
app-56878b4676-vnxfx 1/1 Running 0 4m42s
app-56878b4676-wb9rh 1/1 Running 0 4m42s
app-84fc656775-hf954 0/1 Running 0 66s
app-84fc656775-p287w 0/1 Running 0 66s
[root@master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
app 9/10 2 9 7m1s
先關注 kubectl get pod
輸出:
再來看 kubectl get deployment app
的輸出:
在我們的設定中,新副本始終都無法通過 Readiness 探測,所以這個狀態會一直保持下去。
上面我們模擬了一個滾動更新失敗的場景。不過幸運的是:Health Check 幫我們屏蔽了有缺陷的副本,同時保留了大部分舊副本,業務沒有因更新失敗受到影響。
滾動更新可以通過參數 maxSurge
和 maxUnavailable
來控制副本替換的數量。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。