【kubernetes入門到精通】Kubernetes的健康監(jiān)測機制以及常見ExitCode問題分析「探索篇」

2022-12-31 20:33:34 來源:51CTO博客

kubernetes進(jìn)行Killed我們服務(wù)的問題背景

無論是在微服務(wù)體系還是云原生體系的開發(fā)迭代過程中,通常都會以Kubernetes進(jìn)行容器化部署,但是這也往往帶來了很多意外的場景和情況。例如,雖然我們已經(jīng)將JVM堆內(nèi)存設(shè)置為小于Docker容器中內(nèi)存及K8S的Pod的內(nèi)存,但是還是會被K8s給無情的殺掉(Kill -9 / Kill -15)Killed。當(dāng)發(fā)生了Killed的時候,我們該如何分析和判斷呢?在此我們介紹一下K8s的Killed的Exit Code編碼。

kubernetes健康檢測體系之探針

K8s中的探針用來對pod中容器的狀態(tài)進(jìn)行檢測,有3種探針,存活探針、就緒探針、啟動探針。

kubernetes如何監(jiān)控和管理我們的Pod的運行狀態(tài)

Kubernetes中的健康檢查主要使用就緒性探針(readinessProbes)存活性探針(livenessProbes)來實現(xiàn),service即為負(fù)載均衡,k8s保證service后面的pod都可用,是k8s中自愈能力的主要手段,主要基于這兩種探測機制,可以實現(xiàn)如下需求:


(資料圖片)

異常實例自動剔除,并重啟新實例多種類型探針檢測,保證異常pod不接入流量不停機部署,更安全的滾動升級
存活探針 — livenessProbes

kubelet使用 存活探針來確定什么時候要重啟容器。 例如,存活探針可以探測到應(yīng)用死鎖(應(yīng)用程序在運行,但是無法繼續(xù)執(zhí)行后面的步驟)情況,重啟這種狀態(tài)下的容器有助于提高應(yīng)用的可用性,即使其中存在缺陷。

就緒探針 — readinessProbes

kubelet使用就緒探針可以知道容器何時準(zhǔn)備好接受請求流量,當(dāng)一個 Pod 內(nèi)的所有容器都就緒時,才能認(rèn)為該 Pod 就緒。 該指針用來指示容器是否準(zhǔn)備好為請求提供服務(wù)。如果就緒態(tài)探測失敗,kubelet將該Pod提供的所有服務(wù)的endpoint列表中刪除該Pod的 IP地址。

與存活探針的區(qū)別

當(dāng)容器未通過檢查準(zhǔn)備,則不會被終止或重新啟動。存活探針通過殺死異常的容器并用新的容器去替代他們的工作,而就緒探針確保只有準(zhǔn)備好處理請求的pod才能在服務(wù)集群中。

啟動探針 — startupProbes( 1.17 版本新增)

kubelet使用啟動探針來了解應(yīng)用容器何時啟動。 如果配置了這類探針,你就可以控制容器在啟動成功后再進(jìn)行存活性和就緒態(tài)檢查, 確保這些存活、就緒探針不會影響應(yīng)用的啟動。

啟動探針可以用于對慢啟動容器進(jìn)行存活性檢測,避免它們在啟動運行之前就被殺掉,如:使用了啟動探針,則所有其他探針都會被禁用,直到此探針成功為止。如果啟動探測失敗,kubelet將殺死容器,而容器依其重啟策略進(jìn)行重啟。

探針的3種機制

每種探測機制支持三種健康檢查方法,分別是命令行exec,httpGet和tcpSocket,其中exec通用性最強,適用與大部分場景,tcpSocket適用于TCP業(yè)務(wù),httpGet適用于web業(yè)務(wù)。

HTTP GEt:該類型的探針通過容器的IP地址、端口號及路徑調(diào)用 HTTP Get請求,如果響應(yīng)的狀態(tài)碼大于等于200且小于400,則認(rèn)為容器 健康。TcpSocket:該類型的探針嘗試與容器指定端口建立TCP連接,如果端口打開,則診斷被認(rèn)為是成功的。Exec(自定義健康檢查):該類型的探針在容器內(nèi)執(zhí)行任意的命令,如果命令退出時返回碼為0,則認(rèn)為診斷成功。
配置和設(shè)定livenessProbes探針

通過在yaml文件中pod的spec部分的containers里面添加一個字段livenessProbe來添加存活指針:

livenessProbe執(zhí)行模式執(zhí)行探針控制(httpGet)
apiVersion: v1kind: Podmetadata:  labels:    test: liveness  name: liveness-httpspec:  containers:  - name: liveness    image: registry.k8s.io/liveness    args:    - /server    livenessProbe:      httpGet:        path: /healthz        port: 8080        httpHeaders:        - name: Custom-Header          value: Awesome      initialDelaySeconds: 3      periodSeconds: 3
Exec執(zhí)行模式執(zhí)行探針控制(exec)
apiVersion: v1kind: Podmetadata:  labels:    test: liveness  name: liveness-execspec:  containers:  - name: liveness    image: registry.k8s.io/busybox    args:    - /bin/sh    - -c    - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600    livenessProbe:      exec:        command:        - cat        - /tmp/healthy      initialDelaySeconds: 5      periodSeconds: 5
livenessProbe執(zhí)行模式執(zhí)行探針控制(tcpSocket)
apiVersion: v1kind: Podmetadata:  name: goproxy  labels:    app: goproxyspec:  containers:  - name: goproxy    image: registry.k8s.io/goproxy:0.1    ports:    - containerPort: 8080    readinessProbe:      tcpSocket:        port: 8080      initialDelaySeconds: 5      periodSeconds: 10    livenessProbe:      tcpSocket:        port: 8080      initialDelaySeconds: 15      periodSeconds: 20

