理解 Pod 的狀態(tài)
Pod phase
在 Pod 完整的生命周期中卢厂,存在著 5 種不同的階段:
-
Pending
:創(chuàng)建 Pod 對象后的初始化階段。會一直持續(xù)到 Pod 被分配給某個工作節(jié)點惠啄,鏡像被拉取到本地并啟動 -
Running
:Pod 中至少一個容器處于運行狀態(tài) -
Succeeded
:對于不打算無限期運行的 Pod慎恒,其容器部署完成后的狀態(tài) -
Failed
:對于不打算無限期運行的 Pod,其容器中至少有一個由于錯誤終止 -
Unknown
:由于 Kubelet 與 API Server 的通信中斷礁阁,Pod 的狀態(tài)未知巧号。可能是工作節(jié)點掛掉或斷網(wǎng)
從 kubia.yml
清單文件創(chuàng)建一個 Pod姥闭。
apiVersion: v1
kind: Pod
metadata:
name: kubia
spec:
containers:
- name: kubia
image: luksa/kubia:1.0
ports:
- containerPort: 8080
$ kubectl apply -f kubia.yml
查看 Pod 的 Phase
$ kubectl get po kubia -o yaml | grep phase
phase: Running
或者借助 jq
工具從 JSON 格式的輸出中檢索 phase 字段:
$ kubectl get po kubia -o json | jq .status.phase
"Running"
也可以使用 kubectl describe
命令:
$ kubectl describe po kubia | grep Status:
Status: Running
Pod conditions
Pod 的 conditions 用來表示某個 Pod 是否達到了特定的狀態(tài)以及達到或未達到的原因丹鸿。
與 phase 相反,一個 Pod 可以同時有幾個 conditions棚品。
-
PodScheduled
:表明 Pod 是否已經(jīng)被安排給了某個工作節(jié)點 -
Initialized
:Pod 的初始化容器已經(jīng)部署完成 -
ContainersReady
:Pod 中的所有容器都已經(jīng)準備完畢 -
Ready
:Pod 自身已經(jīng)準備好對其客戶端提供服務(wù)
查看 Pod 的 conditions
$ kubectl describe po kubia | grep Conditions: -A5
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
kubectl describe
命令只會顯示每個 condition 是 true
還是 false
靠欢,不會顯示更詳細的信息廊敌。
為了顯示某個 condition 為 false 的具體原因,需要檢索 Pod 的清單文件:
$ kubectl get po kubia -o json | jq .status.conditions
[
{
"lastProbeTime": null,
"lastTransitionTime": "2021-12-30T03:02:45Z",
"status": "True",
"type": "Initialized"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-12-30T03:02:46Z",
"status": "True",
"type": "Ready"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-12-30T03:02:46Z",
"status": "True",
"type": "ContainersReady"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-12-30T03:02:45Z",
"status": "True",
"type": "PodScheduled"
}
]
當 condition 為 false
時门怪,上述輸出中會包含 reason
和 message
字段來顯示失敗的具體原因和詳細信息骡澈。
容器的 status
容器的 status 包含多個字段。其中 state
字段表示該容器當前的狀態(tài)掷空,restartCount
表示容器重啟的頻率肋殴,此外還有 containerID
、image
坦弟、imageID
等护锤。
容器的 status 包含以下幾種:
-
Waiting
:容器等待啟動。reason
和message
字段會記錄容器處于此狀態(tài)的原因 -
Running
:容器已經(jīng)創(chuàng)建酿傍,進程正在運行 -
Terminated
:容器中運行的進程已經(jīng)終止烙懦。exitCode
字段會記錄進程的退出碼 -
Unknown
:容器的狀態(tài)無法確定
比如修改 kubia.yml
清單文件中的 image
字段,故意改成 uksa/kubia:1.0
這樣無效的地址赤炒,運行 kubectl apply -f kubia.yml
命令重新應(yīng)用清單文件氯析。
等待幾分鐘直到新的配置生效,查看容器的狀態(tài)莺褒。
可以使用 kubectl describe
命令查看容器的狀態(tài):
$ kubectl describe po kubia | grep Containers: -A15
Containers:
kubia:
Container ID: docker://62fa208957d396c38f65305fd073d6b334dd8da22ab5beab196ca9bcf2f9ff91
Image: uksa/kubia:1.0
Image ID: docker-pullable://luksa/kubia@sha256:a961dc8f377916936fa963508726d77cf77dcead5c97de7e5361f0875ba3bef7
Port: 8080/TCP
Host Port: 0/TCP
State: Waiting
Reason: ImagePullBackOff
Last State: Terminated
Reason: Error
Exit Code: 137
Started: Fri, 31 Dec 2021 14:50:39 +0800
Finished: Fri, 31 Dec 2021 14:51:36 +0800
Ready: False
Restart Count: 0
或者使用 kubectl get po kubia -o json
命令:
$ kubectl get po kubia -o json | jq .status.containerStatuses
[
{
"containerID": "docker://62fa208957d396c38f65305fd073d6b334dd8da22ab5beab196ca9bcf2f9ff91",
"image": "luksa/kubia:1.0",
"imageID": "docker-pullable://luksa/kubia@sha256:a961dc8f377916936fa963508726d77cf77dcead5c97de7e5361f0875ba3bef7",
"lastState": {
"terminated": {
"containerID": "docker://62fa208957d396c38f65305fd073d6b334dd8da22ab5beab196ca9bcf2f9ff91",
"exitCode": 137,
"finishedAt": "2021-12-31T06:51:36Z",
"reason": "Error",
"startedAt": "2021-12-31T06:50:39Z"
}
},
"name": "kubia",
"ready": false,
"restartCount": 0,
"started": false,
"state": {
"waiting": {
"message": "Back-off pulling image \"uksa/kubia:1.0\"",
"reason": "ImagePullBackOff"
}
}
}
]
上面輸出中的 state
字段都表明了容器當前的狀態(tài)是 waiting
掩缓,還有 reason
和 message
字段表明處于此狀態(tài)的原因:鏡像拉取失敗。
確保容器的健康狀態(tài)
理解容器的自動重啟機制
當一個 Pod 被分配給了某個工作節(jié)點癣朗,該工作節(jié)點上的 Kubelet 就會負責啟動容器并保證該容器一直處于運行狀態(tài)拾因,只要該 Pod 對象一直存在沒被移除旺罢。
如果容器中的主進程由于某些原因終止運行旷余,Kubernetes 就會自動重啟該容器。
創(chuàng)建如下內(nèi)容的清單文件 kubia-ssl.yml
:
apiVersion: v1
kind: Pod
metadata:
name: kubia-ssl
spec:
containers:
- name: kubia
image: luksa/kubia:1.0
ports:
- name: http
containerPort: 8080
- name: envoy
image: luksa/kubia-ssl-proxy:1.0
ports:
- name: https
containerPort: 8443
- name: admin
containerPort: 9901
運行如下命令應(yīng)用上述清單文件扁达,并啟用端口轉(zhuǎn)發(fā):
$ kubectl apply -f kubia-ssl.yml
pod/kubia-ssl created
$ kubectl port-forward kubia-ssl 8080 8443 9901
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Forwarding from 127.0.0.1:8443 -> 8443
Forwarding from [::1]:8443 -> 8443
Forwarding from 127.0.0.1:9901 -> 9901
Forwarding from [::1]:9901 -> 9901
待容器啟動成功后正卧,訪問 localhost 的 8080、8443跪解、9901 端口就等同于訪問容器中 8080炉旷、8443、9901 端口上運行的服務(wù)叉讥。
打開一個新的命令行窗口運行 kubectl get pods -w
命令窘行,實時監(jiān)控容器的運行狀態(tài)。
打開一個新的命令行窗口運行 kubectl get events -w
命令图仓,實時監(jiān)控觸發(fā)的事件罐盔。
打開一個新的命令行窗口,嘗試終止 Envoy 容器中運行的主進程救崔。Envoy 容器 9901 端口上運行的服務(wù)剛好提供了一個管理接口惶看,能夠接收 HTTP POST 請求來終止進程:
$ curl -X POST http://localhost:9901/quitquitquit
OK
此時查看前兩個窗口中的輸出捏顺,負責監(jiān)控容器狀態(tài)的窗口輸出如下:
$ kubectl get pods -w
NAME READY STATUS RESTARTS AGE
kubia-ssl 2/2 Running 0 11m
kubia-ssl 1/2 NotReady 0 12m
kubia-ssl 2/2 Running 1 (2s ago) 12m
最新的輸出表明,在殺掉 Envoy 容器中的主進程后纬黎,Pod 的狀態(tài)是先變成 NotReady
幅骄,之后就立即重啟該容器,Pod 的狀態(tài)稍后恢復(fù)成 Running
本今。
負責監(jiān)控最新事件的窗口輸出如下:
$ kubectl get events -w
LAST SEEN TYPE REASON OBJECT MESSAGE
11m Normal Scheduled pod/kubia-ssl Successfully assigned default/kubia-ssl to minikube
11m Normal Pulled pod/kubia-ssl Container image "luksa/kubia:1.0" already present on machine
11m Normal Created pod/kubia-ssl Created container kubia
11m Normal Started pod/kubia-ssl Started container kubia
11m Normal Pulled pod/kubia-ssl Container image "luksa/kubia-ssl-proxy:1.0" already present on machine
11m Normal Created pod/kubia-ssl Created container envoy
11m Normal Started pod/kubia-ssl Started container envoy
0s Normal Pulled pod/kubia-ssl Container image "luksa/kubia-ssl-proxy:1.0" already present on machine
0s Normal Created pod/kubia-ssl Created container envoy
0s Normal Started pod/kubia-ssl Started container envoy
最新的事件信息中包含了新的 envoy 容器啟動的過程拆座。其中有一個很重要的細節(jié):Kubernetes 從來不會重啟容器,而是直接丟棄停止的容器并創(chuàng)建一個新的冠息。一般在 Kubernetes 中提及“重啟”容器懂拾,實質(zhì)上都指的是“重建”。
任何寫入到容器文件系統(tǒng)中的數(shù)據(jù)铐达,在容器重新創(chuàng)建后都會丟失岖赋。為了持久化這些數(shù)據(jù),需要向 Pod 添加 Volume瓮孙。
配置容器的重啟策略
Kubernetes 支持 3 種容器重啟策略:
-
Always
:默認配置唐断。不管容器中主進程的退出碼是多少,容器都會自動重啟 -
OnFailure
:容器只會在退出碼非 0 時重啟 -
Never
:容器永不重啟
容器重啟時的延遲時間
第一次容器終止時杭抠,重啟會立即觸發(fā)脸甘。但容器第二次重啟時會先等待 10s,這個等待時間會隨著重啟次數(shù)依次增加到 20偏灿、40丹诀、80魄咕、160s辉浦。再之后則一直保持在 5 分鐘惫皱。
等待過程中容器會處于 Waiting
狀態(tài)路翻,reason
字段顯示 CrashLoopBackOff
做盅,message
字段顯示需要等待的時間敌蚜。
liveness probes
Kubernetes 會在容器的進程終止時重啟容器灵再,以保證應(yīng)用的健康边翁。但應(yīng)用實際上有可能在進程不終止的情況下無響應(yīng)啼肩,比如一個 Java 應(yīng)用報出 OutOfMemoryError 錯誤橄妆,而 JVM 進程仍在運行中。
理想情況下祈坠,Kubernetes 需要能夠檢測到此類錯誤并重啟容器害碾。
當然,應(yīng)用自身也可以捕獲這類錯誤并令進程立即終止赦拘。但假如應(yīng)用因為進入無限循環(huán)或死鎖導致無響應(yīng)慌随,又或者應(yīng)用本身無法檢測到錯誤存在呢?
為了確保容器能夠在這些復(fù)雜情況下重啟另绩,應(yīng)該提供一種從外部檢查應(yīng)用狀態(tài)的機制儒陨。
liveness probe 介紹
Kubernetes 可以通過配置 liveness probe 來檢查某個應(yīng)用是否能夠正常響應(yīng)花嘶,Pod 中的每個容器都可以分別配置 liveness probe。一旦應(yīng)用無響應(yīng)或有錯誤發(fā)生蹦漠,容器就會被認為是不健康的并被終止掉椭员。之后容器被 Kubernetes 重新啟動。
Kubernetes 支持以下三種 probe 機制:
-
HTTP GET probe
:會發(fā)送 GET 請求到容器的 IP 地址笛园、端口號和 URL 路徑隘击。如果 probe 收到正常的響應(yīng)(2xx 或 3xx),該 probe 就被認定是成功的研铆。如果服務(wù)返回了一個錯誤的響應(yīng)碼埋同,或者沒有在規(guī)定的時間內(nèi)響應(yīng),則該 probe 被認定是失敗的棵红。 -
TCP Socket probe
:會嘗試打開一個 TCP 連接到容器的特定端口凶赁。若連接成功,probe 就被認定是成功的逆甜;否則失敗虱肄。 -
Exec probe
:會在容器內(nèi)部執(zhí)行一個命令并檢查該命令的退出碼。若退出碼為 0交煞,則 probe 被認定是成功的咏窿;否則失敗。
HTTP GET liveness probe
創(chuàng)建如下內(nèi)容的 kubia-liveness.yml
清單文件:
apiVersion: v1
kind: Pod
metadata:
name: kubia-liveness
spec:
containers:
- name: kubia
image: luksa/kubia:1.0
ports:
- name: http
containerPort: 8080
livenessProbe:
httpGet:
path: /
port: 8080
- name: envoy
image: luksa/kubia-ssl-proxy:1.0
ports:
- name: https
containerPort: 8443
- name: admin
containerPort: 9901
livenessProbe:
httpGet:
path: /ready
port: admin
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
其中 kubia 容器的 liveness probe 是最簡單版本的 HTTP 應(yīng)用的 probe素征。該 probe 只是向 8080 端口的 /
路徑發(fā)送 HTTP GET集嵌,看容器是否仍然能夠處理請求。當應(yīng)用的響應(yīng)碼介于 200 到 399 之間時御毅,該應(yīng)用就被認為是健康的根欧。
由于該 probe 沒有配置其他選項,默認配置生效亚享。第一次檢查請求會在容器啟動 10s 后發(fā)起咽块,之后每隔 10s 發(fā)起新的請求绘面。若應(yīng)用沒有在 1s 之內(nèi)響應(yīng)欺税,則該次 probe 請求被認定是失敗的。連續(xù) 3 次請求失敗以后揭璃,容器就被認為是不健康的并被終止掉晚凿。
Envoy 容器的管理員接口提供了一個 /ready
入口,可以返回其健康狀態(tài)瘦馍,因此 envoy 容器的 liveness probe 的目標可以是容器的 admin
端口即 9901歼秽。
參數(shù) initialDelaySeconds
表示容器啟動后到發(fā)起第一個檢測請求之間的等待時間,periodSeconds
表示兩次連續(xù)的檢測請求之間的時間間隔情组,timeoutSeconds
表示多長時間以后沒有響應(yīng)則認定此次檢測失敗燥筷,failureThreshold
則表示連續(xù)多少次檢測失敗以后才認定容器失效并重啟箩祥。
觀察 liveness probe 的效果
運行 kubectl apply
命令應(yīng)用上述清單文件并通過 kubectl port-forward
命令啟用端口轉(zhuǎn)發(fā),啟動該 Pod 并令其能夠被訪問:
$ kubectl apply -f kubia-liveness.yml
pod/kubia-liveness created
$ kubectl port-forward kubia-liveness 8080 8443 9901
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Forwarding from 127.0.0.1:8443 -> 8443
Forwarding from [::1]:8443 -> 8443
Forwarding from 127.0.0.1:9901 -> 9901
Forwarding from [::1]:9901 -> 9901
Pod 啟動成功以后肆氓,liveness probe 會在初始等待時間過后持續(xù)向 Pod 中的容器發(fā)起檢測請求袍祖,其檢測結(jié)果只會在容器的 log 中看到。
kubia 容器中的 Node.js 應(yīng)用會在每次處理 HTTP 請求時向標準輸出打印記錄谢揪,這些請求也包括 liveness probe 的檢測請求蕉陋。因此可以打開一個新的命令行窗口,使用如下命令查看請求記錄:
$ kubectl logs kubia-liveness -c kubia -f
Kubia server starting...
Local hostname is kubia-liveness
Listening on port 8080
Received request for / from ::ffff:172.17.0.1
Received request for / from ::ffff:172.17.0.1
Received request for / from ::ffff:172.17.0.1
Received request for / from ::ffff:172.17.0.1
Received request for / from ::ffff:172.17.0.1
...
envoy 容器的 liveness probe 被配置成向其管理員接口發(fā)送 HTTP 請求拨扶,這些請求被記錄在 /var/log/envoy.admin.log
文件中凳鬓。可以使用如下命令查看:
$ kubectl exec kubia-liveness -c envoy -- tail -f /var/log/envoy.admin.log
[2022-01-02T18:34:59.818Z] "GET /ready HTTP/1.1" 200 - 0 5 0 - "172.17.0.1" "kube-probe/1.22" "-" "172.17.0.3:9901" "-"
[2022-01-02T18:35:04.818Z] "GET /ready HTTP/1.1" 200 - 0 5 0 - "172.17.0.1" "kube-probe/1.22" "-" "172.17.0.3:9901" "-"
[2022-01-02T18:35:09.818Z] "GET /ready HTTP/1.1" 200 - 0 5 0 - "172.17.0.1" "kube-probe/1.22" "-" "172.17.0.3:9901" "-"
[2022-01-02T18:35:14.818Z] "GET /ready HTTP/1.1" 200 - 0 5 0 - "172.17.0.1" "kube-probe/1.22" "-" "172.17.0.3:9901" "-"
觀察失敗的 liveness probe
可以嘗試手動令 liveness probe 的檢測請求失敗患民。先在一個新的窗口中運行 kubectl get events -w
命令缩举,方便后續(xù)觀察檢測失敗時輸出的事件信息。
訪問 Envoy 容器的管理員接口匹颤,手動配置其健康狀態(tài)為 fail
:
$ curl -X POST localhost:9901/healthcheck/fail
OK
此時轉(zhuǎn)到觀察事件信息的命令行窗口蚁孔,發(fā)現(xiàn)連續(xù)輸出了 3 次 probe failed 503 錯誤,之后 envoy 容器開始重啟:
kubectl get events -w
LAST SEEN TYPE REASON OBJECT MESSAGE
...
0s Warning Unhealthy pod/kubia-liveness Liveness probe failed: HTTP probe failed with statuscode: 503
0s Warning Unhealthy pod/kubia-liveness Liveness probe failed: HTTP probe failed with statuscode: 503
0s Warning Unhealthy pod/kubia-liveness Liveness probe failed: HTTP probe failed with statuscode: 503
0s Normal Killing pod/kubia-liveness Container envoy failed liveness probe, will be restarted
0s Normal Pulled pod/kubia-liveness Container image "luksa/kubia-ssl-proxy:1.0" already present on machine
0s Normal Created pod/kubia-liveness Created container envoy
0s Normal Started pod/kubia-liveness Started container envoy
exec & tcpSocket liveness probe
添加 tcpSocket liveness probe
對于接收非 HTTP 請求的應(yīng)用惋嚎,可以配置 tcpSocket liveness probe杠氢。
一個 tcpSocket liveness probe 的示例配置如下:
livenessProbe:
tcpSocket:
port: 1234
periodSeconds: 2
failureThreshold: 1
該 probe 會檢查容器的 1234 端口是否打開,每隔 2s 檢查一次另伍,一次檢查失敗則認定該容器是不健康的并重啟它鼻百。
exec liveness probe
不接受 TCP 連接的應(yīng)用可以配置一條命令去檢測其狀態(tài)。
下面的示例配置會每隔 2s 運行 /usr/bin/healthcheck
命令摆尝,檢測容器中的應(yīng)用是否仍在運行:
livenessProbe:
exec:
command:
- /usr/bin/healthcheck
periodSeconds: 2
timeoutSeconds: 1
failureThreshold: 1
startup probe
默認的 liveness probe 配置會給應(yīng)用 20 到 30s 的時間啟動温艇,如果應(yīng)用需要更長的時間才能啟動完成,容器會永遠達不到 liveness probe 檢測成功的狀態(tài)堕汞,從而進入了無限重啟的循環(huán)勺爱。
為了防止上述情況發(fā)生,可以增大 initialDelaySeconds
讯检、periodSeconds
或 failureThreshold
的值琐鲁,但也會有一定的副作用。periodSeconds * failureThreshold
的值越大人灼,當應(yīng)用不健康時重啟的時間就越長围段。
Kubernetes 還提供了一種 startup probe。當容器配置了 startup probe 時投放,容器啟動時只有 startup probe 會執(zhí)行奈泪。startup probe 可以按照應(yīng)用的啟動時間配置,檢測成功之后 Kubernetes 會切換到使用 liveness probe 檢測。
比如 Node.js 應(yīng)用需要 1 分鐘以上的時間啟動涝桅,當啟動成功以后若應(yīng)用狀態(tài)不正常拜姿,則在 10s 以內(nèi)重啟》胨欤可以這樣配置:
containers:
- name: kubia
image: luksa/kubia:1.0
ports:
- name: http
containerPort: 8080
startupProbe:
httpGet:
path: /
port: http
periodSeconds: 10
failureThreshold: 12
livenessProbe:
httpGet:
path: /
port: http
periodSeconds: 5
failureThreshold: 2
上面配置的效果如下圖:
應(yīng)用有 120s 的時間啟動砾隅。Kubernetes 一開始每隔 10s 發(fā)起 startup probe 請求,最多嘗試 12 次债蜜。
不同于 liveness probe晴埂,startup probe 失敗是很正常的,只是說明應(yīng)用還未成功啟動寻定。一旦某次 startup probe 檢測返回成功狀態(tài)儒洛,Kubernetes 就會立即切換到 liveness probe 模式,通常擁有更短的檢測間隔狼速,能夠?qū)ξ错憫?yīng)應(yīng)用做出更快速的反應(yīng)琅锻。
在容器啟動或關(guān)閉時觸發(fā)動作
可以向容器中添加 lifecycle hooks。Kubernetes 目前支持兩種類型的鉤子:
- Post-start hooks:在容器啟動后執(zhí)行
- Pre-stop hooks:在容器停止前執(zhí)行
post-start hooks
post-start lifecycle hook 會在容器創(chuàng)建完成之后立即觸發(fā)向胡∧张睿可以使用 exec
類型的鉤子在主進程啟動的同時執(zhí)行一個額外的程序,或者 httpGet
類型的鉤子向容器中運行的應(yīng)用發(fā)送 HTTP 請求僵芹,以完成初始化或預(yù)熱操作处硬。
假如你是應(yīng)用的作者,類似的操作當然可以加入到應(yīng)用本身的代碼中拇派。但對于一個已經(jīng)存在的并非自己創(chuàng)建的應(yīng)用荷辕,就有可能無法做到。post-start hook 提供了一種不需要修改應(yīng)用或容器鏡像的替代方案件豌。
post-start hook 在容器中執(zhí)行命令
apiVersion: v1
kind: Pod
metadata:
name: fortune-poststart
spec:
containers:
- name: nginx
image: nginx:alpine
lifecycle:
postStart:
exec:
command:
- sh
- -c
- "apk add fortune && fortune > /usr/share/nginx/html/quote"
ports:
- name: http
containerPort: 80
上述清單文件定義的 Pod 名為 fortune-poststart
疮方,包含一個基于 nginx:alpine
鏡像的容器,同時定義了一個 postStart
鉤子茧彤。該鉤子會在 Nginx 服務(wù)啟動時執(zhí)行以下命令:
sh -c "apk add fortune && fortune > /usr/share/nginx/html/quote"
postStart
這個名稱其實有些誤導作用骡显,它并不是在主進程完全啟動后才開始執(zhí)行,而是在容器創(chuàng)建后曾掂,幾乎和主進程同時執(zhí)行惫谤。
$ kubectl apply -f fortune-poststart.yml
pod/fortune-poststart unchanged
$ kubectl port-forward fortune-poststart 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
打開一個新的命令行窗口使用 curl
命令測試效果:
$ curl localhost:8080/quote
The Official MBA Handbook on business cards:
Avoid overly pretentious job titles such as "Lord of the Realm,
Defender of the Faith, Emperor of India" or "Director of Corporate
Planning."
post-startup hook 對容器的影響
雖然 post-start hook 相對于容器的主進程以異步的方式執(zhí)行,它還是會對容器產(chǎn)生兩個方面的影響遭殉。
首先石挂,在 post-start hook 的執(zhí)行過程中容器會一直處于 Waiting
狀態(tài),原因顯示為 ContainerCreating
险污,直到 hook 執(zhí)行完畢。
其次,若 hook 綁定的命令無法執(zhí)行或返回了一個非零的狀態(tài)值蛔糯,則整個容器會被重啟拯腮。
在容器終止前執(zhí)行命令
前面 fortune Pod 中的 Nginx 服務(wù)在收到 TERM
信號后會立即關(guān)閉所有打開的連接并終止進程,這并不是理想的操作蚁飒,不會等待正在處理的客戶端請求徹底完成动壤。
可以使用 pre-stop hook 執(zhí)行 nginx -s quit
命令舒緩地關(guān)閉 Nginx 服務(wù)。示例配置如下:
lifecycle:
preStop:
exec:
command:
- nginx
- -s
- quit
假如某個 pre-stop hook 執(zhí)行失敗淮逻,只會在 Pod 的 events 消息中顯示一條 FailedPreStopHook
警告信息琼懊,并不影響容器繼續(xù)被終止。
理解容器的生命周期
一個 Pod 的生命周期可以被分成如下三個階段:
- 初始化階段:Pod 的 init 容器從開始運行到啟動完成
- 運行階段:Pod 的普通容器從開始運行到啟動完成
- 終止階段:Pod 的所有容器被終止運行
初始化階段
Pod 中的初始化容器會最先運行爬早,按照 spec
的 initContainers
字段中定義的順序哼丈。
第一個初始化容器的鏡像被下載到工作節(jié)點并啟動,完成后繼續(xù)拉取第二個初始化容器的鏡像筛严,直到所有的初始化容器都成功運行醉旦。
若某個初始化容器因為某些錯誤啟動失敗,且其重啟策略設(shè)置為 Always
或 OnFailure
桨啃,則該失敗的容器自動重啟车胡。若其重啟策略設(shè)置為 Never
,則 Pod 的狀態(tài)顯示為 Init:Error
照瘾,必須刪除并重新創(chuàng)建 Pod 對象匈棘。
運行階段
當所有的初始化容器成功運行后,Pod 的普通容器開始以并行的方式創(chuàng)建(需要注意的是析命,容器的 post-start hook 會阻塞下一個容器的創(chuàng)建)羹饰。
termination grace period
容器中的應(yīng)用都有一個固定的關(guān)閉時間做緩沖用,定義在 spec
下的 terminationGracePeriodSeconds
字段中碳却,默認是 30s队秩。
該時間從 pre-stop hook 觸發(fā)或收到 TERM
信號時開始計算,若時間過了進程仍在運行昼浦,應(yīng)用會收到 KILL
信號被強制關(guān)閉馍资。
終止階段
Pod 的容器以并行的方式終止。對每個容器來說关噪,pre-stop hook 觸發(fā)鸟蟹,然后主進程接收 TERM
信號,如果應(yīng)用關(guān)閉的時間超過了 terminationGracePeriodSeconds
使兔,就發(fā)送 KILL
信號給容器的主進程建钥。
在所有的容器都被終止以后,Pod 對象被刪除虐沥。
可以在刪除一個 Pod 時手動指定一個新的時間覆蓋 terminationGracePeriodSeconds
的值熊经,如:
kubectl delete po kubia-ssl --grace-period 10