ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

节点 NotReady:kubelet 与容器运行时的 4 步排查

节点 NotReady:kubelet 与容器运行时的 4 步排查

我不会起名字322· 后端 / 算法 / 数据库

📘 技术栈 | 🧩 力扣 Hot100 | 🐹 Go 项目 | 🟥 Redis | 🐬 MySQL

文章目录

  • 节点 NotReady:kubelet 与容器运行时的 4 步排查
    • 一、NotReady 意味着什么
    • 二、第 1 步:看 Conditions 定位方向
    • 三、第 2 步:到节点上看 kubelet
      • 常见错误与含义
    • 四、第 3 步:看节点资源
    • 五、第 4 步:看网络插件和 CNI
    • 六、恢复之后要做什么
    • 七、预防比排查重要
    • 八、带走物

节点 NotReady:kubelet 与容器运行时的 4 步排查

一、NotReady 意味着什么

节点Ready=False时,控制面会做两件事:

  1. 自动给节点打上污点node.kubernetes.io/not-ready:NoSchedule,新 Pod 不再调度上去;
  2. 默认5 分钟后(由--pod-eviction-timeout控制)开始驱逐该节点上的 Pod。

所以 NotReady 不是"节点慢",而是节点上的工作负载正在被迁移。这就是为什么一个节点抖动会引发一片 Pod 重启。

kubectl get nodes# NAME STATUS ROLES AGE VERSION# node-3 NotReady <none> 30d v1.28.2

第一步永远是:

kubectl describenodenode-3

看Conditions和Events,那里通常已经写了原因。

二、第 1 步:看 Conditions 定位方向

kubectl describenodenode-3|grep-A20Conditions
Conditions: Type Status LastHeartbeatTime Reason Message ---- ------ ----------------- ------ ------- MemoryPressure False Mon, 13 Oct 2026 00:15:01 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Mon, 13 Oct 2026 00:15:01 KubeletHasNoDiskPressure kubelet has no disk pressure PIDPressure False Mon, 13 Oct 2026 00:15:01 KubeletHasSufficientPID kubelet has sufficient PID available Ready False Mon, 13 Oct 2026 00:12:33 KubeletNotReady container runtime is not ready

四个 Condition 各有含义:

ConditionTrue 意味着常见原因
MemoryPressure可用内存低于阈值节点内存真的不够 / 有 Pod 内存泄漏
DiskPressure剩余磁盘/镜像空间不足容器日志、镜像层、emptyDir 堆积
PIDPressure进程数接近上限某个 Pod 疯起线程
Ready——kubelet 挂了 / 容器运行时挂了 / 网络插件没起来

Ready=False的Reason字段是最直接的线索:

  • KubeletNotReady+container runtime is not ready→容器运行时(containerd/docker)有问题;
  • KubeletNotReady+PLEG is not healthy→PLEG 超时(老版本常见,通常也是运行时卡了);
  • KubeletNotReady+ 无更多说明 → kubelet 进程本身或网络插件问题;
  • 心跳时间(LastHeartbeatTime)停更 →kubelet 挂了或者和 API Server 失联。

三、第 2 步:到节点上看 kubelet

这一步必须 SSH 到节点上,控制面看不到节点内部的状况。

# 1. kubelet 进程活着吗systemctl status kubelet# 2. 看 kubelet 日志(最重要)journalctl-ukubelet-n100--no-pager# 3. 关键错误关键字journalctl-ukubelet-n500--no-pager|grep-iE"error|failed|not ready|PLEG|runtime"

常见错误与含义

错误 1:PLEG is not healthy: pleg was last seen active ... ago

PLEG(Pod Lifecycle Event Generator)负责检测 Pod 状态变化。它超时通常意味着:

  • 容器运行时响应慢(节点负载过高);
  • 节点上运行了太多 Pod;
  • 运行时有 goroutine 卡死。
# 看运行时状态systemctl status containerd journalctl-ucontainerd-n100--no-pager

错误 2:container runtime is not ready

# 检查 containerdsystemctl status containerd ctr version# 老版本用 dockersystemctl statusdockerdockerinfo

错误 3:证书过期

x509: certificate has expired or is not yet valid
# 看 kubelet 客户端证书ls-la/var/lib/kubelet/pki/ openssl x509-in/var/lib/kubelet/pki/kubelet-client-current.pem-noout-dates

错误 4:与 API Server 失联

# 从节点上测试curl-khttps://<apiserver>:6443/healthz

网络插件崩了也会导致这个(Pod 网络不通,kubelet 无法上报)。

四、第 3 步:看节点资源

即使Ready是因为别的原因,资源耗尽的排查也值得单独做:

