除了config.yaml,这些CNI配置细节也可能让你的K8s节点卡在NotReady

当你发现Kubernetes工作节点始终处于NotReady状态时,第一反应往往是检查/var/lib/kubelet/config.yaml。但真实情况可能更复杂——我曾在一个生产集群中耗费6小时排查,最终发现是Flannel的subnet.env文件权限配置错误。本文将带你深入那些容易被忽略的CNI配置细节,从底层原理到实操解决方案。

1. 为什么节点NotReady不一定是kubelet的错

大多数工程师看到"failed to load Kubelet config file"报错时,会立即聚焦于kubelet服务本身。但Kubernetes的网络就绪状态是个连锁反应:

journalctl -u kubelet -f | grep -E 'NetworkPluginNotReady|cni'

当看到类似NetworkReady=false reason:NetworkPluginNotReady的日志时,问题已经指向CNI插件。这时需要检查两个关键路径:

检查点健康状态特征故障表现
/run/flannel/subnet.env包含完整的FLANNEL_*环境变量定义文件缺失或变量值格式错误
/etc/cni/net.d/存在至少一个有效的JSON格式网络配置目录为空或配置文件语法错误

最近在调试一个v1.25集群时发现,即使kubelet配置完全正确,如果CNI网络插件未能成功分配Pod CIDR,节点状态也会卡在NotReady。这种间接故障链正是许多运维人员容易陷入的排查盲区。

2. 解剖Flannel的配置文件链

Flannel作为最常用的CNI插件之一,其配置存在三个关键层级:

  1. Kubernetes资源层
    通过kube-flannel DaemonSet的ConfigMap定义基础网络参数:

    net-conf.json: |
      {
        "Network": "10.244.0.0/16",
        "Backend": {
          "Type": "vxlan"
        }
      }
    
  2. 节点运行时层
    DaemonSet生成的/run/flannel/subnet.env必须包含以下关键参数:

    FLANNEL_NETWORK=10.244.0.0/16
    FLANNEL_SUBNET=10.244.1.0/24
    FLANNEL_MTU=1450
    FLANNEL_IPMASQ=true
    
  3. CNI配置层
    /etc/cni/net.d/10-flannel.conflist需要与上述配置保持一致:

    {
      "name": "cbr0",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
    

去年我们在升级Kubernetes 1.24时遇到过一个典型问题:由于containerd配置未正确指向CNI路径,导致虽然所有文件都存在,但kubelet仍然报cni config uninitialized。这提醒我们配置检查必须包含运行时关联性验证。

3. 全链路诊断检查清单

基于数十次故障排查经验,我总结出以下诊断流程:

3.1 基础检查

# 检查kubelet基础状态
systemctl status kubelet -l

# 查看核心日志线索
journalctl -u kubelet --no-pager | grep -iE 'cni|network|flannel'

3.2 文件系统验证

# 检查Flannel环境文件
cat /run/flannel/subnet.env
stat -c '%a %U:%G' /run/flannel/subnet.env  # 权限应为644 root:root

# 验证CNI配置目录
ls -l /etc/cni/net.d/
jq . /etc/cni/net.d/*  # 验证JSON语法

3.3 网络平面测试

# 检查Flannel接口
ip -d link show flannel.1

# 测试Pod网络连通性
kubectl run --image=alpine testpod -- ping 8.8.8.8

关键提示:当使用VXLAN后端时,确保节点间UDP 8472端口互通。我曾遇到AWS安全组遗漏该端口导致Flannel无法建立overlay网络的案例。

4. 高级故障场景与解决方案

4.1 双栈网络配置陷阱

当启用IPv4/IPv6双栈时,Flannel配置需要特殊处理:

{
  "Network": "10.244.0.0/16,2001:db8:42:0::/56",
  "Backend": {
    "Type": "vxlan",
    "VNI": 4096,
    "Port": 8472
  }
}

同时需要更新subnet.env:

FLANNEL_NETWORK=10.244.0.0/16,2001:db8:42:0::/56
FLANNEL_SUBNET=10.244.1.0/24,2001:db8:42:0:1::/80

4.2 自定义MTU引发的血案

在某个使用巨型帧的数据中心环境中,我们设置了:

FLANNEL_MTU=9000

但却忘记在交换机端口做对应配置,导致分片丢包。正确的做法是:

# 先获取物理接口MTU
ETH_MTU=$(ip link show eth0 | awk '{print $5}')
# 设置Flannel MTU小50字节(VXLAN开销)
FLANNEL_MTU=$((ETH_MTU - 50))

4.3 多CNI插件冲突处理

当安装多个网络插件时,/etc/cni/net.d/下文件排序决定加载顺序:

# 确保Flannel配置优先
mv /etc/cni/net.d/10-flannel.conflist /etc/cni/net.d/00-flannel.conflist

5. 自动化验证方案

对于大规模集群,建议部署以下检查脚本:

#!/bin/bash
# 检查CNI基础配置
check_cni() {
  [[ -f /run/flannel/subnet.env ]] || {
    echo "Missing /run/flannel/subnet.env"
    return 1
  }
  
  source /run/flannel/subnet.env
  for var in FLANNEL_NETWORK FLANNEL_SUBNET FLANNEL_MTU; do
    [[ -n "${!var}" ]] || {
      echo "$var not set in subnet.env"
      return 1
    }
  done
  
  [[ -d /etc/cni/net.d ]] && [[ -n $(ls /etc/cni/net.d/*.conf*) ]] || {
    echo "No CNI config in /etc/cni/net.d"
    return 1
  }
}

将这个脚本加入节点的crontab或通过DaemonSet定期运行,可以提前发现配置漂移问题。

更多推荐