日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Kubernetes節(jié)點(diǎn)NotReady怎么排查

馬哥Linux運(yùn)維 ? 來(lái)源:馬哥Linux運(yùn)維 ? 2026-05-11 16:53 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

問(wèn)題背景

生產(chǎn)環(huán)境中 Kubernetes 集群的節(jié)點(diǎn)突然變成NotReady是非常常見(jiàn)的故障場(chǎng)景。節(jié)點(diǎn)一旦進(jìn)入NotReady狀態(tài),該節(jié)點(diǎn)上調(diào)度的 Pod 會(huì)持續(xù)處于Pending或者被驅(qū)逐的狀態(tài),如果集群規(guī)模較小或者副本數(shù)不足,會(huì)直接導(dǎo)致業(yè)務(wù)服務(wù)中斷。NotReady 本身不是根因,只是一個(gè)癥狀表現(xiàn)——它背后的原因可能是kubelet 進(jìn)程崩潰、容器運(yùn)行時(shí)異常、網(wǎng)絡(luò)不通、etcd 連接故障、磁盤空間不足、內(nèi)核問(wèn)題、證書(shū)過(guò)期等等。不同原因?qū)?yīng)的處理方式完全不同,如果不做系統(tǒng)排查,上來(lái)就重啟節(jié)點(diǎn),很可能把現(xiàn)場(chǎng)破壞掉,導(dǎo)致問(wèn)題復(fù)現(xiàn)困難。

這篇文章面向初中級(jí) Kubernetes 運(yùn)維工程師,以一個(gè)真實(shí)的 NotReady 故障為線索,完整走一遍從現(xiàn)象觀察、層層排查、定位根因到修復(fù)驗(yàn)證的全過(guò)程。文章涉及的所有排查命令均在 Kubernetes 1.24 及以上版本驗(yàn)證通過(guò),部分命令在更早版本中表現(xiàn)可能略有差異,文中會(huì)做說(shuō)明。所有涉及破壞性操作(如刪除 Pod、驅(qū)逐節(jié)點(diǎn)、重啟服務(wù))的命令均會(huì)標(biāo)注風(fēng)險(xiǎn)級(jí)別和必要的確認(rèn)步驟。

適用場(chǎng)景

集群中有節(jié)點(diǎn)顯示NotReady狀態(tài)超過(guò) 5 分鐘仍未恢復(fù)

業(yè)務(wù) Pod 被驅(qū)逐,副本數(shù)下降,監(jiān)控告警觸發(fā)

新增節(jié)點(diǎn)加入集群后始終無(wú)法 Ready

節(jié)點(diǎn)運(yùn)行一段時(shí)間后自發(fā)變成 NotReady(而非升級(jí)或維護(hù)導(dǎo)致)

升級(jí) K8s 版本后部分節(jié)點(diǎn) NotReady

集群節(jié)點(diǎn)數(shù)較少(小于 3),單節(jié)點(diǎn) NotReady 已影響核心業(yè)務(wù)

核心知識(shí)點(diǎn):Kubelet 節(jié)點(diǎn)狀態(tài)機(jī)制

理解節(jié)點(diǎn) NotReady 的根因之前,必須先弄清楚 kubelet 是如何向 kube-apiserver 上報(bào)節(jié)點(diǎn)狀態(tài)的。kubelet 會(huì)在每個(gè)nodeStatusReportFrequency周期(默認(rèn) 10 秒)內(nèi)向 API Server 更新節(jié)點(diǎn)狀態(tài)。如果 kubelet 連續(xù)失敗超過(guò)某個(gè)閾值,節(jié)點(diǎn)狀態(tài)就會(huì)被標(biāo)記為Unknown或NotReady。

具體判斷邏輯在 kube-controller-manager 的nodecontroller中:

kubelet 每 10 秒上報(bào)一次節(jié)點(diǎn)狀態(tài)(可通過(guò)--node-status-update-frequency修改,但不要盲目調(diào)大)

nodecontroller 會(huì)在節(jié)點(diǎn)連續(xù) 40 秒未更新時(shí)將狀態(tài)置為Unknown

節(jié)點(diǎn)處于Unknown狀態(tài)超過(guò) 5 分鐘(pod-eviction-timeout,默認(rèn) 5 分鐘)后,RC/Deployment 的 replicas 控制器會(huì)觸發(fā) Pod 驅(qū)逐

如果 kubelet 能恢復(fù),則節(jié)點(diǎn)狀態(tài)恢復(fù)為Ready;如果超過(guò)termination-duration(默認(rèn) 5 分鐘)仍未恢復(fù),節(jié)點(diǎn)會(huì)被徹底標(biāo)記為NotReady

需要注意的是,kubelet 報(bào)告的Ready條件是一個(gè)組合條件,由多個(gè) Condition 組成:

Conditions:
 Type       Status
 MemoryPressure  False
 DiskPressure   False
 PIDPressure   False
 NetworkUnavailable False
 kubeletReady   True  <-- 這個(gè)綜合狀態(tài)由 kubelet 自己計(jì)算

kubeletReady這個(gè) Condition 如果不是True,在 kubectl get node 輸出中就會(huì)顯示NotReady。但實(shí)際上 kubelet 內(nèi)部還會(huì)細(xì)分:它會(huì)檢查容器運(yùn)行時(shí)是否可用、根文件系統(tǒng)是否可寫、節(jié)點(diǎn)網(wǎng)絡(luò)是否配置正確等。任何一個(gè)檢查失敗都可能導(dǎo)致kubeletReady變?yōu)镕alse,從而導(dǎo)致節(jié)點(diǎn) NotReady。

排查路徑總覽

當(dāng)發(fā)現(xiàn)節(jié)點(diǎn) NotReady 時(shí),推薦按以下順序排查,避免走彎路:

1. 確認(rèn) NotReady 現(xiàn)象和受影響范圍
 └── kubectl get node(看節(jié)點(diǎn)狀態(tài)和年齡)
 └── kubectl describe node (看 Reason 和 Condition)

2. 檢查 kubelet 是否在運(yùn)行
 └── systemctl status kubelet
 └── journalctl -u kubelet -n 200 --no-pager

3. 檢查容器運(yùn)行時(shí)是否正常
 └── systemctl status containerd(或 docker)
 └── crictl info / docker info

4. 檢查節(jié)點(diǎn)資源是否耗盡
 └── df -h(磁盤)
 └── free -m(內(nèi)存)
 └── top / uptime(CPU 負(fù)載)

5. 檢查網(wǎng)絡(luò)連通性
 └── ping(api server)
 └── curl -k https:///healthz
 └── hostname -i / ip addr

6. 檢查證書(shū)是否過(guò)期
 └── kubeadm certs check-expiration
 └── openssl x509 -in/var/lib/kubelet/pki/cert.crt -noout -dates

7. 定位根因并修復(fù)

8. 驗(yàn)證恢復(fù)
 └── kubectl get node
 └── 在節(jié)點(diǎn)上跑一個(gè)測(cè)試 Pod

以上順序不是絕對(duì)的,要根據(jù)現(xiàn)場(chǎng)實(shí)際情況靈活調(diào)整。比如磁盤空間不足是最容易快速確認(rèn)的項(xiàng)目,優(yōu)先檢查;如果節(jié)點(diǎn)一開(kāi)始是 Ready 后來(lái)突然 NotReady,則 kubelet 進(jìn)程問(wèn)題概率更大;如果新增節(jié)點(diǎn)始終無(wú)法 Ready,則網(wǎng)絡(luò)配置或 kubelet 啟動(dòng)參數(shù)問(wèn)題概率更大。

第一步:確認(rèn) NotReady 現(xiàn)象和受影響范圍

用 kubectl 連接目標(biāo)集群(如果本地?zé)o法連接集群,可以找一臺(tái)有 kubectl 配置的節(jié)點(diǎn)):

# 查看所有節(jié)點(diǎn)狀態(tài),-o wide 看更多信息
kubectl get nodes -o wide

# 輸出示例:
# NAME     STATUS   ROLES      AGE  VERSION
# k8s-master  Ready   control-plane  45d  v1.28.4
# k8s-node-1  NotReady       30d  v1.28.4
# k8s-node-2  Ready        30d  v1.28.4

如果節(jié)點(diǎn)數(shù)量較多,可以用 grep 過(guò)濾:

kubectl get nodes | grep -v Ready

確認(rèn) NotReady 節(jié)點(diǎn)名稱和數(shù)量后,用 describe 查看詳細(xì)信息:

