news 2026/10/21 12:14:23

K8s节点NotReady与Flannel Pod Terminating排查实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
K8s节点NotReady与Flannel Pod Terminating排查实战

如果你某天早上登录集群,发现kubectl get nodes里 master 节点还是NotReady,而kube-system下面那个kube-flannel-ds-amd64-xxxxx一直挂在Terminating状态,别急着去删 Pod。这个组合很常见,也挺典型的:Flannel 作为 CNI 插件负责把节点间的 Pod 网络打通,它一旦“半死不活”,节点状态很快就会跟着异常。我经历过几次类似问题,今天把这套排查过程、修复命令和踩坑经验完整复现一遍,希望能帮你少走弯路。

这套内容适合正在维护 Kubernetes 集群的运维、SRE,也适合刚接触 K8s 网络组件的人对照着排查。不管是单节点还是多节点环境,问题逻辑基本一致,只是排查命令的侧重点略有不同。我的排查环境是 containerd 作为容器运行时,网络插件用的 Flannel VXLAN 模式,如果你那边是 Docker 运行时,个别命令改成docker执行即可,不影响整体思路。

1. 故障现象与影响范围

1.1 现场看到的样子

先说现象。故障发生时机通常是节点重启过一次,或者内核升级后重启了机器。经过一段时间的运行,集群里某个节点(特别是 master)虽然进程看起来都在,但状态就是不健康。

执行kubectl get nodes:

$ kubectl get nodes NAME STATUS ROLES AGE VERSION master1 NotReady control-plane 127d v1.28.6 worker1 Ready <none> 127d v1.28.6

同时查看kube-system下的 Flannel DaemonSet Pod:

$ kubectl get pods -n kube-system | grep flannel kube-flannel-ds-amd64-8f2n4 0/1 Terminating 0 8h kube-flannel-ds-amd64-m6k9s 1/1 Running 0 6h

这就是最典型的状态组合:老 Pod 卡在Terminating,新 Pod 已经被 DaemonSet 重新拉起,但节点状态依然是NotReady。

关注的指标不只是这两个字段。0/1表示容器没有处于 Ready 状态,Terminating表示删除流程已经卡住,Pod 的宽限期(grace period)耗尽了也没被真正清理掉。你还会发现 master 节点的所有系统组件像kube-apiserver、etcd这些并不一定受影响,它们继续在跑,但 kubelet 向控制面上报的状态始终不健康,这导致调度器默认不会把新工作负载调度到该节点。

1.2 为什么 Flannel 出问题会让 master 节点置为 NotReady

Kubernetes 节点状态是 kubelet 周期性上报的,kubelet 判断节点是否 Ready 会同时看很多因素,其中NetworkReady条件是很关键的一项。kubelet 会检查节点网络是否就绪,而网络是否就绪依赖于 CNI 插件是否配置正常、Pod 网络是否能创建。Flannel 作为 CNI 插件,承担的是在节点之间建立 VXLAN 隧道、维护路由表和flannel.1接口的责任。

如果 Flannel Pod 异常退出或者 CNI 配置缺失,kubelet 在创建 Pod 时调用 CNI 插件会失败,网络不可用,kubelet 就会给节点打上NotReady标记。所以表面上你看到的是 Flannel PodTerminating,本质上是这个节点上的 Pod 网络已经断了,节点自然被判定为不健康。

还有一个容易忽略的细节:Flannel DaemonSet 在节点上以 Pod 方式运行,如果它本身启动依赖的某些条件不满足(比如节点上没有分配 PodCIDR、内核 VXLAN 模块缺失、CNI 配置文件残留等),它会一直 CrashLoopBackOff 或者反复重启,导致节点网络始终无法恢复。

2. 排障思路:先理清因果链再动手

2.1 从 Pod 状态和节点状态反推可能原因

我习惯先不执行任何修复操作,而是把可能的故障链路在脑子里过一遍。Flannel Pod 卡Terminating和节点NotReady之间存在多种原因指向,常见的大致分成这几类:

