Kubernetes节点NotReady深度排查从文件系统异常到CNI插件故障链分析当你发现Kubernetes集群中的节点突然集体罢工状态全部显示为NotReady时那种感觉就像走进了一个没有出口的迷宫。最近我在维护一个生产环境集群时就遇到了这种情况——四个节点同时罢工表面报错是invalid capacity 0 on image filesystem但深入排查后发现这仅仅是冰山一角。本文将带你完整还原这次故障排查的全过程揭示Kubernetes组件间那些不为人知的依赖关系。1. 故障现象与初步诊断那天早上监控系统突然报警显示集群所有节点状态变为NotReady。使用kubectl get nodes命令确认后输出如下NAME STATUS ROLES AGE VERSION sealos-k8s-node-01 NotReady control-plane,master 4m5s v1.22.0 sealos-k8s-node-02 NotReady none 2m39s v1.22.0 sealos-k8s-node-03 NotReady none 2m40s v1.22.0 sealos-k8s-node-04 NotReady control-plane,master 3m33s v1.22.0查看kubelet日志发现了两个看似不相关的错误journalctl -xe -u kubelet | grep -i error输出显示May 18 13:47:56 node-04 kubelet[5038]: E0518 13:47:56.386059 5038 kubelet.go:2332] Container runtime network not ready networkReadyNetworkReadyfalse reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized May 18 13:47:56 node-04 kubelet[5038]: E0518 13:47:56.386123 5038 kubelet.go:1303] Image garbage collection failed once. Stats initialization may not have completed yet errinvalid capacity 0 on image filesystem这两个错误中invalid capacity 0 on image filesystem看起来像是存储问题而cni plugin not initialized则明显是网络问题。它们之间是否存在关联这成为了我们排查的第一个关键点。2. 镜像文件系统容量异常分析invalid capacity 0 on image filesystem这个错误通常意味着kubelet无法正确获取节点上容器镜像文件系统的容量信息。这会影响kubelet的垃圾回收功能但理论上不应该直接导致节点NotReady。让我们深入分析可能的原因2.1 可能的原因排查文件系统挂载问题检查/var/lib/kubelet和/var/lib/containerd的挂载状态使用df -h查看相关挂载点的可用空间containerd服务异常containerd负责管理容器镜像如果它出现问题kubelet无法获取镜像信息检查containerd状态systemctl status containerd磁盘inode耗尽使用df -i检查inode使用情况容器环境容易产生大量小文件导致inode耗尽SELinux或AppArmor限制检查安全模块是否阻止了kubelet访问文件系统查看/var/log/audit/audit.log获取相关拒绝记录2.2 诊断命令与预期输出执行以下命令收集信息# 检查文件系统挂载 mount | grep -E kubelet|containerd # 检查磁盘空间 df -h /var/lib/kubelet /var/lib/containerd # 检查containerd状态 containerd config dump | grep -A 5 \[plugins.\io.containerd.grpc.v1.cri\.image\] # 检查inode使用 df -i /var在本次故障中这些检查都没有发现明显异常containerd服务也显示为运行状态。这提示我们需要更深入地分析kubelet与containerd的交互。3. CNI插件初始化失败的根本原因cni plugin not initialized这个错误表明Kubernetes的网络插件未能正确启动。CNI(Container Network Interface)插件负责为Pod配置网络如果它失败节点上的所有Pod都将无法正常工作导致节点被标记为NotReady。3.1 CNI插件依赖链分析CNI插件的正常工作依赖于以下几个关键组件容器运行时(containerd/docker)提供基础的容器运行环境kubelet协调容器生命周期管理网络插件二进制和配置文件如Calico、Flannel等的可执行文件和配置文件网络命名空间内核级别的网络隔离机制这些组件之间的关系可以用下表表示组件功能依赖项故障表现containerd容器运行时内核cgroup支持容器无法创建kubelet节点代理containerd APIPod调度失败CNI插件网络配置containerd socket网络不通kube-proxy服务代理CNI网络服务无法访问3.2 关键诊断步骤检查CNI配置文件ls -l /etc/cni/net.d/ cat /etc/cni/net.d/10-calico.conflist验证CNI插件二进制文件ls -l /opt/cni/bin/检查kubelet网络配置ps -ef | grep kubelet | grep --colorauto network-plugin查看containerd日志journalctl -u containerd --since 1 hour ago | grep -i cni在本次故障中所有这些检查都显示配置正确但CNI插件仍然报告未初始化。这提示我们可能需要关注containerd的内部状态。4. containerd重启的神奇效果在多次排查无果后尝试了一个简单的操作重启containerd服务。令人惊讶的是这个操作不仅解决了CNI插件初始化问题连invalid capacity 0 on image filesystem错误也一并消失了。systemctl restart containerd几分钟后所有节点状态恢复正常NAME STATUS ROLES AGE VERSION sealos-k8s-node-01 Ready control-plane,master 50m v1.22.0 sealos-k8s-node-02 Ready none 49m v1.22.0 sealos-k8s-node-03 Ready none 49m v1.22.0 sealos-k8s-node-04 Ready control-plane,master 50m v1.22.04.1 为什么重启containerd能解决问题containerd作为容器运行时维护着多个内部状态和连接gRPC连接状态kubelet通过gRPC与containerd通信长时间运行可能出现连接问题文件系统挂载缓存containerd缓存了文件系统信息可能导致容量报告不准确插件管理状态CNI插件通过containerd注册状态异常会影响网络功能当containerd运行时间过长或遇到某些内部错误时这些状态可能会变得不一致。重启服务会重置所有这些状态通常能解决一些难以定位的幽灵问题。4.2 更优雅的解决方案虽然重启containerd可以快速解决问题但在生产环境中我们可能需要更优雅的解决方案配置containerd自动恢复# 在/etc/containerd/config.toml中添加 [plugins.io.containerd.grpc.v1.cri] enable_selinux false sandbox_image registry.k8s.io/pause:3.6 [plugins.io.containerd.grpc.v1.cri.containerd] snapshotter overlayfs disable_snapshot_annotations true设置kubelet健康检查# 在kubelet配置中添加 --healthz-port10248 --healthz-bind-address0.0.0.0监控关键指标containerd的goroutine数量gRPC调用延迟文件系统操作错误计数5. 系统性故障排查框架基于这次经验我总结了一个Kubernetes节点NotReady问题的系统性排查框架5.1 排查流程图确认节点状态kubectl get nodes -o wide检查kubelet日志journalctl -u kubelet -n 100 -f验证容器运行时crictl ps和systemctl status containerd检查网络插件ip link show和kubectl get pods -n kube-system查看资源使用top和df -h检查内核日志dmesg -T | tail -n 505.2 常见错误模式对照表错误现象可能原因验证方法解决方案CNI插件未初始化containerd状态异常containerd日志重启containerd镜像容量为0文件系统挂载问题mount命令重新挂载或重启节点频繁NotReady内存压力free -m调整kubelet资源预留Pod网络不通网络策略冲突calicoctl get networkpolicy调整网络策略5.3 预防性维护建议为了避免类似问题再次发生可以考虑以下预防措施定期滚动重启节点组件# 使用kubectl drain安全排空节点 kubectl drain node-name --ignore-daemonsets systemctl restart kubelet containerd kubectl uncordon node-name配置资源监控和告警监控containerd的内存使用和goroutine数量设置kubelet健康检查端点监控保持版本兼容性确保kubelet、containerd和CNI插件版本兼容参考Kubernetes官方发布的版本兼容性矩阵那次故障后我在所有集群节点上设置了containerd的定期健康检查并调整了kubelet的资源预留参数。半年过去了再没遇到过类似的全节点NotReady情况。有时候最简单的解决方案背后隐藏着最复杂的系统交互这就是Kubernetes运维的迷人之处——你永远在学习和发现新的问题解决模式。