2. CNI基础回顾:CNI规范、常见CNI插件架构对比、CNI与kubelet交互流程
2.1 CNI规范核心要素
容器网络接口(Container Network Interface, CNI)是 Cloud Native Computing Foundation(CNCF)旗下的一个项目,由一组规范和库组成,用于配置 Linux 容器的网络接口。其核心设计原则是“插件化”和“最小化”,不关心容器运行时本身,只关注网络配置。
| 规范要素 | 说明 | 关键字段/行为 |
|---|---|---|
| CNI 命令 | 插件必须实现的三个操作 | ADD、DEL、CHECK(可选) |
| 网络配置 | JSON 格式描述网络参数 | cniVersion、name、type、ipam、dns |
| 运行时参数 | 通过环境变量传递 | CNI_CONTAINERID、CNI_NETNS、CNI_IFNAME、CNI_ARGS、CNI_PATH |
| 结果输出 | 标准输出打印 JSON | cniVersion、interfaces、ips、routes、dns |
| IPAM 委托 | IP 地址管理可独立为子插件 | host-local、dhcp、static |
关键约束:CNI 插件必须是可执行二进制文件,kubelet 通过
exec 方式调用,插件必须在 CNI_PATH 指定的目录中。插件执行超时通常为 30 秒,超时后 kubelet 会重试或标记 Pod 失败。
2.2 常见CNI插件架构对比
当前 Kubernetes 生态中最主流的三个 CNI 插件是 Calico、Flannel 和 Cilium。它们在数据平面、控制平面、网络策略支持和性能特征上存在显著差异。
| 维度 | Calico | Flannel | Cilium |
|---|---|---|---|
| 数据平面 | Linux 内核路由 + iptables / eBPF | VXLAN / host-gw / UDP 隧道 | eBPF(内核态) |
| 控制平面 | BGP(Bird 或 Felix) | etcd 或 Kubernetes API | Kubernetes API + eBPF Map |
| 网络策略 | 原生支持(NetworkPolicy) | 不支持(需配合其他组件) | 原生支持(增强版,支持 L7) |
| 封装开销 | 无封装(纯路由)或 IPIP 封装 | VXLAN 封装(约 50 字节) | 无封装(直接路由) |
| 性能特征 | 高吞吐,低延迟(纯路由模式) | 中等吞吐,封装带来额外延迟 | 极高吞吐,极低延迟(eBPF 加速) |
| 运维复杂度 | 中等(需管理 BGP 或 IPIP 配置) | 低(配置简单,适合小规模) | 高(需内核 >= 5.10,eBPF 调试复杂) |
| 典型场景 | 大规模集群、混合云、需要精细策略 | 开发测试、小规模集群、快速部署 | 高性能场景、安全敏感、可观测性要求高 |
缓存命中率视角:Flannel 的 VXLAN 隧道模式在节点间通信时,数据包需要经过内核隧道处理,容易导致 conntrack 表项膨胀和缓存抖动。Calico 的纯路由模式依赖主机路由表,路由缓存命中率较高。Cilium 通过 eBPF 直接接管网络路径,绕过了传统 iptables 和路由缓存,在连接密集型场景下缓存命中率最优。
2.3 CNI与kubelet交互流程
kubelet 是 Kubernetes 节点上最核心的 agent,负责 Pod 生命周期管理。当 kubelet 需要为 Pod 创建网络时,会按照以下标准流程调用 CNI 插件:
- Sandbox 创建:kubelet 调用容器运行时(如 containerd)创建 Pod 的 network namespace(netns)。
- CNI 配置加载:kubelet 从
/etc/cni/net.d/目录读取 CNI 配置文件(通常为10-calico.conflist或10-flannel.conflist)。 - 环境变量组装:kubelet 设置
CNI_CONTAINERID、CNI_NETNS(指向 netns 路径)、CNI_IFNAME(通常为eth0)、CNI_ARGS(如IgnoreUnknown=1)、CNI_PATH(插件二进制目录)。 - 执行 ADD 命令:kubelet 在 netns 中执行
CNI_COMMAND=ADD的插件二进制,传递标准输入中的 JSON 配置。 - 插件处理:CNI 插件根据配置创建 veth pair、分配 IP(委托 IPAM)、设置路由、配置 iptables 或 eBPF 规则。
- 结果返回:插件将接口信息、IP 地址、路由和 DNS 配置以 JSON 格式打印到标准输出。
- Pod 网络就绪:kubelet 将结果写入 Pod 状态,容器运行时将
eth0移动到 Pod 的 netns 中。
缓存命中率关键点:在步骤 5 中,CNI 插件配置网络时,会创建 conntrack 条目、路由缓存和邻居表项。如果插件在
ADD 或 DEL 操作中频繁刷新 iptables 规则或路由表,会导致内核缓存抖动,直接影响后续数据包的缓存命中率。Cilium 通过 eBPF 将网络策略和转发逻辑下沉到内核态,避免了传统 iptables 规则遍历带来的缓存污染。
2.4 CNI 插件执行环境与缓存影响
CNI 插件在 kubelet 的上下文中执行,其执行环境对缓存命中率有直接影响:
- 进程隔离:每个 CNI 插件调用都是独立的进程,插件退出后其内存状态全部释放,无法跨调用共享缓存。
- 内核状态依赖:插件配置的 iptables 规则、路由表、邻居表、conntrack 表都是内核全局状态,插件之间的操作可能相互覆盖或冲突。
- 并发风险:kubelet 可能同时为多个 Pod 调用 CNI 插件,并发操作同一张内核表时,可能导致锁竞争和缓存失效。
- IPAM 缓存:IPAM 子插件(如
host-local)会在本地文件系统维护 IP 分配记录,频繁读写文件会影响整体延迟,间接影响缓存一致性。