第一类是容器运行时的问题。containerd 或者 dockerd 可能因为存储、内存、或并发问题导致容器删除流程卡住,旧 Pod 的容器进程还残留着,kubelet 删不动,Pod 就挂在Terminating。这种场景下你会观察到kubelet日志中有反复尝试移除容器的报错。

第二类是网络资源残留。Flannel 会在节点上创建flannel.1虚拟网卡、路由项、iptables 规则。如果节点异常重启后这些资源处于不一致状态,新 Pod 无法创建新的flannel.1,旧 Pod 因为持有这些网络资源而无法清理,于是互相卡死。

第三类是协调数据不一致。比如节点上的 PodCIDR 分配信息、CNI 配置文件里的 subnet 信息与集群实际配置不一致,Flannel 启动后发现自己拿到的子网不对,无法正常建立路由,Pod 反复重启也恢复不了。

所以排查的第一步不是删除,而是搞清楚当前节点上到底哪里卡住了。先看事件、日志、网络配置,再决定动手方向。

2.2 先看数据:Pod 事件和容器运行时状态

我会按这样的顺序收集信息:

# 1. 看 Pod 当前状态和事件 kubectl describe pod -n kube-system kube-flannel-ds-amd64-8f2n4 # 2. 看新起的 Flannel Pod 日志 kubectl logs -n kube-system kube-flannel-ds-amd64-m6k9s -c kube-flannel --tail=200 # 3. 看节点 kubelet 最近日志 journalctl -u kubelet --since "1 hour ago" --no-pager

如果容器还在运行但已经 Ready 了,想进一步看它内部是否正常,可以进入 Pod 执行命令。但这里有个注意事项:Flannel 的容器镜像比较精简,不一定带 shell,有时需要依靠日志和nsenter查看主机网络命名空间。

describe输出里值得留意的关键字包括:FailedKillPod、NetworkNotReady、FailedCreatePodSandBox、CNI failed to set up network。这些字符串基本能定位到是容器运行时、CNI 还是网络配置的问题。

2.3 明确排查顺序,不要一上来就删 Pod

这里必须多说一句:看到Terminating就执行kubectl delete pod --force是我见过最多的盲目操作。强制删除一个卡住的 Pod 只能让 kubelet 放弃等待,但 Pod 底层的容器如果还占着网络资源、CRI 里还有残留,新 Pod 依然可能马上失败,节点仍然NotReady。更严重的是,强制删除会掩盖真实根因,日志里唯一的线索被清掉了。

正确的顺序是:

  1. 查看事件和日志,判断是 Pod 清理失败还是 CNI 配置失败。
  2. 检查节点网络接口和路由表,确认flannel.1是否存在、是否处于正确状态。
  3. 检查容器运行时状态,确认是否还有旧容器没有被清理。
  4. 确认 CNI 配置文件有哪些,是否有残留或者冲突。
  5. 全部确认完毕后再做清理和恢复。

3. 实操定位:一步步找到根因

3.1 检查 Flannel Pod 状态与事件

登录到 NotReady 节点,先查看对应 Pod 的详细事件:

kubectl describe pod -n kube-system kube-flannel-ds-amd64-8f2n4

关键的事件可能长这样:

Events: Warning FailedKillPod 6h kubelet error killing pod: failed to "KillContainer" for "kube-flannel" with KillContainerError: "rpc error: code = DeadlineExceeded desc = context deadline exceeded"

DeadlineExceeded表示 kubelet 在删除容器时调用的 CRI 接口超时了。这种情况通常是 containerd 在处理容器停止时 hang 住,可能是 containerd 内部任务队列阻塞、存储驱动异常,也可能是容器内进程处于 D 状态(不可中断睡眠)导致 kill 无效。

再看新 Pod 的事件,如果新的 Pod 反复 CreateContainer 失败,事件里大概率会有 CNI 相关报错:

Warning FailedCreatePodSandBox 3m kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox ... network plugin call failed: cni plugin not found

cni plugin not found直接意味着节点上的 CNI 插件二进制缺失或者配置文件损坏。有时候你看到的是failed to find plugin "flannel",这是因为/opt/cni/bin里确实没有 flannel 的可执行文件。

3.2 检查 Flannel 日志与 CNI 配置

