1. 程式人生 > 實用技巧 >容器殭屍程序造成叢集節點NotReady

容器殭屍程序造成叢集節點NotReady

問題

叢集工作節點頻繁NotReady

NAME  STATUS  ROLE  AGE  VERSION
10.9.x.x NotReady <none> 120d v1.13.9

檢視工作節點/var/log/messages日誌,發現PLEG not healthy導致Not become not ready。

Jul 12 03:24:22 hostnamex kubelet:I0712 03:24:22.233328 2653 kubelet.go:1846] skipping pod synchronization - [PLEG is not healthy: pleg was last seen active 3m7.15341635s ago; threshold is
3m0s] Jul 12 03:24:23 hostnamex kubelet:I0712 03:24:23.731971 2563 setters.go:520] Node vecame not ready:{Type:Ready Status:False LastHeartbeatTime:2020-07-12 -3:24:23.731942491 +0800 CST m=+6020732.425522098 LastTransitionTime:2020-07-12 03:24:23.731942491 +0800 CST m=+6020732.425522098 Reason:KubeletNotReady Message:PLEG is
not healthy: pleg was last seen active 3m8.652082872s ago; threshold is 3m0s}

排查臨近時間點的日誌,發現PLEG一直無法獲取某一個POD 的狀態。

Jul 12 03:21:14 hostnamex kubelet: E0712 03:21:14.079575 2563 generic.go:277] PLEG: pod xxx-xxx-xxx-xxx/xxx-xxx-xxx failed reinspection: rpc error: code = DeadlineExceeded desc = context deadline exceeded
Jul 
12 03:23:15 hostnamex kubelet: E0712 03:23:15.100271 2563 generic.go:247] PLEG: Ignoring events for pod xxx-xxx-xxx-xxx/xxx-xxx-xxx: rpc error: code = DeadlineExceeded desc = context deadline exceeded

執行'kubectl get pod xxx-xxx-xxx-xxx -n xxx-xxx-xxx',發現這個POD不存在。

執行'docker ps | grep xxx-xxx-xxx-xxx',發現容器還在,但是執行'docker inspect <container id>'時命令卡死無響應。

檢視/var/lib/docker/containers/<container id>/config.v2.json'檔案中的Pid欄位,獲取容器PID。

'ps -ef | grep <PID>' 發現有殭屍程序,並且這些殭屍程序均為sh或su程序。

進入使用者正常的POD中檢視程序,發現使用者在同一個容器中運行了多個不同的應用,例如shell,uwsgi,nginx。而容器的原則是應該儘量保持容器功能的單一,把不同功能的應用拆分成多個容器。

並且,使用者容器中有多個sh和su程序,其父程序ID為0,並且啟動時間比容器啟動時間晚了幾天。懷疑是使用者進入容器執行的命令。

經測試,如果使用者通過kubectl exec進入容器,會生成父程序ID為0的程序。如果使用者正常退出的話,這些程序會自動結束,但如果會話因為超時退出,這些程序則無法自動結束,會遺留在容器中。

為什麼會話會超時呢?kubectl exec其實是通過kube-api -> kubelet -> docker daemon -> docker 容器執行命令的,kubelet本身有超時限制(--streaming-connection-idle-timeout),預設是4小時。另外,有些平臺自行開發了在網頁登入容器的功能,這些平臺本身也會有超時限制。

解決方案

因為使用者的容器是通過shell程序啟動的,所以容器中的PID 1程序為shell程序,如果shell程序不能正常回收容器中因為kubectl exec遺留下的程序,則可能會造成殭屍程序。

於是建議使用者通過dumb-init啟動應用。關於dumb-init的介紹及下載可以參考以下連結:

https://github.com/Yelp/dumb-init

https://github.com/Yelp/dumb-init/releases/

下載dumb-init二進位制檔案,在編譯映象時拷貝到映象中,並且在Dockerfile檔案中新增以下內容:

# 設定可執行許可權
RUN chmod +x /path/to/dumb-init

ENTRYPOINT ["/path/to/dumb-init", "--"]
CMD ["應用的啟動命令"]