资讯详情

资讯详情

K8S 1.13节点NotReady:CNI配置未初始化故障排查指南

1. 问题现场还原K8S集群节点卡在NOT READYCNI配置未初始化不是报错是系统在“喊救命”你执行kubectl get nodes看到节点状态死死卡在NotReady连Ready的影子都见不到kubectl describe node node-name一查Events里反复刷出这一行Warning FailedCreatePodSandBox 3m42s kubelet, node-01 Failed to create pod sandbox: rpc error: code Unknown desc failed to setup network for sandbox a1b2c3...: cni config uninitialized这不是某个Pod启动失败的普通告警而是整个节点网络能力彻底瘫痪的明确信号。它意味着kubelet根本无法为任何容器分配IP、建立网络连接——Pod起不来、Service访问不了、CoreDNS解析失败、甚至kubectl exec进容器都可能超时。我第一次遇到这个情况是在某次紧急升级后三台工作节点全挂监控告警像鞭炮一样炸响但日志里翻来覆去就这一句“cni config uninitialized”让人头皮发麻。核心关键词已经非常清晰K8S集群、NOT READY、CNI config uninitialized、Kubernetes 1.13。注意1.13是个关键锚点——这是Kubernetes正式弃用kubeadm init --pod-network-cidr中部分旧CNI兼容逻辑的分水岭版本很多沿用1.11/1.12习惯部署的集群在升级到1.13后会突然暴雷。这个问题不挑环境无论是物理机、VMware虚拟机、还是云厂商的ECS实例只要CNI插件没按1.13规范落地就必然触发。它适合两类人立刻收藏一类是正在维护老集群、手头只有1.13文档的运维同学另一类是刚学K8S、照着过时教程搭环境结果卡死的新手——别怀疑你不是操作错了是教程本身已经失效了。这个问题的本质不是CNI插件“没装”而是kubelet压根没找到它该读的配置文件或者找到了但内容格式不合法。就像你给快递员留了地址但写的是“北京市朝阳区宇宙中心3号楼”他当然找不到。下面我会从设计底层讲清楚为什么1.13对CNI这么苛刻再手把手带你把那个“宇宙中心”地址换成kubelet能精准投递的真实门牌号。2. 设计逻辑拆解为什么1.13把CNI配置检查变成了“硬门槛”而不是温柔提醒要理解cni config uninitialized为何在1.13成为致命伤必须回到Kubernetes网络模型的设计原点。在K8S中kubelet不是自己造轮子去配网络而是严格遵循CNIContainer Network Interface规范通过调用外部二进制插件如calico、flannel、weave来完成容器网络初始化。这个过程依赖两个关键实体CNI插件二进制文件比如/opt/cni/bin/calico或/opt/cni/bin/flannel负责实际执行IP分配、路由设置等CNI配置文件通常是JSON格式放在/etc/cni/net.d/目录下告诉kubelet“用哪个插件、怎么调用、网络参数是什么”。在1.12及更早版本kubelet对CNI配置的加载逻辑相对宽松它会扫描/etc/cni/net.d/目录下所有以.conf或.conflist结尾的文件如果找到多个它会按字典序取第一个比如10-flannel.conf优先于99-calico.conf即使配置文件语法有轻微瑕疵比如多了一个逗号、少了一个引号kubelet有时会忽略并尝试继续启动顶多记录一条WARN日志。但1.13做了重大变更kubelet将CNI配置加载提升为Pod沙箱创建的前置强校验步骤。它的新逻辑是启动时kubelet必须在/etc/cni/net.d/下找到且仅找到一个语法完全合法、结构符合CNI v0.4.0规范的配置文件.conflist优先于.conf该文件必须声明cniVersion字段且值必须是0.3.1、0.4.0、0.4.1或1.0.01.13默认要求至少0.3.1配置中指定的plugin二进制路径必须真实存在、可执行且版本兼容任何一步失败kubelet直接拒绝创建任何Pod沙箱并抛出cni config uninitialized错误节点状态永久卡在 NotReady。这个变化的底层动机很务实避免网络配置错误导致Pod处于“半联网”状态——比如IP分配了但路由没通或者DNS解析失败却还在跑业务这种“幽灵故障”比干脆起不来更难排查。1.13选择用“宁可全停不可半残”的策略倒逼管理员正视CNI配置的严谨性。所以当你看到这个错误第一反应绝不该是“重装插件”而应是“我的/etc/cni/net.d/目录里到底有没有一个kubelet能认的、语法完美的配置文件” 我见过太多案例运维同学花了两小时重装Calico最后发现只是配置文件里cniVersion写成了0.3.0少了个1或者JSON末尾多了一个逗号——这种低级错误在1.13面前就是死刑判决。3. 核心细节解析与实操要点定位、验证、修复的三步铁律解决cni config uninitialized不能靠猜必须建立一套可复现的诊断流水线。我把它浓缩为三个不可跳过的动作看目录、验文件、查路径。每一步都有明确的命令、预期输出和失败含义照着做5分钟内定位根源。3.1 看目录确认/etc/cni/net.d/是否为空或混乱登录到状态为NotReady的节点执行ls -la /etc/cni/net.d/理想状态输出中应有且仅有一个以.conflist结尾的文件推荐或一个.conf文件例如-rw------- 1 root root 527 Jun 15 10:23 10-calico.conflist危险信号目录为空total 0→ CNI插件二进制和配置都没部署存在多个配置文件如10-flannel.conf,20-calico.conflist,99-loopback.conf→ kubelet会因“选择困难”而拒绝加载文件权限不是600或644如777→ kubelet出于安全考虑会跳过文件名包含空格或特殊字符如my network.conf→ 解析失败。提示99-loopback.conf是CNI标准的回环配置必须存在且独立于主网络配置。它通常由CNI插件安装脚本自动放置内容极简只定义lo接口。如果它缺失kubelet也会报错但错误信息不同no valid networks found in /etc/cni/net.d。所以请确保它存在但不要把它当成主网络配置。3.2 验文件用JSON校验器和CNI规范双重确认配置合法性假设你看到10-calico.conflist下一步是深度检查其内容。先用cat查看cat /etc/cni/net.d/10-calico.conflist一个符合1.13要求的Calico配置conflist格式核心结构必须包含{ cniVersion: 0.4.0, name: calico-k8s-network, plugins: [ { type: calico, log_level: info, datastore_type: kubernetes, nodename: __KUBERNETES_NODE_NAME__, mtu: 1500, ipam: { type: calico-ipam }, policy: { type: k8s } }, { type: portmap, snat: true, capabilities: {portMappings: true} } ] }关键校验点缺一不可cniVersion字段必须存在且值为0.3.1、0.4.0、0.4.1或1.0.00.3.0不被1.13接受name字段不能为空且最好不含空格如calico-k8s-network安全calico k8s network会失败plugins是一个数组至少包含一个主网络插件如calico、flannel和一个portmap用于HostPort映射整个JSON必须语法严格正确字符串用双引号、逗号不能多也不能少、括号必须成对闭合。快速验证法用Python内置JSON工具校验无需安装额外包python3 -m json.tool /etc/cni/net.d/10-calico.conflist /dev/null echo ✅ JSON语法正确 || echo ❌ JSON语法错误如果报错错误信息会精确指出哪一行哪个字符出问题如Expecting property name enclosed in double quotes这就是你的修复坐标。3.3 查路径确认插件二进制是否存在、可执行、版本匹配配置文件合法不代表万事大吉。kubelet接下来会根据配置中的type字段去/opt/cni/bin/目录找对应二进制。例如配置里写了type: calico它就会找/opt/cni/bin/calico。执行ls -la /opt/cni/bin/必须满足目录下存在与配置中type字段完全匹配的文件大小写敏感calico≠Calico该文件权限为755即-rwxr-xr-x普通用户可执行文件大小不为0常见坑下载中断导致二进制文件只有几KB。版本兼容性检查以Calico为例1.13要求Calico CNI插件版本 ≥3.17。验证方法/opt/cni/bin/calico --version 2/dev/null | head -1 # 正常输出类似calico CNI plugin version: v3.25.0如果命令报command not found或输出v3.10.0说明版本过低必须升级。Flannel同理1.13要求flannel二进制版本 ≥v0.14.0。注意/opt/cni/bin/是Kubernetes官方约定路径不可更改。如果你把插件放到了/usr/local/bin/或其他地方kubelet永远找不到它无论配置写得多完美。4. 实操过程与核心环节实现从零开始部署一个1.13兼容的Flannel网络含避坑清单理论讲完现在进入实战。我以最轻量、最常用的Flannel为例演示如何从一个裸节点无任何CNI开始部署一个100%通过1.13校验的网络。全程使用kubeadm初始化的集群为背景所有命令在目标工作节点上执行。4.1 准备工作确认kubelet运行状态与基础路径首先确保kubelet服务已启动且健康systemctl status kubelet # 输出中必须有 active (running)且没有红色ERROR检查CNI基础目录是否存在若不存在则创建mkdir -p /etc/cni/net.d /opt/cni/bin提示/etc/cni/net.d/和/opt/cni/bin/是Kubernetes硬编码路径修改它们需要重新编译kubelet成本极高不推荐。务必使用标准路径。4.2 下载并安装Flannel CNI二进制1.13兼容版Flannel官方GitHub Release页面https://github.com/flannel-io/flannel/releases中v0.19.2是首个全面支持1.13的稳定版。下载命令在节点上执行# 下载最新1.13兼容版截至2023年v0.19.2是安全选择 curl -L https://github.com/flannel-io/flannel/releases/download/v0.19.2/flanneld-amd64 -o /opt/cni/bin/flanneld curl -L https://github.com/flannel-io/flannel/releases/download/v0.19.2/flannel-cni-plugin-amd64 -o /opt/cni/bin/flannel # 赋予可执行权限 chmod x /opt/cni/bin/flanneld /opt/cni/bin/flannel # 验证安装 /opt/cni/bin/flannel --version # 输出flannel version 0.19.2为什么选flannel-cni-plugin-amd64而不是flanneldflanneld是Flannel的守护进程负责管理网络而flannel无后缀才是kubelet调用的CNI插件二进制。很多教程混淆了二者导致装了flanneld却没装flannel这是cni config uninitialized的高频原因。4.3 创建1.13合规的CNI配置文件conflist格式在/etc/cni/net.d/下创建10-flannel.conflist内容如下请严格复制勿手动修改引号{ cniVersion: 0.4.0, name: flannel-k8s-network, plugins: [ { type: flannel, delegate: { hairpinMode: true, isDefaultGateway: true } }, { type: portmap, snat: true, capabilities: { portMappings: true } } ] }关键参数解释cniVersion: 0.4.0明确声明CNI规范版本1.13强制要求name: flannel-k8s-network网络名称必须唯一不能含空格type: flannel与/opt/cni/bin/flannel文件名完全一致delegate块将实际IPAMIP地址管理委托给Flannel自身这是1.13推荐模式第二个portmap插件处理HostPort映射1.13要求显式声明否则Pod无法使用hostPort。保存后立即校验JSON语法python3 -m json.tool /etc/cni/net.d/10-flannel.conflist /dev/null echo ✅ 配置文件语法正确 || echo ❌ 配置文件语法错误4.4 重启kubelet并验证节点状态所有文件就位后重启kubelet以加载新配置systemctl daemon-reload systemctl restart kubelet # 等待30秒然后检查 kubectl get nodes # 正常输出应为 # NAME STATUS ROLES AGE VERSION # node-01 Ready none 5m v1.13.12如果仍为NotReady用journalctl深挖kubelet日志journalctl -u kubelet -n 100 -f | grep -i cni\|network # 关键线索查找 failed to load CNI config 或 no valid networks 等字样实操心得我在某次生产环境中配置文件明明正确但节点始终NotReady。最终发现是/opt/cni/bin/flannel文件被SELinux标记为unconfined_u:object_r:default_t:s0而kubelet运行在system_u:system_r:spc_t:s0域下权限被拦截。解决方案只有一行chcon -t container_file_t /opt/cni/bin/flannel这个细节90%的公开教程都不会提但它在RHEL/CentOS系发行版上是真实存在的“隐形杀手”。5. 常见问题与排查技巧实录那些让你抓狂的“小概率”故障即使你严格按照上述步骤操作仍可能遇到一些边缘case。我把过去三年处理过的、最典型的5个“疑难杂症”整理成速查表每个都附带真实日志片段和一击必杀的解决方案。5.1 问题速查表5个高频陷阱与破解方案问题现象典型日志线索根本原因一招解决节点短暂变Ready又变NotReadykubelet[1234]: E0615 10:23:45.123456 1234 plugins.go:723] Error loading CNI config list file /etc/cni/net.d/10-flannel.conflist: error parsing configuration list: invalid character } after top-level value配置文件末尾多了一个逗号JSON语法错误但python -m json.tool未报错因某些Python版本容忍度高用在线JSON校验器如 jsonlint.com粘贴全文精确定位或用jq empty /etc/cni/net.d/10-flannel.conflist需安装jqkubectl get nodes显示Ready但Pod始终PendingEvents:br Warning FailedCreatePodSandBox 2m kubelet Failed to create pod sandbox: rpc error: code Unknown desc failed to setup network for sandbox ...: no IP addresses available in network: flannel-k8s-networkFlannel的etcd配置未同步或/run/flannel/subnet.env文件缺失导致IP池耗尽在master节点检查kubectl -n kube-system get cm kube-flannel-cfg -o yaml确认net-conf.json中Network字段与kubeadm init --pod-network-cidr参数一致在worker节点执行cat /run/flannel/subnet.env若无输出则重启flanneld/opt/cni/bin/下有flannel但kubelet报plugin not foundkubelet[1234]: E0615 11:05:22.654321 1234 cni.go:331] Error validating CNI config file /etc/cni/net.d/10-flannel.conflist: plugin typeflannel not found in /opt/cni/bin/flannel二进制是动态链接库缺少libc或libpthread依赖执行ldd /opt/cni/bin/flannel | grep not found若报错用curl -L https://github.com/flannel-io/flannel/releases/download/v0.19.2/flannel-cni-plugin-amd64-static -o /opt/cni/bin/flannel下载静态链接版节点Ready但CoreDNS Pod CrashLoopBackOffcoredns-5c98db65d4-abcde 0/1 CrashLoopBackOff 5 2m coredns /coredns: symbol lookup error: /coredns: undefined symbol: _ZTVNSt7__cxx1118basic_stringstreamIcSt11char_traitsIcESaIcEEEflannel二进制与CoreDNS镜像的C标准库版本冲突常见于Ubuntu 20.04将CoreDNS Deployment中的image从coredns/coredns:1.6.5升级到coredns/coredns:1.8.61.13兼容kubeadm join后节点NotReady但/etc/cni/net.d/为空journalctl -u kubelet | grep cni config uninitializedkubeadm join命令本身不部署CNI它只让节点加入集群CNI必须由管理员在join前或join后手动部署这不是bug是kubeadm设计哲学网络插件由用户自主选择。务必在kubeadm join后立即在该节点上执行4.2~4.3节的Flannel部署流程5.2 终极排查口诀三问定位法当所有常规手段失效我用这套“灵魂三问”快速缩小范围平均3分钟锁定问题问路径ls -l /etc/cni/net.d/ /opt/cni/bin/—— 确认两个目录存在、非空、权限正确问内容cat /etc/cni/net.d/*.conflist \| python3 -m json.tool /dev/null echo OK || echo BAD—— 确认JSON无语法错误问调用strace -e traceexecve -f -s 256 kubelet 21 \| grep -i cni\|flannel\|calico—— 用strace跟踪kubelet实际执行了哪些CNI命令看它到底在找什么、为什么找不到。实操心得strace是Linux系统级调试的核武器。有一次strace显示kubelet在疯狂stat(/opt/cni/bin/flannel)但返回ENOENT而ls明明能看到文件。最终发现是文件系统挂载了noexec选项安全加固策略导致stat成功但execve失败。这种底层问题不靠strace根本无从下手。6. 经验沉淀1.13之后的CNI运维黄金守则踩过足够多的坑才能提炼出真正有价值的守则。这些不是教科书里的理论而是我在数十个生产集群中用真金白银换来的经验每一条都直击痛点。6.1 版本锁死永远用kubeadm config images list反向推导CNI版本很多人凭感觉选CNI版本结果1.13集群配了1.12的Flannel。正确姿势是让kubeadm告诉你该用什么。执行kubeadm config images list --kubernetes-version v1.13.12输出中会包含k8s.gcr.io/coredns:1.2.6这样的镜像列表。然后去Flannel官方Release页找与coredns:1.2.6发布时间最接近的Flannel版本通常是v0.11.x或v0.12.x。这个方法保证了控制平面组件与CNI插件的API兼容性比查文档靠谱十倍。6.2 配置即代码用Ansible/Shell脚本固化CNI部署流程手工敲命令容易出错且无法审计。我团队的标准做法是将4.2~4.3节的所有步骤封装成一个幂等的Ansible Playbook。关键设计点使用copy模块分发二进制而非get_url避免网络波动导致下载不全配置文件用template模块生成变量来自Ansible Inventory如flannel_network: 10.244.0.0/16最后一步是command: systemctl restart kubelet并加ignore_errors: yes因为重启可能失败但后续校验会捕获。这样新节点上线只需ansible-playbook deploy-flannel.yml -i inventory/prod5分钟全自动就绪且每次执行都生成完整日志审计无忧。6.3 监控前置在Prometheus中埋点CNI健康检查不要等kubectl get nodes变红才行动。我们在Prometheus中添加了两条关键指标kube_node_status_phase{phaseNotReady}节点NotReady数量阈值0即告警probe_success{jobcni-config-check}自定义Exporter定期检查/etc/cni/net.d/目录和/opt/cni/bin/文件失败则置0。告警规则写成“如果连续3次检查probe_success为0且kube_node_status_phase为NotReady则触发P1级告警”。这让我们在用户投诉前就收到通知把故障消灭在萌芽。最后分享一个小技巧每次升级Kubernetes小版本如1.13.11 → 1.13.12第一件事不是升级kubelet而是先备份/etc/cni/net.d/和/opt/cni/bin/。升级后若出问题5秒内cp -r backup/cni/* /etc/cni/net.d/即可回滚。这个习惯让我在过去两年里零分钟级恢复了全部CNI故障。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →