Kubernetes實(shí)踐之優(yōu)雅終止
本文轉(zhuǎn)載自微信公眾號(hào)「云原生知識(shí)宇宙」,作者I am roc。轉(zhuǎn)載本文請聯(lián)系云原生知識(shí)宇宙公眾號(hào)。
概述
Pod 銷毀時(shí),會(huì)停止容器內(nèi)的進(jìn)程,通常在停止的過程中我們需要執(zhí)行一些善后邏輯,比如等待存量請求處理完以避免連接中斷,或通知相關(guān)依賴進(jìn)行清理等,從而實(shí)現(xiàn)優(yōu)雅終止目的。本文介紹在 Kubernetes 場景下,實(shí)現(xiàn)容器優(yōu)雅終止的最佳實(shí)踐。
容器終止流程
我們先了解下容器在 Kubernetes 環(huán)境中的終止流程:
- Pod 被刪除,狀態(tài)置為 Terminating。
- kube-proxy 更新轉(zhuǎn)發(fā)規(guī)則,將 Pod 從 service 的 endpoint 列表中摘除掉,新的流量不再轉(zhuǎn)發(fā)到該 Pod。
- 如果 Pod 配置了 preStop Hook ,將會(huì)執(zhí)行。
- kubelet 對(duì) Pod 中各個(gè) container 發(fā)送 SIGTERM 信號(hào)以通知容器進(jìn)程開始優(yōu)雅停止。
- 等待容器進(jìn)程完全停止,如果在 terminationGracePeriodSeconds 內(nèi) (默認(rèn) 30s) 還未完全停止,就發(fā)送 SIGKILL 信號(hào)強(qiáng)制殺死進(jìn)程。
- 所有容器進(jìn)程終止,清理 Pod 資源。
業(yè)務(wù)代碼處理 SIGTERM 信號(hào)
要實(shí)現(xiàn)優(yōu)雅終止,務(wù)必在業(yè)務(wù)代碼里面處理下 SIGTERM 信號(hào),參考 處理 SIGTERM 代碼示例 ) 。
別讓 shell 導(dǎo)致收不到 SIGTERM 信號(hào)
如果容器啟動(dòng)入口使用了腳本 (如 CMD ["/start.sh"]),業(yè)務(wù)進(jìn)程就成了 shell 的子進(jìn)程,在 Pod 停止時(shí)業(yè)務(wù)進(jìn)程可能收不到 SIGTERM 信號(hào),因?yàn)?shell 不會(huì)自動(dòng)傳遞信號(hào)給子進(jìn)程。更詳細(xì)解釋請參考 為什么我的容器收不到 SIGTERM 信號(hào) ?
如果解決?請參考 在 SHELL 中傳遞信號(hào)。
合理使用 preStop Hook
若你的業(yè)務(wù)代碼中沒有處理 SIGTERM 信號(hào),或者你無法控制使用的第三方庫或系統(tǒng)來增加優(yōu)雅終止的邏輯,也可以嘗試為 Pod 配置下 preStop,在這里面實(shí)現(xiàn)優(yōu)雅終止的邏輯,示例:
- lifecycle:
- preStop:
- exec:
- command:
- - /clean.sh
參考 Kubernetes API 文檔
在某些極端情況下,Pod 被刪除的一小段時(shí)間內(nèi),仍然可能有新連接被轉(zhuǎn)發(fā)過來,因?yàn)?kubelet 與 kube-proxy 同時(shí) watch 到 pod 被刪除,kubelet 有可能在 kube-proxy 同步完規(guī)則前就已經(jīng)停止容器了,這時(shí)可能導(dǎo)致一些新的連接被轉(zhuǎn)發(fā)到正在刪除的 Pod,而通常情況下,當(dāng)應(yīng)用受到 SIGTERM 后都不再接受新連接,只保持存量連接繼續(xù)處理,所以就可能導(dǎo)致 Pod 刪除的瞬間部分請求失敗。
這種情況下,我們也可以利用 preStop 先 sleep 一小下,等待 kube-proxy 完成規(guī)則同步再開始停止容器內(nèi)進(jìn)程:
- lifecycle:
- preStop:
- exec:
- command:
- - sleep
- - 5s
調(diào)整優(yōu)雅時(shí)長
如果需要的優(yōu)雅終止時(shí)間比較長 (preStop + 業(yè)務(wù)進(jìn)程停止可能超過 30s),可根據(jù)實(shí)際情況自定義 terminationGracePeriodSeconds,避免過早的被 SIGKILL 殺死,示例:
參考資料
處理 SIGTERM 代碼示例: https://imroc.cc/k8s/ref/code-example-of-handle-sigterm/
為什么我的容器收不到 SIGTERM 信號(hào): https://imroc.cc/k8s/faq/why-cannot-receive-sigterm/
在 SHELL 中傳遞信號(hào): https://imroc.cc/k8s/trick/propagating-signals-in-shell/