如果新 Pod 能跑起来但 node 还NotReady,那问题多半不在容器运行本身,而在网络配置。此时看 Flannel 日志:

kubectl logs -n kube-system kube-flannel-ds-amd64-m6k9s -c kube-flannel --tail=200

正常的日志尾部一般是不断输出Subnet added、Lease acquired这类信息,并且包含当前的节点 IP 和 Pod 网段。如果日志里出现类似下面的内容,就能找到线索:

E0603 12:00:01.123456 12345 main.go:456] Error registering network: failed to acquire lease: node "master1" pod cidr not assigned

pod cidr not assigned是在告诉你说该节点没有 PodCIDR。这个字段是 kube-controller-manager 在节点加入时分配的,如果你的集群使用 Flannel 作为网络插件,并且在 kube-controller-manager 启动参数里没有设置--allocate-node-cidrs=true和--cluster-cidr,节点就不会拿到 PodCIDR,Flannel 也就拿不到可用的网段。

排查时还要看 CNI 配置文件:

ls -la /etc/cni/net.d/ cat /etc/cni/net.d/10-flannel.conflist

我遇到过一种很典型的情况:节点上同时存在多个 CNI 配置文件,比如/etc/cni/net.d/10-flannel.conflist和/etc/cni/net.d/05-cilium.conf同时存在。CNI 会按字典序读取配置,如果先读到的是其他插件的配置,容器创建时就会调用错误插件,Flannel 的实际网络配置一直不生效。

3.3 检查节点网络接口与路由

这一步最容易忽略,但往往是问题所在。节点异常重启后,flannel.1接口可能会处于 DOWN 状态,或者完全存在但路由表已经乱了。查看接口状态:

ip addr show flannel.1

期望的结果是接口存在且状态为UP,并有对应的 VXLAN 隧道 IP。如果接口不存在,说明 Flannel 还没有成功启动或者已经删除了自己的接口。

再看路由表:

ip route | grep flannel.1

正常的 Flannel VXLAN 模式路由表大约长这样:

10.244.0.0/24 dev flannel.1 proto kernel scope link src 10.244.0.1 10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink

如果路由表里只剩部分条目,或者对应flannel.1的路由指向了错误网关,那说明租约信息不同步,Flannel 无法正确建立节点间隧道。

内核模块也需要确认。VXLAN 模式依赖vxlan模块,检查方式:

lsmod | grep vxlan modinfo vxlan

如果模块没有加载,Flannel 启动时会报operation not permitted,但这个问题在云主机上相对少见,多为自建物理机或特定内核环境。

3.4 检查容器运行时,确认卡 Terminating 的根源

这一节最接近“Terminating 为什么卡住”的答案。用crictl查看节点上的容器:

crictl ps -a | grep flannel

你会看到类似输出:

CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID a1b2c3d4e5f6 rancher/flannel:v0.24.2 8h Running kube-flannel 1 ... f6e5d4c3b2a1 rancher/flannel:v0.24.2 8h Exited kube-flannel 0 ...

注意两个容器共用同一个 Pod,一个是新容器,一个是旧容器。如果旧容器对应的 STATE 不是Exited而是Running,说明 containerd 里容器进程还活着,而 kubelet 已经放弃了等待。这种情况强制删除 Pod 意义不大,真正要做的是去 containerd 里确认容器是否还在运行:

crictl inspect a1b2c3d4e5f6 | grep -A 20 state

如果镜像层挂载无法卸载,crictl 删除也会卡住,这类问题通常和 containerd 的元数据损坏、磁盘空间不足有关系。检查一下节点磁盘:

df -h

一个很常见但容易被忽略的事实:如果/var/lib/containerd所在分区满了,任何需要写元数据的容器操作都会卡在 IO 等待上,表现为容器删除超时。

4. 修复过程:从清残留到恢复 Ready

4.1 清理卡住的容器与网络资源

确认是容器残留导致的问题后,分步骤清理。先处理 containerd 里残留的容器:

crictl stop a1b2c3d4e5f6 crictl rm a1b2c3d4e5f6

如果crictl stop也超时,可以考虑直接查看容器进程,发送 SIGKILL:

crictl inspect a1b2c3d4e5f6 | grep pid kill -9 <pid>

然后等待 containerd 回收容器。这种操作在紧急处理时是有效的,但如果你发现 kill 之后容器仍然存在,说明 containerd 的元数据已经不一致,需要考虑重启 containerd。

清理完容器后,接下来是网络资源。如果旧的flannel.1接口状态异常,删除后由 Flannel 重建:

ip link delete flannel.1

删除接口会影响节点上所有使用该接口的 Pod 网络,所以这一步建议在业务低峰期做,并且要确保你已经知道这个节点上 Pod 会全部被重建。

接着清理残留路由:

ip route flush dev flannel.1

还要检查一下 CNI 配置目录,是否需要清理其他插件残留:

ls -la /etc/cni/net.d/

如果有其他插件的配置文件,应该先备份再移除到其他目录,确保 Flannel 的配置文件成为唯一可用的 CNI 配置。

4.2 强制删除异常 Pod,让 DaemonSet 重新调度

清理完容器和网络资源后,终于可以强制删除那个卡住的TerminatingPod 了:

kubectl delete pod -n kube-system kube-flannel-ds-amd64-8f2n4 --force --grace-period=0

这里解释一下为什么要加--force --grace-period=0:正常删除会等待 30 秒左右的宽限期,让容器优雅退出;但对于已经卡死、kubelet 删不掉的容器来说,宽限期没有意义,强制删除只是让 API Server 侧立刻清理对象记录。真正的容器清理工作我们刚才已经在节点上用crictl完成了,所以这里只是做一次“对齐”。

删除旧 Pod 后,DaemonSet 会在该节点上重新创建新 Pod。这时候不要急着认为所有问题都解决了,先观察新的 Pod 是否能通过 CNI 创建网络沙箱。如果新 Pod 能进入Running状态,说明之前的容器残留和网络资源是根因;如果新 Pod 也失败,问题出在 CNI 配置或内核模块等更底层的原因。

4.3 重启 kubelet 并验证集群状态

清理完节点上的网络残留后,建议重启一次 kubelet,让它的 Pod 网络缓存清掉:

systemctl restart kubelet

重启 kubelet 会让它重新执行所有 Pod 的创建流程。对于已经在跑的 Pod,kubelet 不会把它们全部杀掉,只是重新校验状态;对于网络异常期间被判定失败的 Pod,这里会重新尝试创建。

如果 containerd 在之前也表现得不太正常,比如频繁超时,建议一并重启:

systemctl restart containerd

但注意,containerd 是容器运行时的核心,重启它会让节点上所有容器中断,影响面远大于重启 kubelet。所以这个操作一定要谨慎,如果只是个别容器卡删除,不建议重启 containerd;如果节点上大量容器都处于异常状态,再考虑重启。

等待一两分钟后验证:

kubectl get nodes kubectl get pods -n kube-system | grep flannel

正常结果应该是:

NAME STATUS ROLES AGE VERSION master1 Ready control-plane 127d v1.28.6 worker1 Ready <none> 127d v1.28.6 kube-flannel-ds-amd64-m6k9s 1/1 Running 0 6h

节点状态变为Ready后,还需要验证一下 Pod 网络是否真的恢复正常:随便在一个 Pod 里ping另一个节点的 Pod IP,确认 VXLAN 隧道是通的。如果只是节点状态 Ready 但 Pod 网络不通,Flannel 的租约信息可能还有问题,需要进一步排查。

5. 复盘:真正导致 NotReady 的根因与防复发

5.1 一次典型故障的完整复盘

我在某项目X的测试集群里遇到过一模一样的情况,过程记录在这里,作为一个典型的复盘案例。

那台 master 节点起初一切正常,某天晚上因为它所在宿主机的操作系统进行了一次内核升级,机器重启了。重启之后 kubelet 和 containerd 都自动起来了,但 Flannel Pod 一直起不来。我登录节点看到状态,API Server 里的旧 Pod 卡在Terminating,新 Pod 不断CrashLoopBackOff。

翻日志后发现关键报错是:

failed to create vxlan interface: file exists

