K8S線上叢集排查,實測排查Node節點NotReady異常狀態

奮進的小樣發表於2021-02-19

一,文章簡述

大家好,本篇是個人的第 2 篇文章。是關於在之前專案中,k8s 線上叢集中 Node 節點狀態變成 NotReady 狀態,導致整個 Node 節點中容器停止服務後的問題排查。

文章中所描述的是本人在專案中線上環境實際解決的,那除了如何解決該問題,更重要的是如何去排查這個問題的起因。

關於 Node 節點不可用的 NotReady 狀態,當時也是花了挺久的時間去排查的。

二,Pod 狀態

在分析 NotReady 狀態之前,我們首先需要了解在 k8s 中 Pod 的狀態都有哪些。並且每個狀態都表示什麼含義,不同狀態是很直觀的顯示出當前 Pod 所處的建立資訊。

為了避免大家對 Node 和 Pod 的概念混淆,先簡單描述下兩者之間的關係(引用一張 K8S 官方圖)。

K8S線上叢集排查,實測排查Node節點NotReady異常狀態

從圖中很直觀的顯示出最外面就是 Node 節點,而一個 Node 節點中是可以執行多個 Pod 容器,再深入一層就是每個 Pod 容器可以執行多個例項 App 容器。

因此關於本篇文章所闡述的 Node 節點不可用,就會直接導致 Node 節點中所有的容器不可用。

毫無疑問,Node 節點是否健康,直接影響該節點下所有的例項容器的健康狀態,直至影響整個 K8S 叢集。

那麼如何解決並排查 Node 節點的健康狀態?不急,我們先來聊聊關於關於 Pod 的生命週期狀態。

K8S線上叢集排查,實測排查Node節點NotReady異常狀態
  • Pending:該階段表示已經被 Kubernetes 所接受,但是容器還沒有被建立,正在被 kube 進行資源排程。
  • 1:圖中數字 1 是表示在被 kube 資源排程成功後,開始進行容器的建立,但是在這個階段是會出現容器建立失敗的現象
  • Waiting或ContainerCreating:這兩個原因就在於容器建立過程中映象拉取失敗,或者網路錯誤容器的狀態就會發生轉變。
  • Running:該階段表示容器已經正常執行。
  • Failed:Pod 中的容器是以非 0 狀態(非正常)狀態退出的。
  • 2:階段 2 可能出現的狀態為CrashLoopBackOff,表示容器正常啟動但是存在異常退出。
  • Succeeded:Pod 容器成功終止,並且不會再在重啟。

上面的狀態只是 Pod 生命週期中比較常見的狀態,還有一些狀態沒有列舉出來。

這。。。狀態有點多。休息 3 秒鐘

K8S線上叢集排查,實測排查Node節點NotReady異常狀態

不過話又說回來,Pod 的狀態和 Node 狀態是一回事嗎?嗯。。。其實並不完全是一回事。

但是當容器服務不可用時,首先通過 Pod 的狀態去排查是非常重要的。那麼問題來了,如果 Node 節點服務不可用,Pod 還能訪問嗎?

答案是:不能

因此排查Pod的健康狀態的意義就在於,是什麼原因會導致Node節點服務不可用,因此這是一項非常重要的排查指標。

三,業務回顧

由於本人的工作是和物聯網相關的,暫且我們假設 4 臺伺服器(假設不考慮伺服器本身效能問題,如果是這個原因那最好是升級伺服器),其中一臺做 K8S-Master 搭建,另外 3 臺機器做 Worker 工作節點。

K8S線上叢集排查,實測排查Node節點NotReady異常狀態

每個 worker 就是一個 Node 節點,現在需要在 Node 節點上去啟動映象,一切正常 Node 就是ready狀態。

但是過了一段時間後,就成這樣了

這就是我們要說的 Node 節點變成 NotReady 狀態。

四,問題刨析

這跑著跑著就變成 NotReady 了,啥是 NotReady?

K8S線上叢集排查,實測排查Node節點NotReady異常狀態

這都執行一段時間了,你告訴我還沒準備好?

K8S線上叢集排查,實測排查Node節點NotReady異常狀態

好吧,那就看看為什麼還沒準備好。

4.1 問題分析

再回到我們前面說到問題,就是 Node 節點變成 NotReady 狀態後,Pod 容器是否還成正常執行。

圖中用紅框標示的就是在節點edgenode上,此時 Pod 狀態已經顯示為Terminating,表示 Pod 已經終止服務。

接下來我們就分析下 Node 節點為什麼不可用。

(1)首先從伺服器物理環境排查,使用命令df -m檢視磁碟的使用情況

或者直接使用命令free檢視

磁碟並沒有溢位,也就是說物理空間足夠。

(2)接著我們再檢視下 CPU 的使用率,命令為:top -c (大寫P可倒序)

CPU 的使用率也是在範圍內,不管是在物理磁碟空間還是 CPU 效能,都沒有什麼異常。那 Node 節點怎麼就不可用了呢?而且伺服器也是正常執行中。

這似乎就有點為難了,這可咋整?

(3)不慌,還有一項可以作為排查的依據,那就是使用 kube 命令 describe 命令檢視 Node 節點的詳細日誌。完整命令為:

kubectl describe node <節點名稱>,那麼圖中 Node 節點如圖:

哎呀,好像在這個日誌裡面看到了一些資訊描述,首先我們先看第一句:Kubelet stoped posting node status,大致的意思是 Kubelet 停止傳送 node 狀態了,再接著Kubelet never posted node status意思為再也收不到 node 狀態了。