kubectl describe node k8s-node-1

describe 輸出的最后幾行Conditions是最關(guān)鍵的:

Conditions:
 Type       Status  LastHeartbeatTime         LastTransitionTime        Reason       Message
 ----       ------  -----------------         ------------------        ------       -------
 MemoryPressure  False   2026-04-29T1034Z       2026-04-29T0812Z       KubeletHasSufficientMemory  kubelet has sufficient memory available
 DiskPressure   True   2026-04-29T1034Z       2026-04-29T1000Z       KubeletHasDiskPressure    kubelet has disk pressure; low disk space
 PIDPressure   False   2026-04-29T1034Z       2026-04-29T0812Z       KubeletHasSufficientPID   kubelet has sufficient PID available
 NetworkUnavailable False  2026-04-29T1034Z       2026-04-29T0812Z       RouteCreated        Route created successfully
 kubeletReady   False   2026-04-29T1034Z       2026-04-29T1000Z       KubeletNotReady       kubelet status is (matchNodeConditionMode)

從上面這個(gè)示例可以看到,DiskPressure為True且kubeletReady為False,Message 中明確寫了"low disk space"。這就是根因線索——磁盤空間不足導(dǎo)致 kubelet 認(rèn)為節(jié)點(diǎn)不健康。

但要注意,DiskPressure和kubeletReady是兩個(gè)獨(dú)立的 Condition。kubeletReady為 False 不一定是因?yàn)镈iskPressure,也可能是因?yàn)槿萜鬟\(yùn)行時(shí)無(wú)響應(yīng)、容器網(wǎng)絡(luò)配置錯(cuò)誤等。需要綜合判斷。

再看 Nodes Conditions 中NotReady對(duì)應(yīng)的Reason字段,常見(jiàn)的原因值如下:

Reason 含義 常見(jiàn)根因
KubeletNotReady kubelet 未就緒 kubelet 進(jìn)程崩潰、容器運(yùn)行時(shí)異常、磁盤/內(nèi)存壓力
NodeNotReady 節(jié)點(diǎn)整體不健康 kubelet 完全無(wú)響應(yīng)、證書(shū)過(guò)期、網(wǎng)絡(luò)不通
KubeletHasNoDiskPressure kubelet 認(rèn)為磁盤正常 僅狀態(tài)展示用,不表示問(wèn)題
MemoryPressure 內(nèi)存壓力 節(jié)點(diǎn)內(nèi)存耗盡
NetworkUnavailable 網(wǎng)絡(luò)不可用 CNI 配置錯(cuò)誤、節(jié)點(diǎn)網(wǎng)絡(luò)未正確配置

接下來(lái)按照不同場(chǎng)景分別講解排查步驟。

第二步:檢查 kubelet 進(jìn)程是否正常運(yùn)行

kubelet 是節(jié)點(diǎn)上最核心的 K8s 組件。如果 kubelet 進(jìn)程掛了,節(jié)點(diǎn)狀態(tài)立即就會(huì)變成 NotReady。因此排查的第一步就是確認(rèn) kubelet 進(jìn)程狀態(tài)。

2.1 查看 kubelet 服務(wù)狀態(tài)

# 查看 kubelet 服務(wù)狀態(tài)(systemd 管理方式)
sudo systemctl status kubelet

# 如果是 containerd 運(yùn)行時(shí),可能看到:
# kubelet.service - kubelet: The Kubernetes Node Agent
#  Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled)
#  Active: active (running) since ...
# 或者
#  Active: failed (Result: start-limit-hit) since ...

如果看到Active: failed,說(shuō)明 kubelet 啟動(dòng)失敗了。需要立即查看日志。

2.2 查看 kubelet 日志

# 查看最近 300 行日志,不分頁(yè)直接輸出
sudo journalctl -u kubelet -n 300 --no-pager

# 從頭查看(啟動(dòng)日志)
sudo journalctl -u kubelet --no-pager | head -500

# 查看某個(gè)時(shí)間點(diǎn)之后的日志(結(jié)合故障時(shí)間)
sudo journalctl -u kubelet --since"2026-04-29 0900"--no-pager

# 查看 kubelet 啟動(dòng)失敗的相關(guān)日志
sudo journalctl -u kubelet -b --no-pager | grep -i error

kubelet 日志中最常見(jiàn)的錯(cuò)誤類型和處理方式如下。

錯(cuò)誤類型一:容器運(yùn)行時(shí)連接失敗

Failed to run Kubelet: failed to load Kubelet config file"/var/lib/kubelet/config.yaml":
error adding watch on /var/lib/kubelet/cpu_manager_state": context deadline exceeded

這類錯(cuò)誤通常是 kubelet 啟動(dòng)參數(shù)和容器運(yùn)行時(shí)配置不匹配。如果是 Docker 切換到 containerd,或者升級(jí)了容器運(yùn)行時(shí)版本后出現(xiàn),重點(diǎn)檢查/etc/containerd/config.toml和 kubelet 的--container-runtime-endpoint參數(shù)是否一致。

錯(cuò)誤類型二:證書(shū)相關(guān)

Failed to start kubelet: unable to load client CA file /etc/kubernetes/pki/kubelet-client-latest/current:
open /etc/kubernetes/pki/kubelet-client-latest/current: no such file or directory

證書(shū)文件缺失或不完整,通常發(fā)生在手動(dòng)修改了/etc/kubernetes/目錄之后,或者升級(jí)過(guò)程中證書(shū)沒(méi)有正確續(xù)期。可以用以下命令檢查證書(shū)狀態(tài):

# 檢查 kubelet 證書(shū)是否過(guò)期(需要先 SSH 到目標(biāo)節(jié)點(diǎn))
sudo kubeadm certs check-expiration --cert-dir /etc/kubernetes/pki

# 手動(dòng)檢查某個(gè)具體證書(shū)
sudo openssl x509 -in/var/lib/kubelet/pki/cert.crt -noout -dates

錯(cuò)誤類型三:ETCD 連接超時(shí)

Failed to start kubelet: Post"https://192.168.1.10:2379/vote": net/http: request canceled

說(shuō)明 kubelet 無(wú)法連接到集群的 etcd。可能是網(wǎng)絡(luò)問(wèn)題,也可能是 etcd 本身響應(yīng)慢。如果集群所有節(jié)點(diǎn)同時(shí)出現(xiàn)這個(gè)問(wèn)題,則 etcd 故障的概率更高;如果只有某一個(gè)節(jié)點(diǎn)出現(xiàn),則該節(jié)點(diǎn)的網(wǎng)絡(luò)配置問(wèn)題概率更大。

2.3 手動(dòng)重啟 kubelet

風(fēng)險(xiǎn)提醒:重啟 kubelet 會(huì)導(dǎo)致該節(jié)點(diǎn)上的 Pod 被驅(qū)逐和重新調(diào)度,對(duì)業(yè)務(wù)有影響。生產(chǎn)環(huán)境中執(zhí)行前必須:1)確認(rèn)業(yè)務(wù)副本數(shù)足夠撐過(guò)驅(qū)逐和重新調(diào)度;2)通知相關(guān)業(yè)務(wù)方;3)準(zhǔn)備好回滾方案。

# 先查看節(jié)點(diǎn)上運(yùn)行了哪些 Pod,評(píng)估影響
kubectl get pods -o wide --all-namespaces | grep k8s-node-1

# 確認(rèn)無(wú)誤后,重啟 kubelet
sudo systemctl restart kubelet

# 查看重啟后的狀態(tài)
sudo systemctl status kubelet
sleep 30
kubectl get node k8s-node-1

如果 kubelet 重啟后能正常啟動(dòng),節(jié)點(diǎn)恢復(fù) Ready,則說(shuō)明是臨時(shí)故障(比如 OOM 殺掉了 kubelet)。但這只是治標(biāo),要找到根因,還需要結(jié)合后面的步驟分析日志,判斷是什么導(dǎo)致的 kubelet 崩潰。

第三步:檢查容器運(yùn)行時(shí)是否正常

容器運(yùn)行時(shí)(containerd 或 dockerd)是 kubelet 工作的前提。如果容器運(yùn)行時(shí)異常,kubelet 雖然進(jìn)程在,但無(wú)法創(chuàng)建/管理容器,對(duì)應(yīng)的 Pod 狀態(tài)會(huì)變成ContainerCreating或Error,同時(shí) kubelet 會(huì)認(rèn)為節(jié)點(diǎn)不健康。

