ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Kubernetes 节点 NotReady 排查全流程:从 kubelet、CNI 到磁盘压力逐层定位

Kubernetes 节点 NotReady 排查全流程:从 kubelet、CNI 到磁盘压力逐层定位 Kubernetes 节点 NotReady 排查全流程:从 kubelet、CNI 到磁盘压力逐层定位kubectl get nodes突然看到某个节点STATUS变成NotReady,上面的 Pod 陆续被驱逐,业务开始报警。这时候慌着重启节点往往是最坏的选择——重启可能暂时恢复,但下次照样复发,而且你永远不知道根因。节点 Ready 与否,本质是 kubelet 定期向 API Server 上报的一组状态条件的综合结果。NotReady 只是表象,背后可能是 kubelet 挂了、网络插件没就绪、磁盘满了、或者 kubelet 连不上 API Server。这篇按「从外到内」的顺序,给一套能定位到根因的排查路径。第一步:先看节点自己怎么说不要一上来就 SSH。先用describe看 kubelet 上报的 Conditions 和最近的 Events,这是信息密度最高的一步:kubectl describenodenode-name重点看Conditions这一段:Conditions: Type Status Reason Message MemoryPressure False KubeletHasSufficientMemory kubelet has sufficient memory DiskPressure True KubeletHasDiskPressure kubelet has disk pressure PIDPressure False KubeletHasSufficientPID kubelet has sufficient PID Ready False KubeletNotReady ...这里一眼就能分流:DiskPressureTrue→ 磁盘满了,跳到「磁盘压力」小节。ReadyFalse且Message里提到container runtime network not ready/cni plugin not initialized→ 网络插件问题,跳到「CNI」小节。所有 Condition 都是Unknown→ kubelet 根本没上报,已经和 API Server 失联,跳到「kubelet 失联」小节。Unknown和False的区别很重要:False说明 kubelet 还活着、在主动汇报「我不健康」;Unknown说明 kubelet 压根没汇报,API Server 是靠node-monitor-grace-period(默认 40s)超时后自己把状态标成 Unknown 的。方向完全不同。第二步:kubelet 失联(Conditions 全是 Unknown)Conditions 全 Unknown,基本是 kubelet 进程死了或连不上 API Server。SSH 到节点上:# 看 kubelet 是否还活着systemctl status kubelet# 实时滚动日志,找最近的 errorjournalctl-ukubelet-f--since10 minutes ago常见几种日志和对应根因:# 证书过期——kubeadm 集群一年不升级最容易踩 failed to run Kubelet: unable to load bootstrap ... certificate has expired # 连不上 API Server——控制面挂了或网络不通 Failed to list *v1.Node: Get https://10.0.0.1:6443/...: dial tcp ... connection refused证书过期就续签:kubeadm certs check-expiration# 先确认哪个证书过期kubeadm certs renew all systemctl restart kubelet如果是connection refused,别在这个 worker 上折腾,去 control-plane 节点看kube-apiserver容器是不是挂了(crictl ps -a | grep apiserver)。worker 的 NotReady 有可能只是控制面故障的连带表现。第三步:CNI 网络插件没就绪Message里出现network plugin is not ready: cni config uninitialized时,是网络插件(Calico、Flannel、Cilium 等)的 Pod 在这个节点上没起来。kubelet 检查/etc/cni/net.d/下有没有有效配置,没有就判定网络未就绪,整个节点 NotReady。先看该节点上网络插件 Pod 的状态:# 网络插件多以 DaemonSet 部署在 kube-systemkubectl get pods-nkube-system-owide --field-selectorspec.nodeNamenode-name如果 Calico/Flannel 的 Pod 处于CrashLoopBackOff或Init,看它的日志:kubectl logs-nkube-systemcalico-pod-ccalico-node再到节点上确认 CNI 配置文件到底有没有生成:ls-l/etc/cni/net.d/# 正常应有类似 10-calico.conflist 的文件;空目录就是插件没写进来典型原因:插件镜像拉不下来(内网无法访问 registry)、节点刚加入集群但 DaemonSet 还没调度过来、或者升级后 CNI 版本和 kubelet 不兼容。对症处理:修好镜像拉取、kubectl rollout restart daemonset/cni -n kube-system。第四步:磁盘压力(DiskPressureTrue)DiskPressureTrue时,kubelet 因为磁盘超过驱逐阈值(默认镜像文件系统可用空间低于 15%)主动上报不健康,并开始驱逐 Pod。先定位到底是什么把盘吃满了:# 看根分区和 kubelet 数据目录df-h/df-h/var/lib/kubelet /var/lib/docker /var/lib/containerd绝大多数情况是这几类占用:# 1. 死掉的容器和悬空镜像——最常见crictl images|wc-lcrictl rmi--prune# 清理未被使用的镜像# 2. 容器日志无限增长(没配 log rotation)du-sh/var/lib/containerd/... 或 /var/log/pods/*|sort-h|tail# 3. emptyDir / 临时文件把节点盘写满清理后 kubelet 会在下一个检查周期自动把DiskPressure翻回False,节点恢复 Ready。但根治要配日志轮转:给容器运行时设置containerLogMaxSize(如10Mi)和containerLogMaxFiles,否则一个爱打日志的 Pod 迟早再次撑爆节点。一张排查决策表把上面的路径浓缩成可照抄的顺序:kubectl describe node n → 看 Conditions ├── Conditions 全 Unknown → kubelet 挂了/失联 → journalctl -u kubelet │ ├── certificate expired → kubeadm certs renew all │ └── connection refused → 查 control-plane 的 apiserver ├── Ready.Message cni not ready → 查 kube-system 里 CNI Pod /etc/cni/net.d └── DiskPressure True → df -h → crictl rmi --prune → 配日志轮转小结先describe node看 Conditions,别急着 SSH:False(kubelet 主动报不健康)和Unknown(kubelet 失联)是两条完全不同的路。kubelet 失联看journalctl -u kubelet,高频根因是证书过期(kubeadm certs renew all)和连不上 API Server。CNI 未就绪查kube-system里网络插件 Pod 的状态和/etc/cni/net.d/有没有配置文件。磁盘压力用df -h定位、crictl rmi --prune清理,根治靠给容器运行时配日志轮转。重启节点能「恢复」但会掩盖根因,排查完再重启才不会反复复发。一句话记忆:节点 NotReady 不是一种故障,而是一类症状——describe node的 Conditions 就是分诊台,先分诊再对症。
返回列表