檢視下 Kubelet 是否在正常執行,是使用命令:systemctl status kubelet,如果狀態為 Failed,那麼是需要重啟下的。但如果是正常執行,請繼續向下看。

分析一下好像有點眉目了,Kubelet 為什麼要傳送 node 節點的狀態呢?這就丟擲了關於 Pod 的另一個知識點,請耐心向下看。

五,Pod 健康檢測 PLEG

根據我們最後面分析的情形,似乎是 node 狀態再也沒有收到上報,導致 node 節點不可用,這就引申出關於 Pod 的生命健康週期。

PLEG全稱為:Pod Lifecycle Event Generator:Pod 生命週期事件生成器。

簡單理解就是根據 Pod 事件級別來調整容器執行時的狀態,並將其寫入 Pod 快取中,來保持 Pod 的最新狀態。

在上述圖中,看出是 Kubelet 在檢測 Pod 的健康狀態。Kubelet 是每個節點上的一個守護程式,Kubelet 會定期去檢測 Pod 的健康資訊,先看一張官方圖。

K8S線上叢集排查,實測排查Node節點NotReady異常狀態

PLEG去檢測執行容器的狀態,而 kubelet 是通過輪詢機制去檢測的。

分析到這裡,似乎有點方向了,導致 Node 節點變成 NotReady 狀態是和 Pod 的健康狀態檢測有關係,正是因為超過預設時間了,K8S 叢集將 Node 節點停止服務了。

那為什麼會沒有收到健康狀態上報呢?我們先檢視下在 K8S 中預設檢測的時間是多少。

在叢集伺服器是上,進入目錄:/etc/kubernetes/manifests/kube-controller-manager.yaml,檢視引數:

–node-monitor-grace-period=40s(node驅逐時間)

–node-monitor-period=5s(輪詢間隔時間)

上面兩項參數列示每隔 5 秒 kubelet 去檢測 Pod 的健康狀態,如果在 40 秒後依然沒有檢測到 Pod 的健康狀態便將其置為 NotReady 狀態,5 分鐘後就將節點下所有的 Pod 進行驅逐。

官方文件中對 Pod 驅逐策略進行了簡單的描述,https://kubernetes.io/zh/docs/concepts/scheduling-eviction/eviction-policy/

K8S線上叢集排查,實測排查Node節點NotReady異常狀態

kubelet 輪詢檢測 Pod 的狀態其實是一種很消耗效能的操作,尤其隨著 Pod 容器的數量增加,對效能是一種嚴重的消耗。

在 GitHub 上的一位小哥對此也表示有自己的看法,原文連結為:

https://github.com/fabric8io/kansible/blob/master/vendor/k8s.io/kubernetes/docs/proposals/pod-lifecycle-event-generator.md

到這裡我們分析的也差不多了,得到的結論為:

  • Pod 數量的增加導致 Kubelet 輪詢對伺服器的壓力增大,CPU 資源緊張

  • Kubelet 輪詢去檢測 Pod 的狀態,就勢必受網路的影響

  • Node 節點物理硬體資源限制,無法承載較多的容器

而由於本人當時硬體的限制,及網路環境較差的前提下,所以只改了上面了兩項引數配置,延長 Kubelet 去輪詢檢測 Pod 的健康狀態。實際效果也確實得到了改善。

// 需要重啟docker
sudo systemctl restart docker

// 需要重啟kubelet
sudo systemctl restart kubelet

但是如果條件允許的情況下,個人建議最好是從硬體方面優化。

  • 提高 Node 節點的物理資源
  • 優化 K8S 網路環境

六,K8S 常用命令

最後分享一些常用的 K8S 命令

1,查詢全部 pod(名稱空間)

kubectl get pods -n

2,查詢全部 node 節點

kubectl get nodes

3,檢視 pod 詳細資訊和日誌

kubectl describe pod -n

kubectl logs -f -n

4,檢視 pod-yaml 檔案

kubectl get pod -n -o yaml

5,通過標籤查詢 pod

kubectl get pod -l app= -n

6,查詢 pod 具體某一條資訊

kubectl -n get pods|grep |awk '{print $3}'

7,刪除 pod(或通過標籤 -l app=)

kubectl delete pod -n

8,刪除 deployment

kubectl delete deployment -n

9,強制刪除 pod

kubectl delete pod -n --force --grace-period=0

10,進入 pod 容器

kubectl exec -it -n -- sh

11,給 node 打標籤

kubectl label node app=label

12,檢視某一個 node 標籤

kubectl get node -l ""

13,檢視全部 node 標籤

kubectl get node --show-labels=true

七,總結

關於 Node 節點的 NotReady 狀態當時也是排查了很久,對很多種情況也是猜測,並不能具體確定是什麼原因。

網上關於這方面的內容也不是很多,只能是根據提示一步一步去排查問題的源頭,並加以驗證,最後也是在條件限制下解決了這個問題。

以後的工作也是做 AIOT 相關的,所謂 A 是指 Ai,IOT 指物聯網。也是和 K8S 強相關的內容,後續也還會繼續和大家分享關於 K8S 相關的知識。

如果您也是 K8S 的使用者,或者想接觸學習 K8S,歡迎關注個人公眾號!

最後,求關注


總結辛苦,原創不易!希望一些正能量的支援,求關注,點贊,轉發(一鍵三連)

K8S線上叢集排查,實測排查Node節點NotReady異常狀態

相關文章