3.1 檢查 containerd 服務(wù)狀態(tài)

# 查看 containerd 服務(wù)狀態(tài)
sudo systemctl status containerd

# 查看 containerd 日志
sudo journalctl -u containerd -n 200 --no-pager

# 檢查 containerd 進(jìn)程是否存活
ps aux | grep containerd | grep -v grep

3.2 使用 crictl 檢查容器運(yùn)行時(shí)

crictl 是 containerd 提供的命令行工具,用于直接和 containerd 通信,繞過(guò) kubelet 排查問(wèn)題。

# 檢查 containerd 版本和信息
sudo crictl info

# 如果報(bào)錯(cuò) "runtime endpoint not connected",說(shuō)明 containerd 未正常響應(yīng)

正常情況下,crictl info會(huì)輸出 containerd 的配置信息,包括存儲(chǔ)驅(qū)動(dòng)、網(wǎng)絡(luò)插件等。如果這一步失敗,問(wèn)題很可能在 containerd 本身。

# 查看 containerd 的 socket 文件是否存在
ls -la /run/containerd/containerd.sock
ls -la /var/run/containerd/containerd.sock

socket 文件不存在通常意味著 containerd 進(jìn)程沒(méi)有正常創(chuàng)建 socket,或者 containerd 服務(wù)配置了非默認(rèn)路徑。

3.3 檢查 dockerd 服務(wù)(如果使用 docker 作為運(yùn)行時(shí))

sudo systemctl status docker

# 查看 dockerd 日志
sudo journalctl -u docker -n 200 --no-pager

# 檢查 docker 是否能列出容器(驗(yàn)證 daemon 響應(yīng))
sudo docker ps -a

# 檢查 docker 網(wǎng)絡(luò)驅(qū)動(dòng)是否正常
sudo docker info

docker info輸出中重點(diǎn)關(guān)注以下幾個(gè)字段:

Container runtime: containerd # 確認(rèn)使用的運(yùn)行時(shí)
Storage Driver: overlay2    # 確認(rèn)存儲(chǔ)驅(qū)動(dòng)
Logging Driver: json-file
Cgroup Driver: systemd     # 注意:docker 和 kubelet 的 cgroup driver 必須一致

如果Cgroup Driver顯示cgroupfs而 kubelet 使用的是systemd,就會(huì)導(dǎo)致資源管理不一致,節(jié)點(diǎn)可能出現(xiàn)莫名的內(nèi)存壓力或 CPU 限制失效。

3.4 檢查 crictl 可見(jiàn)的容器和鏡像

# 列出所有容器(包括已停止的)
sudo crictl ps -a

# 列出所有鏡像
sudo crictl images

# 查看運(yùn)行中的容器
sudo crictl ps

如果crictl ps能正常列出容器,但 kubelet 報(bào)告節(jié)點(diǎn) NotReady,說(shuō)明問(wèn)題可能在 kubelet 和容器運(yùn)行時(shí)通信的 endpoint 配置上。這種情況比較少見(jiàn),但容易讓人誤判。

第四步:檢查節(jié)點(diǎn)資源是否耗盡

節(jié)點(diǎn)資源(磁盤、內(nèi)存、CPU)耗盡是導(dǎo)致 NotReady 的最常見(jiàn)原因。kubelet 內(nèi)置了資源壓力檢測(cè),當(dāng)檢測(cè)到節(jié)點(diǎn)資源不足時(shí),會(huì)自動(dòng)設(shè)置對(duì)應(yīng)的 Condition 為 True,同時(shí)降低節(jié)點(diǎn)評(píng)分甚至拒絕調(diào)度新 Pod。

4.1 檢查磁盤空間

# 查看所有掛載點(diǎn)的磁盤使用率,重點(diǎn)關(guān)注 / 和 /var/lib/containerd
df -h

# 輸出示例:
# Filesystem   Size Used Avail Use% Mounted on
# /dev/sda1    100G  95G  5G 95% /    <-- 危險(xiǎn):超過(guò) 90%
# /dev/sdb1 ? ? ? 500G ?200G ?300G ?40% /data
# overlay ? ? ? ? 100G ? 95G ? ?5G ?95% /var/lib/containerd ?<-- 這個(gè)是 containerd 使用的overlay

磁盤使用率超過(guò) 90% 是非常危險(xiǎn)的。kubelet 的DiskPressure檢測(cè)默認(rèn)閾值是:磁盤空間低于 10%(可通過(guò) kubelet 配置--eviction-hard調(diào)整)。當(dāng)磁盤空間不足時(shí):

容器無(wú)法寫入日志(寫入 /var/log 或 stdout)

鏡像無(wú)法解壓加載

kubelet 自身寫cpu_manager_state、memory_manager_state等文件失敗

節(jié)點(diǎn)逐漸失控

風(fēng)險(xiǎn)提醒:不要盲目刪除 /var/lib/containerd/overlay2 下的鏡像文件來(lái)釋放磁盤空間。容器鏡像層存儲(chǔ)在 overlay2 目錄中,手動(dòng)刪除可能導(dǎo)致正在運(yùn)行的容器異常。用ctr -n k8s.io images prune來(lái)清理未使用的鏡像(ctr 是 containerd 自帶的命令行工具),不要用rm -rf直接刪 overlay2 目錄。

清理磁盤空間的正確步驟如下:

# SSH 到目標(biāo)節(jié)點(diǎn)后,先評(píng)估可以清理的空間

