我不会起名字322· 后端 / 算法 / 数据库
📘 技术栈 | 🧩 力扣 Hot100 | 🐹 Go 项目 | 🟥 Redis | 🐬 MySQL
文章目录
- 节点 NotReady:kubelet 与容器运行时的 4 步排查
- 一、NotReady 意味着什么
- 二、第 1 步:看 Conditions 定位方向
- 三、第 2 步:到节点上看 kubelet
- 常见错误与含义
- 四、第 3 步:看节点资源
- 五、第 4 步:看网络插件和 CNI
- 六、恢复之后要做什么
- 七、预防比排查重要
- 八、带走物
节点 NotReady:kubelet 与容器运行时的 4 步排查
一、NotReady 意味着什么
节点Ready=False时,控制面会做两件事:
- 自动给节点打上污点
node.kubernetes.io/not-ready:NoSchedule,新 Pod 不再调度上去; - 默认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-A20ConditionsConditions: 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 各有含义:
| Condition | True 意味着 | 常见原因 |
|---|---|---|
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-detector2. 给关键服务配 PodDisruptionBudget,避免节点驱逐时一次性把副本全赶走:
apiVersion:policy/v1kind:PodDisruptionBudgetspec:minAvailable:2selector:matchLabels:app:api3. 监控节点 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;前者告诉你方向,后者告诉你具体原因,两者缺一不可。