每次探測都將獲得以下三種結(jié)果之一:

Success(成功):表示容器通過了診斷。Failure(失敗):表示容器未通過診斷。Unknown(未知):表示沒有正常進(jìn)行且診斷失敗,因此不會采取任何行動。

容器退出狀態(tài)碼的區(qū)間

Exit Codes的取值范圍必須在0-255之間。可以參考:??https://tldp.org/LDP/abs/html/exitcodes.html,如下圖所示。??

0:表示正常退出1-128:一般程序自身原因?qū)е碌漠惓M顺鰻顟B(tài)區(qū)間在 1-128 (這只是一般約定,程序如果一定要用129-255的狀態(tài)碼也是可以的)129-255:外界中斷將程序退出的時候狀態(tài)碼區(qū)間在129-255,(操作系統(tǒng)給程序發(fā)送中斷信號,比如 kill -9 是 SIGKILL)
查看 Pod 退出狀態(tài)碼
$ kubectl describe pods ${pod-name}

如下圖所示:

Exit Code 0

退出代碼0表示特定容器沒有附加前臺進(jìn)程,該退出代碼是所有其他后續(xù)退出代碼的例外,這不一定意味著發(fā)生了不好的事情。如果開發(fā)人員想要在容器完成其工作后自動停止其容器,則使用此退出代碼。比如:kubernetes job在執(zhí)行完任務(wù)后正常退出碼為 0

Exit Code 1

程序錯誤,或者Dockerfile中引用不存在的文件,如 entrypoint中引用了錯誤的包程序錯誤可以很簡單,例如 “除以0”,也可以很復(fù)雜,比如空引用或者其他程序 crash

Exit Code 139

Exit Code 139: Indicates failure as container received SIGSEGV

表明容器收到了 SIGSEGV 信號,無效的內(nèi)存引用,對應(yīng)kill -11,一般是代碼有問題,或者 docker 的基礎(chǔ)鏡像有問題

Exit Code 143

Exit Code 143: Indicates failure as container received SIGTERM

表明容器收到了 SIGTERM 信號,終端關(guān)閉,對應(yīng)kill -15,一般對應(yīng) docker stop 命令,有時docker stop也會導(dǎo)致Exit Code 137,發(fā)生在與代碼無法處理SIGTERM的情況下,docker進(jìn)程等待十秒鐘然后發(fā)出 SIGKILL 強制退出。

Exit Code 137

Exit Code 137: Indicates failure as container received SIGKILL

表明容器收到了 SIGKILL 信號,進(jìn)程被殺掉,對應(yīng)kill -9,引發(fā)SIGKILL的是docker kill。這可以由用戶或由docker守護(hù)程序來發(fā)起,手動執(zhí)行:docker kill(Manual intervention or ‘oom-killer’ [OUT-OF-MEMORY]) 被手動干預(yù)殺死進(jìn)程,或者違反系統(tǒng)限制被殺

137 比較常見,如果 pod 中的limit 資源設(shè)置較小,會運行內(nèi)存不足導(dǎo)致 OOMKilled,此時state 中的 ”O(jiān)OMKilled” 值為true,你可以在系統(tǒng)的 dmesg -T 中看到 oom 日志

內(nèi)存溢出問題

此狀態(tài)碼一般是因為 pod 中容器內(nèi)存達(dá)到了它的資源限制(resources.limits),一般是內(nèi)存溢出(OOM),CPU達(dá)到限制只需要不分時間片給程序就可以。因為限制資源是通過 linux 的 cgroup 實現(xiàn)的,所以 cgroup 會將此容器強制殺掉,類似于kill -9,此時在describe pod中可以看到 Reason 是OOMKilled

還可能是宿主機本身資源不夠用了(OOM),內(nèi)核會選取一些進(jìn)程殺掉來釋放內(nèi)存,不管是 cgroup 限制殺掉進(jìn)程還是因為節(jié)點機器本身資源不夠?qū)е逻M(jìn)程死掉,都可以從系統(tǒng)日志中找到記錄:

ubuntu 的系統(tǒng)日志在/var/log/syslog,centos的系統(tǒng)日志在/var/log/messages,都可以用journalctl -k來查看系統(tǒng)日志

標(biāo)簽: 系統(tǒng)日志 退出狀態(tài)

上一篇:每日播報!一文了解 Go fmt 標(biāo)準(zhǔn)庫輸入函數(shù)的使用
下一篇:Docker可視化管理工具 - Portainer