# 内存free-h# 磁盘(DiskPressure 最常见的原因)df-hdf-i# inode 也可能满# 看谁占了磁盘du-sh/var/lib/containerd/*2>/dev/null|sort-rh|headdu-sh/var/log/pods/*2>/dev/null|sort-rh|head

磁盘是最常见的 NotReady 诱因,三个主要来源:

来源清理方式
容器标准输出日志配 logrotate,或者用emptyDir大小限制
未清理的镜像层crictl rmi --pruned/ 配imageGCHighThresholdPercent
emptyDir / 宿主路径卷堆积查du,清业务数据

kubelet 自带的垃圾回收参数:

--image-gc-high-threshold=85 # 磁盘用到 85% 开始清镜像(默认 85) --image-gc-low-threshold=80 # 清到 80% 停(默认 80)

默认是开启的,但清理有延迟,突发的写盘可能来不及。

另一个高频:inode 耗尽。很多小文件(比如某个应用疯狂写小日志)会把 inode 吃光,df -h看着还有空间但df -i是 100%。

五、第 4 步:看网络插件和 CNI

如果 kubelet 正常、运行时正常、资源也够,但节点还是 NotReady,八成是 CNI。

# 看 CNI 插件的 Pod(以 calico 为例)kubectl get pod-nkube-system-owide|grep-iE"calico|flannel|cilium"# 到节点上看 CNI 配置文件ls/etc/cni/net.d/# 应该是有效的配置,空的或者残留 .conf 都会导致失败# CNI 二进制在不在ls/opt/cni/bin/

常见症状:

  • cni plugin not initialized→ CNI 配置没就绪;
  • CNI Pod 在该节点上 CrashLoop → 网络插件自己挂了;
  • 节点重启后 CNI 配置丢失。

六、恢复之后要做什么

节点恢复 Ready 后,还有几件事:

# 1. 确认污点已自动移除kubectl describenodenode-3|grep-itaint# 2. 确认节点可以调度(不是被 cordon 了)kubectl get nodes|grepSchedulingDisabled kubectl uncordon node-3# 如果是被手动 cordon 的# 3. 看有没有 Pod 卡在 Terminating(节点失联期间常出现)kubectl get pods-A--field-selector=spec.nodeName=node-3|grepTerminating# 4. 强制清理卡住的 Pod(谨慎,确认 Pod 真的已经不在运行)kubectl delete pod<pod>-n<ns>--force--grace-period=0

第 4 步要谨慎:强制删除后,如果容器其实还在某个节点上跑着,会出现"两个同名 Pod 同时运行"的情况,对有状态服务是灾难。先确认容器真的已经停了。

七、预防比排查重要

三条建议:

1. 配node-problem-detector。它能在节点真正 NotReady 之前发现问题(内核死锁、OOM、文件系统损坏等),并打上 Event/污点。

kubectl get pod-nkube-system|grepnode-problem-detector

2. 给关键服务配 PodDisruptionBudget,避免节点驱逐时一次性把副本全赶走:

apiVersion:policy/v1kind:PodDisruptionBudgetspec:minAvailable:2selector:matchLabels:app:api

3. 监控节点 Conditions,别等 Pod 被驱逐了才发现:

kube_node_status_condition{condition="Ready",status="true"} == 0 kube_node_status_condition{condition="MemoryPressure",status="true"} == 1 kube_node_status_condition{condition="DiskPressure",status="true"} == 1

八、带走物

排查顺序:

# 1. 控制面:看 Conditions 和 Reasonkubectl describenode<node>|grep-A20Conditions# 2. 节点:kubelet 活着吗,日志说什么systemctl status kubelet journalctl-ukubelet-n100--no-pager|grep-iE"error|failed|PLEG|runtime"# 3. 节点:是不是资源压力free-h;df-h;df-idu-sh/var/log/pods/*|sort-rh|head# 4. CNI:网络插件正常吗kubectl get pod-nkube-system-owide|grep-iE"calico|flannel|cilium"ls/etc/cni/net.d/

对应处理:

Reason处理
container runtime is not ready重启/修复 containerd;查节点负载
PLEG is not healthy运行时卡了,重启 containerd;节点负载过高要扩容
DiskPressure清日志/镜像层/emptyDir;查 inode
MemoryPressure查内存泄漏的 Pod;或节点规格不够
证书过期续签 kubelet 客户端证书
CNI 未初始化查 CNI 配置和插件 Pod

一句话结论:NotReady 的排查核心是describe node里的Reason字段 + 节点上的journalctl -u kubelet;前者告诉你方向,后者告诉你具体原因,两者缺一不可。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进