2. CNI 插件架构:CNI 标准接口、容器运行时与网络插件的交互流程

容器网络接口(CNI, Container Network Interface)是 Kubernetes 生态中事实上的网络标准。理解 CNI 的架构设计,是排查网络缓存命中故障、分析 Calico 策略生效路径的前提。本节从接口规范、组件角色、交互流程三个维度展开。

2.1 CNI 标准接口规范

CNI 定义了一组 容器运行时 与 网络插件 之间的契约。该契约以 JSON 格式的配置文件、标准输入(stdin)参数和环境变量为载体,规定了插件必须实现的四个操作:

操作 方向 核心行为 典型触发场景
ADD 容器 → 网络 将容器加入网络命名空间,分配 IP、路由、接口 Pod 创建、Sandbox 启动
DEL 网络 → 容器 清理网络资源,释放 IP、删除 veth pair Pod 删除、Sandbox 销毁
CHECK 运行时 → 插件 验证容器网络状态是否与预期一致 kubelet 周期性同步、网络策略重评估
VERSION 运行时 → 插件 返回插件支持的 CNI 规范版本号 kubelet 启动时探测插件能力
关键约束:CNI 插件必须是独立的二进制可执行文件,运行时通过 exec 调用。插件不能依赖守护进程(daemon)常驻,但 Calico 等高级插件会通过 CNI 链式调用启动 Felix 等后台组件。

2.2 核心组件角色与职责

一次完整的容器网络接入涉及三个角色:

  • 容器运行时(Container Runtime):如 containerd、CRI-O。负责调用 CNI 插件,传递网络命名空间路径、容器 ID、网络配置等参数。
  • CNI 配置管理(Config Manager):通常由 kubelet 内置的 cniConfig 模块承担。读取 /etc/cni/net.d/ 目录下的配置文件,决定调用哪个插件及调用顺序。
  • CNI 插件(Plugin):分为三类:
    • Main 插件:负责创建网络设备(如 bridge、veth、ipvlan)。
    • IPAM 插件:负责 IP 地址分配(如 host-local、calico-ipam)。
    • Meta 插件:负责组合多个插件(如 flannel、calico 的 CNI 入口)。

2.3 交互流程:从 Pod 创建到网络就绪

下图展示了 kubelet 收到 Pod 创建请求后,容器运行时与 CNI 插件之间的完整交互路径:

CNI 插件交互流程:Pod 创建 → 网络就绪 kubelet 容器运行时 /etc/cni/net.d/ CNI 插件 网络命名空间 IP / 路由 / 接口 Sandbox 创建 读取配置 调用二进制 ADD 操作:创建 veth、分配 IP 返回结果 回写 IP / 路由 💡 缓存命中关键点: CNI 插件本身不缓存网络状态。但 Calico 的 Felix 组件会缓存策略规则和端点信息,若缓存未刷新,可能导致 ADD 操作返回过期的 IP 或路由。

2.4 链式调用与插件组合

Kubernetes 支持 CNI 链式调用(Chaining),即一个网络配置可以指定多个插件顺序执行。前一个插件的输出作为后一个插件的输入。以 Calico 为例,典型的链式配置如下:

{
  "cniVersion": "0.3.1",
  "name": "k8s-pod-network",
  "plugins": [
    {
      "type": "calico",
      "datastore_type": "kubernetes",
      "etcd_endpoints": "",
      "log_level": "info",
      "ipam": { "type": "calico-ipam" }
    },
    {
      "type": "portmap",
      "capabilities": { "portMappings": true },
      "snat": true
    },
    {
      "type": "bandwidth",
      "capabilities": { "bandwidth": true }
    }
  ]
}
故障排查提示:当容器网络缓存命中失败时,应优先检查链式调用中 第一个插件(通常是 Calico 主插件)的 ADD 操作是否成功。若主插件返回错误,后续的 portmap、bandwidth 插件将不会执行,导致 Pod 网络不可用。

2.5 交互流程中的关键数据结构

CNI 插件通过 标准输入(stdin) 接收网络配置,通过 环境变量 接收运行时上下文。以下是最核心的输入参数:

参数来源 参数名 说明 缓存故障关联
环境变量 CNI_CONTAINERID 容器唯一 ID Calico 用此 ID 查询端点缓存
环境变量 CNI_NETNS 网络命名空间路径(如 /proc/1234/ns/net) 路径错误会导致 ADD 操作失败
环境变量 CNI_IFNAME 容器内接口名称(通常为 eth0) 接口名冲突会触发缓存清理
stdin JSON ipam.type IPAM 插件类型 IPAM 缓存过期导致 IP 重复分配
stdin JSON capabilities 插件能力声明 能力不匹配导致链式调用中断

2.6 缓存故障在交互流程中的典型表现

结合 CNI 交互流程,容器网络缓存命中故障通常出现在以下环节:

  1. IPAM 缓存未刷新:Calico-ipam 在内存中缓存已分配的 IP 列表。当 Pod 快速创建/删除时,缓存可能未及时同步到 etcd,导致新 Pod 分配到已被占用的 IP。
  2. 端点缓存(Endpoint Cache)过期:Calico Felix 维护 WorkloadEndpoint 缓存。若缓存未随 Pod 生命周期更新,ADD 操作可能引用已删除的端点信息,造成路由错误。
  3. CNI 配置缓存:kubelet 会缓存 /etc/cni/net.d/ 目录的解析结果。修改配置后若不重启 kubelet,新配置不会生效,导致插件调用链与预期不符。
⚠️ 常见误区:不要将 CNI 插件本身的执行日志与容器运行时的日志混淆。排查缓存问题时,应同时查看 kubelet 日志(journalctl -u kubelet)和 calico-node 日志(kubectl logs -n kube-system calico-node-xxxx),对比两者对同一 Pod 的 ADD 操作记录。