# 1. 查看 /var/log 下的日志文件大小
sudo du -sh /var/log/*
sudo find /var/log-name"*.log"-size +100M -execls -lh {} ;

# 2. 查看是否有過(guò)大的 core dump
sudo find /var/lib/systemd/coredump -typef -size +100M 2>/dev/null | xargs ls -lh

# 3. 查看 containerd 鏡像緩存
sudo ctr -n k8s.io images list

# 4. 清理未使用的鏡像(不刪除正在使用的)
sudo ctr -n k8s.io images prune -f

# 5. 清理舊的 journal 日志(保留最近 3 天)
sudo journalctl --vacuum-time=3d

# 6. 清理已停止的容器
sudo crictl rm -f $(sudo crictl ps -a --state EXITED -q)

如果磁盤使用率已經(jīng)超過(guò) 95%,上述清理手段可能不夠,需要臨時(shí)擴(kuò)容或者遷移數(shù)據(jù)。要評(píng)估是哪些目錄占用了最多空間:

# 查看 /var/lib 目錄大小分布
sudo du -sh /var/lib/*

通常/var/lib/containerd和/var/lib/kubelet是最大的兩個(gè)目錄。containerd 存儲(chǔ)鏡像數(shù)據(jù),kubelet 存儲(chǔ) Pod 沙盒數(shù)據(jù)。

4.2 檢查內(nèi)存使用

free -m

# 輸出示例:
#        total    used    free   shared buff/cache  available
# Mem:     32000    28000    4000    2000    8000    2000
# Swap:     8192      0    8192

如果available列的值非常低(低于總內(nèi)存的 10%),說(shuō)明節(jié)點(diǎn)處于內(nèi)存壓力狀態(tài)。Linux 會(huì)使用 buff/cache 作為可用內(nèi)存的一部分,但如果free列持續(xù)為 0 且available也很低,說(shuō)明物理內(nèi)存確實(shí)不夠用了。

查看具體是哪些進(jìn)程消耗了最多內(nèi)存:

# 按內(nèi)存使用排序查看進(jìn)程
ps aux --sort=-%mem | head -20

# 查看 kubelet 進(jìn)程的內(nèi)存使用
ps -p $(pgrep kubelet) -o pid,vsz,rss,comm

如果發(fā)現(xiàn)某個(gè)進(jìn)程(不一定是 kubelet)內(nèi)存占用異常高,比如 Elasticsearch、Java 應(yīng)用等,可以進(jìn)一步分析是該進(jìn)程自身的內(nèi)存泄漏還是配置不合理(比如 JVM 堆內(nèi)存設(shè)置過(guò)大)。但無(wú)論如何,如果節(jié)點(diǎn)的available內(nèi)存持續(xù)很低,即使找到根因,節(jié)點(diǎn)也可能在根因修復(fù)前就已經(jīng) OOM 了。

4.3 檢查 CPU 負(fù)載

# 查看系統(tǒng)負(fù)載和 CPU 使用率
uptime

# 輸出示例:
# 1032 up 45 days, 3:22, 2 users, load average: 8.52, 6.31, 5.12
# 這個(gè)節(jié)點(diǎn)有 8 個(gè) CPU 核心,load average 8.52 意味著 CPU 隊(duì)列長(zhǎng)度為 8.52
# 接近核心數(shù),說(shuō)明 CPU 資源非常緊張

# 查看 CPU 使用詳情
top -bn1 | head -30

load average 是 1分鐘、5分鐘、15分鐘的系統(tǒng)平均負(fù)載。如果 load average 持續(xù)高于 CPU 核心數(shù),說(shuō)明 CPU 資源不足。但 CPU 不足一般不會(huì)直接導(dǎo)致 NotReady(除非導(dǎo)致 kubelet 響應(yīng)超時(shí)),更多是間接影響。直接導(dǎo)致 NotReady 的是 kubelet 進(jìn)程本身被 OOM kill 或者 CPU 饑餓導(dǎo)致無(wú)法正常心跳。

4.4 綜合資源診斷腳本

以下腳本可以快速輸出節(jié)點(diǎn)資源全景,發(fā)現(xiàn)明顯異常:

#!/bin/bash
# save as: node_diag.sh
# 執(zhí)行方式: sudo bash node_diag.sh

echo"===== 節(jié)點(diǎn)基本信息 ====="
uname -r
cat /etc/os-release | grep PRETTY_NAME
echo""

echo"===== CPU 核心數(shù)和負(fù)載 ====="
nproc
uptime
echo""

echo"===== 內(nèi)存使用 ====="
free -m
echo""

echo"===== 磁盤使用 ====="
df -h | grep -v tmpfs | grep -v devtmpfs
echo""

echo"===== 主要進(jìn)程 CPU/MEM 占用 Top 10 ====="
ps aux --sort=-%cpu | awk'NR==1{print} NR>1 && NR<=12'
echo?""

echo?"===== kubelet 進(jìn)程狀態(tài) ====="
systemctl is-active kubelet
systemctl is-failed kubelet 2>/dev/null ||echo"not failed"
echo""

echo"===== containerd/docker 狀態(tài) ====="
systemctl is-active containerd 2>/dev/null ||echo"containerd not active"
systemctl is-active docker 2>/dev/null ||echo"docker not active"
echo""

echo"===== kubelet 日志最新錯(cuò)誤 ====="
journalctl -u kubelet -n 20 --no-pager | grep -i error
echo""

echo"===== inode 使用情況(文件名耗盡也導(dǎo)致磁盤問(wèn)題)====="
df -i | grep -v tmpfs | grep -v devtmpfs

第五步:檢查網(wǎng)絡(luò)連通性

網(wǎng)絡(luò)問(wèn)題也是導(dǎo)致 NotReady 的常見(jiàn)原因。kubelet 需要和 API Server 保持通信,如果網(wǎng)絡(luò)不通,kubelet 的心跳就無(wú)法送達(dá),節(jié)點(diǎn)就會(huì)被標(biāo)記為 NotReady。

5.1 從節(jié)點(diǎn)上測(cè)試到 API Server 的連通性

# 查看 API Server 的 endpoint(需要先從kubectl配置中獲?。?APISERVER=$(kubectl config view --raw -o jsonpath='{.clusters[0].cluster.server}')
echo"API Server:$APISERVER"

# 測(cè)試 HTTPS 連通性(使用內(nèi)置 CA 驗(yàn)證,不驗(yàn)證證書(shū)可以加 -k)
curl -sk --max-time 5${APISERVER}/healthz

# 正常返回: {"status":"OK"}
# 如果報(bào)錯(cuò): Connection refused / Timeout,說(shuō)明網(wǎng)絡(luò)不通

5.2 測(cè)試 DNS 解析

# 查看 kubelet 的 --cluster-dns 配置
grep -r"clusterDNS"/var/lib/kubelet/config.yaml 2>/dev/null ||echo"not in config.yaml"
grep"cluster-dns"/etc/kubernetes/kubelet.conf 2>/dev/null | head -2

# 測(cè)試集群 DNS 是否可達(dá)
ping -c 3 kubernetes.default.svc
ping -c 3 $(grep nameserver /etc/resolv.conf | awk'{print $2}'| head -1)

# 如果 DNS 不通,檢查 CoreDNS 是否在運(yùn)行
kubectl get pods -n kube-system -o wide | grep coredns

5.3 檢查節(jié)點(diǎn)網(wǎng)絡(luò)接口和路由

# 查看網(wǎng)絡(luò)接口配置
ip addr

# 重點(diǎn)關(guān)注:
# 1. 是否有網(wǎng)卡未 UP
# 2. 是否有網(wǎng)卡配置了正確的 IP 和掩碼
# 3. CNI 插件創(chuàng)建的網(wǎng)橋和 veth 設(shè)備是否存在(如 cni0, flannel.1, calico* 等)

# 查看路由表
ip route

# 確認(rèn)是否有到 API Server IP 的路由
ip route | grep $(echo$APISERVER| awk -F/'{print $3}'| awk -F:'{print $1}')

5.4 檢查 CNI 插件狀態(tài)

不同集群使用的 CNI 插件不同(Flannel、Calico、Cilium、Weave 等),檢查方式也不同。

如果是 Flannel:

# 查看 flannel 網(wǎng)卡是否存在
ip addr | grep flannel

# 查看 flannel.1 接口信息
ip addr show flannel.1

# 查看 kube-flannel 的 Pod 日志
kubectl logs -n kube-system -l app=flannel --tail=50

如果是 Calico:

# 查看 calico-node Pod 狀態(tài)
kubectl get pods -n kube-system -l k8s-app=calico-node -o wide

# 查看 calico-node 日志
kubectl logs -n kube-system -l k8s-app=calico-node --tail=50

# 查看 BGP 對(duì)等連接狀態(tài)(需要 calicoctl)
calicoctl node status

# 查看 calico IP 池
calicoctl get ippool -o wide

通用排查方法——查看所有 kube-system Pod 的網(wǎng)絡(luò)相關(guān)組件:

kubectl get pods -n kube-system -o wide | grep -v Running

# 查看所有網(wǎng)絡(luò)相關(guān) Pod
kubectl get pods -n kube-system | grep -E"cni|network|calico|flannel|cilium|weave"

5.5 檢查節(jié)點(diǎn)是否被網(wǎng)絡(luò)策略誤傷

如果集群?jiǎn)⒂昧?NetworkPolicy,而針對(duì)特定命名空間或 Pod 設(shè)置了過(guò)于嚴(yán)格的策略,可能導(dǎo)致 kubelet 和 API Server 通信被阻斷。檢查方法:

# 查看某個(gè)命名空間的 NetworkPolicy
kubectl get networkpolicy -A

# 查看具體的 NetworkPolicy 規(guī)則
kubectl get networkpolicy  -n  -o yaml

不過(guò)這種情況比較罕見(jiàn),因?yàn)?kube-system 命名空間通常不受 NetworkPolicy 影響。更常見(jiàn)的是業(yè)務(wù)命名空間的 Policy 影響了業(yè)務(wù) Pod 和 API Server 的通信,導(dǎo)致 Pod 啟動(dòng)失敗,而不是節(jié)點(diǎn) NotReady。

第六步:檢查證書(shū)是否過(guò)期

kubelet 的證書(shū)默認(rèn)有效期為 1 年(通過(guò) kubeadm 部署的集群)。如果證書(shū)過(guò)期,kubelet 將無(wú)法和 API Server 通信,導(dǎo)致節(jié)點(diǎn) NotReady。這種情況在集群運(yùn)行超過(guò) 1 年后首次出現(xiàn),或者在手動(dòng)調(diào)整過(guò)系統(tǒng)時(shí)間后出現(xiàn)。

6.1 檢查 kubelet 證書(shū)過(guò)期時(shí)間

在 NotReady 節(jié)點(diǎn)上執(zhí)行:

# 用 kubeadm 檢查證書(shū)過(guò)期時(shí)間
sudo kubeadm certs check-expiration --cert-dir /etc/kubernetes/pki

# 如果提示 "certificates signed by unknown authority",說(shuō)明證書(shū)鏈有問(wèn)題
# 重點(diǎn)關(guān)注以下證書(shū)的過(guò)期時(shí)間:
# - kubelet client certificate (/etc/kubernetes/pki/kubelet-client-latest/current)
# - kubelet server certificate (/var/lib/kubelet/pki/cert.crt)

注意:kubeadm certs check-expiration檢查的是/etc/kubernetes/pki/目錄下的控制面證書(shū),而不是 kubelet 自己的證書(shū)。kubelet 的證書(shū)存放在/var/lib/kubelet/pki/。兩個(gè)目錄不要混淆。

6.2 手動(dòng)檢查 kubelet 證書(shū)

# 查看 kubelet 證書(shū)文件
sudo ls -la /var/lib/kubelet/pki/

# 檢查證書(shū)過(guò)期時(shí)間
sudo openssl x509 -in/var/lib/kubelet/pki/cert.crt -noout -dates

# 對(duì)比當(dāng)前時(shí)間
date

如果證書(shū)已過(guò)期或者即將過(guò)期(剩余有效期不足 7 天),需要續(xù)期。

6.3 續(xù)期 kubelet 證書(shū)

風(fēng)險(xiǎn)提醒:續(xù)期證書(shū)需要重啟 kubelet,會(huì)觸發(fā)節(jié)點(diǎn)上的 Pod 重新調(diào)度。生產(chǎn)環(huán)境操作前必須確認(rèn)業(yè)務(wù)副本數(shù)和影響范圍。

# 方式一:通過(guò) kubeadm 續(xù)期(推薦)
# 先備份現(xiàn)有證書(shū)
sudo cp -r /etc/kubernetes/pki /etc/kubernetes/pki.bak.$(date +%Y%m%d)
sudo cp -r /var/lib/kubelet/pki /var/lib/kubelet/pki.bak.$(date +%Y%m%d)

# 續(xù)期 kubelet 證書(shū)(需要 API Server 可達(dá))
sudo kubeadm alpha certs renew kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf

# 方式二:刪除舊證書(shū)讓 kubelet 自動(dòng)重新申請(qǐng)
sudo systemctl stop kubelet
sudo rm -rf /var/lib/kubelet/pki/*
sudo rm -rf /etc/kubernetes/pki/kubelet-client-latest
sudo systemctl start kubelet

方式二會(huì)讓 kubelet 啟動(dòng)時(shí)自動(dòng)向 API Server 申請(qǐng)新的證書(shū),適合緊急情況。方式一更可控,但需要證書(shū)配置正確。

第七步:常見(jiàn)根因場(chǎng)景與修復(fù)方案

通過(guò)以上排查步驟,大多數(shù) NotReady 問(wèn)題可以定位到根因。下面整理常見(jiàn)根因?qū)?yīng)的修復(fù)方案。

場(chǎng)景一:磁盤空間不足(最常見(jiàn))

根因:節(jié)點(diǎn)磁盤被日志、鏡像、臨時(shí)文件填滿,kubelet 檢測(cè)到DiskPressure后將節(jié)點(diǎn)標(biāo)記為 NotReady。

修復(fù)方案

# 1. 確認(rèn)根因
df -h
# 看到 /dev/sda1 使用率 95%+

# 2. 評(píng)估可以清理的內(nèi)容
sudo du -sh /var/lib/containerd/* 2>/dev/null | sort -rh | head -10
sudo du -sh /var/log/* 2>/dev/null | sort -rh | head -10

# 3. 清理未使用鏡像(先查看鏡像列表,評(píng)估哪些可以刪)
sudo crictl images
# 查看未被任何容器使用的鏡像(ctr 命令)
sudo ctr -n k8s.io images list | awk'{print $1":"$2}'| head -20

# 確認(rèn)無(wú)誤后執(zhí)行清理(ctr 是 containerd 自帶的命令行工具)
# 清理所有未被任何容器使用的鏡像
sudo ctr -n k8s.io images prune -f

# 4. 清理舊的 journal 日志
sudo journalctl --vacuum-size=500M

# 5. 驗(yàn)證磁盤空間恢復(fù)
df -h

# 6. 等待 kubelet 重新評(píng)估磁盤狀態(tài)(通常 1-2 分鐘內(nèi)自動(dòng)恢復(fù))
sleep 120
kubectl get node k8s-node-1

如果磁盤使用率是因?yàn)槿萜麋R像本身太大(比如拉取了過(guò)多大型鏡像),需要從鏡像管理入手:設(shè)置鏡像配額、定期清理未使用的鏡像、使用更小的基礎(chǔ)鏡像。

從根源上防止磁盤壓力

# 在 kubelet 配置中設(shè)置 eviction threshold
# 編輯 /var/lib/kubelet/config.yaml 或通過(guò) kubelet 啟動(dòng)參數(shù)

# 示例:設(shè)置更嚴(yán)格的磁盤空間 eviction 閾值(85% 開(kāi)始告警,80% 開(kāi)始驅(qū)逐)
evictionHard:
 imagefs.available:"15%"
 memory.available:"100Mi"
 nodefs.available:"10%"

場(chǎng)景二:kubelet 進(jìn)程 OOM 被 kill

根因:節(jié)點(diǎn)內(nèi)存不足,Linux OOM Killer 殺掉了 kubelet 進(jìn)程。kubelet 進(jìn)程被 kill 后無(wú)法上報(bào)心跳,節(jié)點(diǎn)立即變?yōu)?NotReady。

診斷依據(jù)

# 查看系統(tǒng)日志中的 OOM kill 記錄
sudo dmesg | grep -i"out of memory"
sudo dmesg | grep -i"kubelet"

# 如果 dmesg 輸出被清除(環(huán)形緩沖區(qū)大小有限),查看 systemd journal
sudo journalctl -x | grep -i"memory"| tail -50
sudo journalctl -xb | grep -i"oom"| tail -20

如果看到類似如下記錄:

[12345.678901] kubelet invoked oom-killer: gfp_mask=0x6200x2502ca, order=0, oom_score_adj=999
[12345.678902] Memory cgroup out of memory: Killed process 12345 (kubelet)

說(shuō)明 kubelet 確實(shí)被 OOM Killer 殺掉了。

修復(fù)方案

先恢復(fù)內(nèi)存:清理內(nèi)存占用高的進(jìn)程(不重要的業(yè)務(wù) Pod),騰出空間

設(shè)置 kubelet 的 OOM Score Adj 為負(fù)數(shù),讓 kubelet 更不容易被 kill

# 查看 kubelet 進(jìn)程當(dāng)前的 oom_score_adj
cat /proc/$(pgrep kubelet)/oom_score_adj
# 默認(rèn)值通常是 0 或負(fù)數(shù)(如 -999)

# 如果需要調(diào)整(在 systemd service 文件中添加)
# 編輯 /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
# 在 [Service] 段添加:
Environment="KUBELET_OPTS=--oom-score-adj=-999"

根本解決:增加節(jié)點(diǎn)內(nèi)存或減少節(jié)點(diǎn)上部署的 Pod 數(shù)量??梢圆榭垂?jié)點(diǎn)上當(dāng)前的 Pod 數(shù)量和內(nèi)存請(qǐng)求:

kubectl get pods -o json --all-namespaces | jq'[.items[].spec.containers[].resources.requests.memory // "0Mi" | gsub("Ki";"") | gsub("Mi";"") | tonumber] | add'

場(chǎng)景三:容器運(yùn)行時(shí)配置變更后無(wú)法通信

根因:修改了/etc/containerd/config.toml后沒(méi)有重啟 containerd,或者 containerd 和 kubelet 的 cgroup driver 配置不一致。

診斷依據(jù)

# 查看 kubelet 的 container runtime endpoint
grep container-runtime /var/lib/kubelet/config.yaml

# 查看 containerd 的 cgroup driver 配置
grep SystemdCgroup /etc/containerd/config.toml

# 對(duì)比兩者是否一致
# containerd config.toml 中: SystemdCgroup = true
# kubelet config.yaml 中: cgroupDriver: systemd
# 兩者必須匹配,否則 kubelet 無(wú)法管理容器

修復(fù)方案

# 1. 檢查配置一致性
grep -i"SystemdCgroup"/etc/containerd/config.toml
grep -i"cgroupDriver"/var/lib/kubelet/config.yaml

# 2. 如果不一致,修改 containerd 配置
# 編輯 /etc/containerd/config.toml
# 確保 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
# 段中有: SystemdCgroup = true

# 3. 重啟 containerd
sudo systemctl restart containerd

# 4. 重啟 kubelet
sudo systemctl restart kubelet

# 5. 等待恢復(fù)
sleep 60
kubectl get node k8s-node-1

風(fēng)險(xiǎn)提醒:重啟 containerd 會(huì)導(dǎo)致節(jié)點(diǎn)上所有容器停止并重新創(chuàng)建。對(duì)有狀態(tài)應(yīng)用(MySQL、Redis)和敏感業(yè)務(wù)有嚴(yán)重影響,必須在業(yè)務(wù)方確認(rèn)后執(zhí)行。

場(chǎng)景四:節(jié)點(diǎn)內(nèi)核問(wèn)題導(dǎo)致網(wǎng)絡(luò)或存儲(chǔ)異常

根因:內(nèi)核版本過(guò)舊或存在已知的 BUG,導(dǎo)致某些 K8s 功能不正常。例如內(nèi)核 5.x 之前的版本對(duì) overlay2 文件系統(tǒng)支持不完善,或者某些內(nèi)核版本對(duì) cgroup v2 支持有問(wèn)題。

診斷依據(jù)

# 查看內(nèi)核版本
uname -r
# 查看操作系統(tǒng)版本
cat /etc/os-release

# 查看內(nèi)核日志中是否有硬件或文件系統(tǒng)錯(cuò)誤
sudo dmesg -T | grep -iE"error|warn|fail|timeout|offline"| tail -50

# 查看是否有文件系統(tǒng)只讀的錯(cuò)誤
sudo dmesg -T | grep -i"readonly"

修復(fù)方案:升級(jí)內(nèi)核或重裝節(jié)點(diǎn)。如果內(nèi)核問(wèn)題導(dǎo)致根文件系統(tǒng)變成只讀,必須立即重啟節(jié)點(diǎn),但要做好 Pod 驅(qū)逐和業(yè)務(wù)切換的準(zhǔn)備。

# 查看當(dāng)前內(nèi)核相關(guān)參數(shù)
sysctl -a | grep -i"bridge|netfilter|forward"| head -20

# 檢查 br_netfilter 模塊是否加載
lsmod | grep br_netfilter

場(chǎng)景五:kubelet 配置文件錯(cuò)誤

根因:手動(dòng)修改了/var/lib/kubelet/config.yaml或 kubelet 啟動(dòng)參數(shù),導(dǎo)致 kubelet 啟動(dòng)失敗。

診斷依據(jù)

# 查看 kubelet 的完整啟動(dòng)命令
ps aux | grep kubelet | grep -v grep

# 查看 kubelet 配置文件
cat /var/lib/kubelet/config.yaml

# 嘗試手動(dòng)啟動(dòng) kubelet 看報(bào)錯(cuò)
sudo /usr/bin/kubelet --config=/var/lib/kubelet/config.yaml --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf

常見(jiàn)配置文件錯(cuò)誤

cgroupDriver值和容器運(yùn)行時(shí)不一致

evictionHard配置格式錯(cuò)誤(缺少引號(hào)、格式不對(duì))

containerLogMaxSize和containerLogMaxFiles格式不對(duì)

serializeImagePulls值寫成了字符串而不是布爾值

場(chǎng)景六:etcd 連接超時(shí)(影響所有節(jié)點(diǎn))

根因:etcd 是 K8s 的狀態(tài)存儲(chǔ)后端,如果 etcd 響應(yīng)慢或不可達(dá),所有節(jié)點(diǎn)的 kubelet 心跳都無(wú)法處理,節(jié)點(diǎn)會(huì)陸續(xù)變成 NotReady。

診斷依據(jù)

# 在任意節(jié)點(diǎn)測(cè)試 etcd 連通性
ETCD_ENDPOINT=$(kubectl get endpoints kube-apiserver -n default -o jsonpath='{.subsets[0].addresses[0].targetRef.name}')
ETCD_POD_NAME=$(kubectl get pods -n kube-system -l component=etcd -o jsonpath='{.items[0].metadata.name}')

# 測(cè)試 etcd 健康狀態(tài)
kubectlexec-n kube-system${ETCD_POD_NAME}-- etcdctl --cert=/etc/kubernetes/pki/etcd/server.crt --cacert=/etc/kubernetes/pki/etcd/ca.crt --key=/etc/kubernetes/pki/etcd/server.key endpoint health

# 查看 etcd pod 是否 Running
kubectl get pods -n kube-system -l component=etcd -o wide

修復(fù)方案:如果 etcd 故障,需要優(yōu)先恢復(fù) etcd 集群。etcd 恢復(fù)是另一個(gè)大話題,這里不展開(kāi),但需要知道:etcd 故障導(dǎo)致的 NotReady,節(jié)點(diǎn)本身沒(méi)問(wèn)題,重啟 etcd 后節(jié)點(diǎn)會(huì)自動(dòng)恢復(fù)。

第八步:驗(yàn)證修復(fù)結(jié)果

修復(fù)完成后,必須驗(yàn)證節(jié)點(diǎn)確實(shí)恢復(fù)到 Ready 狀態(tài),并且業(yè)務(wù)恢復(fù)正常。

8.1 節(jié)點(diǎn)狀態(tài)驗(yàn)證

# 查看節(jié)點(diǎn)狀態(tài),等待所有節(jié)點(diǎn)變?yōu)?Ready
kubectl get nodes -o wide

# 查看節(jié)點(diǎn)的 Conditions,確認(rèn)所有狀態(tài)為 False 或 True(如 DiskPressure=False)
kubectl describe node k8s-node-1 | grep -A 20"Conditions"

# 如果節(jié)點(diǎn)狀態(tài)是 Ready 但某些 Condition 仍為 True,說(shuō)明 kubelet 已恢復(fù)但資源壓力未完全解除

8.2 Pod 調(diào)度驗(yàn)證

# 查看 NotReady 節(jié)點(diǎn)上之前的 Pod 是否已經(jīng)重新調(diào)度并運(yùn)行
kubectl get pods -o wide --all-namespaces | grep k8s-node-1

# 查看是否有 Pod 處于 Pending、ContainerCreating、CrashLoopBackOff 等異常狀態(tài)
kubectl get pods --all-namespaces | grep -v Running | grep -v Completed

# 如果有異常 Pod,分析原因
kubectl describe pod  -n 
kubectl logs  -n  --previous

8.3 業(yè)務(wù)功能驗(yàn)證

# 查看業(yè)務(wù)相關(guān)的 Deployment replicas 是否滿足預(yù)期
kubectl get deployment -A

# 查看 Services 是否正常
kubectl get svc -A

# 如果有 Ingress,測(cè)試 Ingress 訪問(wèn)
curl -sk https:/// -w"
%{http_code}
"

# 測(cè)試 DNS 解析
kubectl run dnsutils --image=tbuskey/dnsutils:1.0 --restart=Never -it --rm -- sh
# 在容器內(nèi)執(zhí)行:nslookup kubernetes.default

8.4 節(jié)點(diǎn)資源驗(yàn)證

# 在節(jié)點(diǎn)上執(zhí)行最終資源檢查
ssh k8s-node-1"df -h / && free -m && uptime"

# 確認(rèn)磁盤空間已釋放到安全范圍
# 確認(rèn)內(nèi)存使用恢復(fù)正常
# 確認(rèn)負(fù)載回到正常水平

第九步:預(yù)防措施和日常巡檢

故障修復(fù)后,更重要的是建立長(zhǎng)效機(jī)制,避免同類問(wèn)題反復(fù)發(fā)生。

9.1 建立節(jié)點(diǎn)健康巡檢機(jī)制

推薦每日?qǐng)?zhí)行一次節(jié)點(diǎn)健康檢查,可以通過(guò) Ansible、Prometheus 告警或定時(shí)腳本來(lái)實(shí)現(xiàn):

#!/bin/bash
# save as: k8s_node_health_check.sh
# 建議通過(guò) cron 每日?qǐng)?zhí)行,結(jié)果寫入日志文件

NODES=$(kubectl get nodes -o jsonpath='{.items[*].metadata.name}')
ALERT_MSG=""

forNODEin$NODES;do
# 檢查節(jié)點(diǎn)狀態(tài)
 STATUS=$(kubectl get node$NODE-o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
if["$STATUS"!="True"];then
  ALERT_MSG="${ALERT_MSG}
[node NotReady]$NODE"
  kubectl describe node$NODE| grep -A 5"Conditions">> /var/log/k8s-health.log
fi

# 檢查磁盤使用率(閾值 85%)
 DISK_USAGE=$(ssh$NODE"df -h / | tail -1 | awk '{print $5}' | sed 's/%//'")
if["$DISK_USAGE"-gt 85 ];then
  ALERT_MSG="${ALERT_MSG}
[disk pressure]$NODE:${DISK_USAGE}%"
fi

# 檢查內(nèi)存使用率(閾值 90%)
 MEM_AVAILABLE=$(ssh$NODE"free -m | tail -2 | head -1 | awk '{print $7}'")
 MEM_TOTAL=$(ssh$NODE"free -m | tail -2 | head -1 | awk '{print $2}'")
 MEM_USAGE=$(( (MEM_TOTAL - MEM_AVAILABLE) * 100 / MEM_TOTAL ))
if["$MEM_USAGE"-gt 90 ];then
  ALERT_MSG="${ALERT_MSG}
[memory pressure]$NODE:${MEM_USAGE}%"
fi

# 檢查 kubelet 和容器運(yùn)行時(shí)狀態(tài)
 KUBELET_ACTIVE=$(ssh$NODE"systemctl is-active kubelet")
 CONTAINERD_ACTIVE=$(ssh$NODE"systemctl is-active containerd 2>/dev/null"||echo"unknown")
if["$KUBELET_ACTIVE"!="active"];then
  ALERT_MSG="${ALERT_MSG}
[kubelet down]$NODE:$KUBELET_ACTIVE"
fi
done

if[ -n"$ALERT_MSG"];then
echo-e"K8s Node Health Alert:$ALERT_MSG"| tee -a /var/log/k8s-health.log
# 這里可以接入告警系統(tǒng)(如釘釘、企業(yè)微信、飛書(shū)、郵件等)
else
echo"$(date): All nodes healthy">> /var/log/k8s-health.log
fi

9.2 合理配置 kubelet eviction threshold

不要使用默認(rèn)的 eviction threshold,因?yàn)槟J(rèn)值比較激進(jìn),可能在磁盤空間稍微不足時(shí)就觸發(fā) NotReady。建議根據(jù)實(shí)際業(yè)務(wù)負(fù)載調(diào)整:

# /var/lib/kubelet/config.yaml
apiVersion:kubelet.config.k8s.io/v1beta1
kind:KubeletConfiguration
# evictionHard: 不夠用時(shí)直接驅(qū)逐,不給緩沖
evictionHard:
memory.available:"100Mi"   # 內(nèi)存低于 100Mi 時(shí)才觸發(fā) eviction
nodefs.available:"5%"     # 磁盤空間低于 5% 時(shí)觸發(fā)(保守設(shè)置)
imagefs.available:"10%"    # 鏡像存儲(chǔ)低于 10% 時(shí)觸發(fā)
# evictionSoft: 軟閾值,觸發(fā)告警但不立即驅(qū)逐,給運(yùn)維人員響應(yīng)時(shí)間
evictionSoft:
memory.available:"200Mi"
nodefs.available:"10%"
imagefs.available:"15%"
evictionSoftGracePeriod:
memory.available:"2m"
nodefs.available:"2m"
imagefs.available:"2m"
# evictionPressureTransitionPeriod: 進(jìn)入壓力狀態(tài)后,等待這段時(shí)間再?zèng)Q定是否開(kāi)始驅(qū)逐
evictionPressureTransitionPeriod:"2m"

9.3 部署節(jié)點(diǎn)資源監(jiān)控告警

使用 Prometheus Node Exporter 配合 AlertManager,可以對(duì)節(jié)點(diǎn)資源問(wèn)題做到提前發(fā)現(xiàn):

# PrometheusRule 示例:節(jié)點(diǎn)磁盤空間告警
apiVersion:monitoring.coreos.com/v1
kind:PrometheusRule
metadata:
name:node-disk-alerts
namespace:monitoring
spec:
groups:
-name:node-resources
 rules:
 -alert:NodeDiskPressure
  expr:node_filesystem_avail_bytes{mountpoint="/"}/node_filesystem_size_bytes{mountpoint="/"}

9.4 證書(shū)自動(dòng)續(xù)期

通過(guò) kubeadm 部署的集群,kubelet 證書(shū)會(huì)在過(guò)期前自動(dòng)續(xù)期(kubelet 使用的是 bootstrap 機(jī)制)。但如果手動(dòng)管理證書(shū),需要建立定時(shí)任務(wù):

# 在所有 master 節(jié)點(diǎn)上創(chuàng)建 cronjob 每月檢查一次證書(shū)
# 添加到 crontab: 0 3 1 * * /usr/bin/kubeadm certs renew all --kubeconfig=/etc/kubernetes/admin.conf

9.5 節(jié)點(diǎn)資源限制

在生產(chǎn)環(huán)境中,建議對(duì)每個(gè)節(jié)點(diǎn)的 Pod 數(shù)量和資源使用設(shè)置硬限制,防止單節(jié)點(diǎn)過(guò)載:

# 查看節(jié)點(diǎn)最大 Pod 數(shù)量配置(kubelet --max-pods 參數(shù),默認(rèn) 110)
ps aux | grep kubelet | grep max-pods

# 推薦在 /var/lib/kubelet/config.yaml 中設(shè)置:
maxPods: 110

總結(jié)

Kubernetes 節(jié)點(diǎn) NotReady 故障的排查,核心在于理解 kubelet 是如何向 API Server 報(bào)告節(jié)點(diǎn)狀態(tài)的,以及哪些系統(tǒng)級(jí)問(wèn)題會(huì)導(dǎo)致 kubelet 無(wú)法正常工作。

標(biāo)準(zhǔn)排查流程回顧

kubectl describe node:看 Conditions,判斷是哪種壓力(磁盤、內(nèi)存、網(wǎng)絡(luò)、PID)

systemctl status kubelet:確認(rèn) kubelet 進(jìn)程是否存活

journalctl -u kubelet:看 kubelet 日志,找啟動(dòng)失敗或異常退出的原因

df -h / free -m / uptime:檢查磁盤、內(nèi)存、CPU 資源

crictl info / docker info:驗(yàn)證容器運(yùn)行時(shí)是否正常

ping / curl api-server:驗(yàn)證節(jié)點(diǎn)網(wǎng)絡(luò)和 API Server 連通性

kubeadm certs check-expiration / openssl x509:檢查證書(shū)是否過(guò)期

crictl ps -a / kubectl get pods:看節(jié)點(diǎn)上的 Pod 狀態(tài),輔助判斷

最常見(jiàn)的三個(gè)根因

磁盤空間不足(占比最高):日志/鏡像/臨時(shí)文件占滿磁盤,kubelet 檢測(cè)到 DiskPressure

kubelet OOM 被 kill(占比第二):節(jié)點(diǎn)內(nèi)存不足,OOM Killer 優(yōu)先殺掉 kubelet

容器運(yùn)行時(shí)配置不一致(升級(jí)后常見(jiàn)):containerd 和 kubelet 的 cgroup driver 配置不匹配

修復(fù)后必須驗(yàn)證

節(jié)點(diǎn)狀態(tài)恢復(fù) Ready

原有 Pod 重新調(diào)度并 Running

業(yè)務(wù)功能正常

資源使用回到安全范圍

長(zhǎng)期預(yù)防

建立每日節(jié)點(diǎn)健康巡檢

合理配置 eviction threshold(不要全用默認(rèn))

部署 Prometheus 監(jiān)控和告警,提前發(fā)現(xiàn)資源問(wèn)題

證書(shū)到期前自動(dòng)續(xù)期

控制單節(jié)點(diǎn) Pod 數(shù)量和資源請(qǐng)求/限制

遇到 NotReady 問(wèn)題時(shí),保持冷靜,按順序排查,不要急于重啟節(jié)點(diǎn)。重啟節(jié)點(diǎn)會(huì)清除現(xiàn)場(chǎng),讓很多根因信息丟失。先查日志、再查資源、最后再?zèng)Q定是否重啟?,F(xiàn)場(chǎng)保留得越完整,定位根因就越快,下次預(yù)防也就越有針對(duì)性。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 節(jié)點(diǎn)
    +關(guān)注

    關(guān)注

    0

    文章

    231

    瀏覽量

    25686
  • 集群
    +關(guān)注

    關(guān)注

    0

    文章

    155

    瀏覽量

    17696
  • kubernetes
    +關(guān)注

    關(guān)注

    0

    文章

    277

    瀏覽量

    9539

原文標(biāo)題:Kubernetes 節(jié)點(diǎn) NotReady 怎么排查?從現(xiàn)象到根因的完整排查流程

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    Kubernetes架構(gòu)和核心組件組成 Kubernetes節(jié)點(diǎn)“容器運(yùn)行時(shí)”技術(shù)分析

    Kubernetes 架構(gòu)簡(jiǎn)介 Kubernetes架構(gòu)如下圖所示: 在這張系統(tǒng)架構(gòu)圖中,我們把服務(wù)分為運(yùn)行在工作節(jié)點(diǎn)上的服務(wù)和組成集群級(jí)別控制板的服務(wù)。Kubernetes
    的頭像 發(fā)表于 09-25 15:53 ?4527次閱讀
    <b class='flag-5'>Kubernetes</b>架構(gòu)和核心組件組成 <b class='flag-5'>Kubernetes</b><b class='flag-5'>節(jié)點(diǎn)</b>“容器運(yùn)行時(shí)”技術(shù)分析

    Kubernetes 網(wǎng)絡(luò)模型如何實(shí)現(xiàn)常見(jiàn)網(wǎng)絡(luò)任務(wù)

    Kubernetes 是為運(yùn)行分布式集群而建立的,分布式系統(tǒng)的本質(zhì)使得網(wǎng)絡(luò)成為 Kubernetes 的核心和必要組成部分,了解 Kubernetes 網(wǎng)絡(luò)模型可以使你能夠正確運(yùn)行、監(jiān)控和排查
    的頭像 發(fā)表于 10-08 11:32 ?1821次閱讀

    Kubernetes的Device Plugin設(shè)計(jì)解讀

    至工作節(jié)點(diǎn),到設(shè)備與容器的實(shí)際綁定。首先思考的第一個(gè)問(wèn)題是為什么進(jìn)入alpha.kubernetes.io/nvidia-gpu主干一年之久的GPU功能徹底移除?OutOfTree
    發(fā)表于 03-12 16:23

    Kubernetes Ingress 高可靠部署最佳實(shí)踐

    Kubernetes集群中部署高可靠Ingress接入層同樣采用多節(jié)點(diǎn)部署架構(gòu),同時(shí)由于Ingress作為集群流量接入口,建議采用獨(dú)占Ingress節(jié)點(diǎn)的方式,以避免業(yè)務(wù)應(yīng)用與Ingress服務(wù)發(fā)生
    發(fā)表于 04-17 14:35

    Kubernetes網(wǎng)絡(luò)隔離NetworkPolicy實(shí)驗(yàn)

    Kubernetes的一個(gè)重要特性就是要把不同node節(jié)點(diǎn)的pod(container)連接起來(lái),無(wú)視物理節(jié)點(diǎn)的限制。但是在某些應(yīng)用環(huán)境中,比如公有云,不同租戶的pod不應(yīng)該互通,這個(gè)時(shí)候就需要網(wǎng)絡(luò)
    發(fā)表于 11-28 10:00 ?2961次閱讀

    在Windows 10上創(chuàng)建單節(jié)點(diǎn)Kubernetes實(shí)施示例

    Kubernetes使開(kāi)發(fā)人員和系統(tǒng)管理員可以快速部署應(yīng)用程序并將其擴(kuò)展到其需求,而無(wú)需停機(jī)。Kubernetes系統(tǒng)是高度可配置的,幾乎所有內(nèi)容都圍繞四個(gè)重要概念:節(jié)點(diǎn),pod,部署和服務(wù)。
    的頭像 發(fā)表于 05-05 21:01 ?2368次閱讀
    在Windows 10上創(chuàng)建單<b class='flag-5'>節(jié)點(diǎn)</b>的<b class='flag-5'>Kubernetes</b>實(shí)施示例

    深入研究Kubernetes調(diào)度

    “本文從 Pod 和節(jié)點(diǎn)的配置開(kāi)始,介紹了 Kubernetes Scheduler 框架、擴(kuò)展點(diǎn)、API 以及可能發(fā)生的與資源相關(guān)的瓶頸,并展示了性能調(diào)整設(shè)置,涵蓋了 Kubernetes 中調(diào)度
    的頭像 發(fā)表于 08-23 10:39 ?2067次閱讀

    Kubernetes網(wǎng)絡(luò)模型介紹以及如何實(shí)現(xiàn)常見(jiàn)網(wǎng)絡(luò)任務(wù)

    Kubernetes 是為運(yùn)行分布式集群而建立的,分布式系統(tǒng)的本質(zhì)使得網(wǎng)絡(luò)成為 Kubernetes 的核心和必要組成部分,了解 Kubernetes 網(wǎng)絡(luò)模型可以使你能夠正確運(yùn)行、監(jiān)控和排查
    的頭像 發(fā)表于 05-05 20:22 ?2623次閱讀

    Kubernetes網(wǎng)絡(luò)模型的基礎(chǔ)知識(shí)

    Kubernetes 是為運(yùn)行分布式集群而建立的,分布式系統(tǒng)的本質(zhì)使得網(wǎng)絡(luò)成為 Kubernetes 的核心和必要組成部分,了解 Kubernetes 網(wǎng)絡(luò)模型可以使你能夠正確運(yùn)行、監(jiān)控和排查
    的頭像 發(fā)表于 07-20 09:46 ?2050次閱讀

    Kubernetes集群發(fā)生網(wǎng)絡(luò)異常時(shí)如何排查

    本文將引入一個(gè)思路:“在 Kubernetes 集群發(fā)生網(wǎng)絡(luò)異常時(shí)如何排查”。文章將引入 Kubernetes 集群中網(wǎng)絡(luò)排查的思路,包含網(wǎng)絡(luò)異常模型,常用工具,并且提出一些案例以供學(xué)
    的頭像 發(fā)表于 09-02 09:45 ?9897次閱讀

    帶你快速了解 kubernetes

    節(jié)點(diǎn),負(fù)責(zé)控制整個(gè) kubernetes 集群。它包括 Api Server、Scheduler、Controller 等組成部分。它們都需要和 Etcd 進(jìn)行交互以存儲(chǔ)數(shù)據(jù)。 Api Server:
    的頭像 發(fā)表于 01-17 10:00 ?3692次閱讀

    Kubernetes的集群部署

    Kubeadm是一種Kubernetes集群部署工具,通過(guò)kubeadm init命令創(chuàng)建master節(jié)點(diǎn),通過(guò) kubeadm join命令把node節(jié)點(diǎn)加入到集群中
    的頭像 發(fā)表于 02-15 10:35 ?2883次閱讀

    Kubernetes集群中如何選擇工作節(jié)點(diǎn)

    簡(jiǎn)要概述: 本文討論了在Kubernetes集群中選擇較少數(shù)量的較大節(jié)點(diǎn)和選擇較多數(shù)量的較小節(jié)點(diǎn)之間的利弊。
    的頭像 發(fā)表于 08-28 15:46 ?1463次閱讀
    <b class='flag-5'>Kubernetes</b>集群中如何選擇工作<b class='flag-5'>節(jié)點(diǎn)</b>

    Kubernetes故障排查手冊(cè)

    K8s集群出故障是常態(tài)。Pod起不來(lái)、Service訪問(wèn)不通、節(jié)點(diǎn)NotReady、證書(shū)過(guò)期、etcd磁盤滿——每一個(gè)問(wèn)題都可能導(dǎo)致業(yè)務(wù)中斷。和傳統(tǒng)運(yùn)維不同,K8s的故障鏈路更長(zhǎng):一個(gè)請(qǐng)求從
    的頭像 發(fā)表于 02-26 09:47 ?345次閱讀

    K8s服務(wù)訪問(wèn)不通的排查方法

    Kubernetes 里服務(wù)訪問(wèn)不通是比節(jié)點(diǎn) NotReady 更常見(jiàn)的故障場(chǎng)景。相比節(jié)點(diǎn) NotReady 這種基礎(chǔ)設(shè)施層的問(wèn)題,服務(wù)訪問(wèn)
    的頭像 發(fā)表于 05-11 16:49 ?113次閱讀
    辽阳市| 盘山县| 龙江县| 广东省| 东城区| 湾仔区| 华亭县| 科尔| 东乡| 吉首市| 河北省| 屏南县| 海门市| 崇明县| 西乌珠穆沁旗| 沙坪坝区| 五寨县| 钦州市| 镇雄县| 江都市| 西林县| 宜兰市| 嘉峪关市| 方正县| 彝良县| 兰考县| 桓仁| 昌宁县| 黄梅县| 措美县| 渝中区| 张家界市| 河曲县| 盐城市| 台中市| 南江县| 彰化市| 龙山县| 高唐县| 扎兰屯市| 客服|