原因在于节点重启后,内核里那个与flannel.1重名的接口(实际是 VXLAN 虚拟网卡)没有被清掉,但 Flannel 的 meta 信息里并没有记录这个接口存在,于是启动时尝试创建同名接口直接失败。而旧 Pod 之所以一直Terminating,是因为 containerd 里对应的容器进程在重启时没有退出,一直占着那个网络接口。

我当时没有直接强制删 Pod,而是先在节点上执行:

ip link delete flannel.1

然后crictl stop/crictl rm清理掉旧容器,最后等待 DaemonSet 把新 Pod 调度起来。整个过程不到两分钟,节点状态恢复Ready。

这个案例说明一个核心问题:Flannel 的状态和节点上的实际网络状态必须保持一致,而节点重启往往打破这种一致,Flannel 又没有足够强的自愈能力。

5.2 如何避免同类问题再次发生

经验上讲,有几类措施可以显著降低 Flannel Pod 卡 Terminating 的概率。

第一是节点维护流程要规范化。重启节点前,先做一次平滑操作:把该节点上的负载驱逐到其他节点,然后停止 kubelet,再重启操作系统。不要直接重启让 kubelet 和 containerd 一起断掉,那样 Flannel 的清理流程没有任何机会执行,残留是必然的。

第二是初始化集群时务必确认 CNI 配置的唯一性和完整性。装完 Flannel 后,检查/etc/cni/net.d/目录是否只有一个<编号>-flannel.conflist文件;检查kube-controller-manager是否开启了--allocate-node-cidrs;检查节点annotations里的flannel.alpha.coreos.com/public-ip和backend-type是否正确。这些细节点决定了 Flannel 后续能不能稳定运行。

第三是监控要覆盖这一类异常。不只是看kubectl get nodes,更要用类似 Prometheus 的方式持续跟踪kube_pod_container_status_waiting_reason、kube_node_status_condition这些指标。Flannel 状态在变成 Terminating 之前通常有配置异常或模块缺失做前兆,能早一点知道就早一点处理。

6. 常见问题速查表

这里整理了一份排查速查表,可以直接对照使用。

现象可能原因快速确认方式对应处理
Flannel Pod 一直 Terminating容器运行时删除超时,容器残留crictl ps -a查看容器状态crictl stop+crictl rm清理残留容器
Flannel Pod 反复 CrashLoopBackOffCNI 配置冲突或缺失ls /etc/cni/net.d/,查看日志清理多余 CNI 配置,保留有效配置
Flannel Pod 报 subnet 错误节点 PodCIDR 未分配查看kubectl get node <node> -o yaml的podCIDR字段检查 kube-controller-manager 参数
新 Pod 报 cni plugin not foundCNI 插件二进制缺失ls /opt/cni/bin/重新安装插件二进制到所有节点
节点 NotReady 但 Flannel 日志正常flannel.1 接口或路由残留异常ip addr show flannel.1、ip routeip link delete flannel.1后重启 kubelet
强制删除 Pod 后新 Pod 也失败更深层网络配置问题查看新 Pod 的 Sandbox 事件清理 CNI 配置文件、重启 containerd
多节点中只有一个节点异常该节点本地网络或镜像缓存问题df -h、journalctl -u containerd检查磁盘、修复 containerd

使用这个表的时候有个原则:每一项都要先“快速确认”再“对应处理”,不要在没确认的情况下直接执行修复,尤其是删除接口和重启 containerd这类操作。

关于 Flannel 的配置文件还有一个容易踩的坑:如果集群里使用其他模板工具管理 Flannel 的 ConfigMap,改完 ConfigMap 后要记得把 DaemonSet 里的 Pod 滚动重启一次,否则老 Pod 用的还是旧配置。这个操作本身是安全的,因为 DaemonSet 会逐个重建 Pod,避免节点网络中断时间过长。

最后再分享一个小技巧:在把一堆命令发给自己的浏览器终端前,先在出问题的节点上把所有诊断命令的输出存一份到文件里。我习惯的做法是:

{ echo "===== flannel pods =====" kubectl get pods -n kube-system -o wide | grep flannel echo "===== describe =====" kubectl describe pod -n kube-system <flannel-pod-name> echo "===== flannel logs =====" kubectl logs -n kube-system <flannel-pod-name> -c kube-flannel --tail=200 echo "===== network interfaces =====" ip addr show flannel.1 echo "===== routes =====" ip route echo "===== cni config =====" ls -la /etc/cni/net.d/ echo "===== kubelet logs =====" journalctl -u kubelet --since "30 min ago" --no-pager | tail -100 } > flannel-debug-$(date +%Y%m%d-%H%M%S).log

这个文件既能留作事后复盘用,也是你如果向其他同事求助时的“病历本”。我踩过几次坑后发现,很多人拿到诊断信息就能秒定位,但如果你只给一句“节点 NotReady”没人能帮到你。

这套流程下来,kube-flannel-ds-amd64 的 Terminating 和 master 节点的 NotReady 基本都能解决。核心是不要慌,不要先删,按着日志、容器、接口、配置的顺序一层层排查,最后你会发现大多数情况下问题都出在那些不起眼却特别致命的细节上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 12:11:32

论文AIGC率超标怎么降?从检测原理到降AI工具使用全攻略

每年到了论文送审的季节&#xff0c;我的后台和私信基本会被同一类问题淹没&#xff1a;学校指定的检测系统红了&#xff0c;AIGC疑似率比查重率还高&#xff0c;怎么办&#xff1f;还有人说&#xff0c;自己明明已经在用各种降AI工具熬夜刷了好几遍&#xff0c;结果一提交复测…

作者头像 李华
网站建设 2026/10/21 12:10:45

IDEA 2021 从零搭建 SSM 框架:依赖版本对齐与避坑指南

简介&#xff1a;这份源码资源面向Java Web初学者与需要从零搭建SSM框架的开发者&#xff0c;基于IDEA2021、Tomcat9.0与MySQL8.0.25环境&#xff0c;完整演示SpringSpringMVCMyBatis整合过程&#xff0c;帮助读者理解分层架构、依赖注入与数据库映射的落地方式。压缩包共105个…

作者头像 李华
网站建设 2026/10/21 12:10:34

无需GPU!用LocalAI在CPU上跑大模型:从部署到调优全攻略

1. 为什么在GPU昂贵的年代&#xff0c;我选择了一条本地化的道路先说结论&#xff1a;LocalAI 解决的是很多开发者一个非常现实的痛点——手里没有高端显卡&#xff0c;甚至根本没有独显&#xff0c;但依然想跑大模型&#xff0c;想本地化部署&#xff0c;不想把数据送到云端。…

作者头像 李华
网站建设 2026/10/21 12:10:12

深圳中英集运如何避坑?四大硬指标筛选靠谱集运公司

1. 为什么中英集运这件事&#xff0c;到了深圳就特别容易踩坑先说一个我这几年的真实感受&#xff1a;凡是跟"深圳中英包裹集运"沾边的推荐帖&#xff0c;底下永远有人吵架。有人说自己一个月飞了五批货&#xff0c;稳得一批&#xff1b;也有人说同样一家公司&#x…

作者头像 李华
网站建设 2026/10/21 12:08:33

从零手写SQL数据库图标:CSS与SVG双方案实战指南

上周在做一个企业内部管理系统的技术预研时&#xff0c;遇到一个看似很小的需求&#xff1a;侧边栏要加一个“数据库”入口&#xff0c;需要一个SQL图标。我当时第一反应是找个免费图标库下载&#xff0c;结果被各种灰色PNG、风格千篇一律的线性图标模板折磨了整整半天。尺寸不…

作者头像 李华
网站建设 2026/10/21 12:06:35

AI辅助论文写作全攻略:从选题到定稿的高效实践指南

1. 从“畏难”到“上道”&#xff1a;论文写作的真正痛点在哪读研那会儿&#xff0c;我写第一篇小论文的时候&#xff0c;光一个引言部分就磨了整整一周。不是不想写&#xff0c;是真的不知道该怎么下笔。后来跟同门聊天才发现&#xff0c;大家都一样——脑子里有想法&#xff…

作者头像 李华