1. CNI 缓存基础概念
1.1 什么是 CNI 缓存
CNI(Container Network Interface)缓存是 Kubernetes 节点上 kubelet 与 CNI 插件之间的一层本地数据暂存机制。当 Pod 被调度到节点后,kubelet 会调用 CNI 插件为 Pod 配置网络接口。CNI 插件将每次网络配置的结果(如 IP 地址、路由、接口名称等)写入节点本地文件系统,形成缓存记录。
缓存文件通常存储在 /var/lib/cni/networks/ 或 /var/lib/cni/results/ 目录下,具体路径取决于 CNI 实现(如 Flannel、Calico、Weave 等)。
关键路径: 缓存文件是 CNI 插件与 kubelet 之间唯一的持久化状态载体。Pod 重启、节点重启或 CNI 插件升级时,缓存决定了网络配置能否快速恢复。
1.2 缓存的作用与价值
CNI 缓存并非可有可无的附属组件,它在 Kubernetes 网络栈中承担着三个核心职责:
- 状态持久化: 记录每个 Pod 已分配的网络资源(IP、MAC、路由表项),防止重复分配或资源泄漏。
- 快速恢复: 当 kubelet 或 CNI 插件重启后,缓存可跳过完整的网络配置流程,直接复用已有记录,将 Pod 网络恢复时间从秒级降至毫秒级。
- 冲突检测: 缓存中的 IP 分配记录可作为分布式锁,避免同一节点上两个 Pod 获取相同 IP 地址。
| 场景 | 无缓存 | 有缓存 |
|---|---|---|
| Pod 重启 | 重新执行 CNI ADD 流程,耗时 200-500ms | 直接读取缓存,耗时 < 1ms |
| 节点重启 | 所有 Pod 网络需重新配置,可能引发 IP 冲突 | 缓存恢复,IP 分配与重启前一致 |
| CNI 插件升级 | 旧 Pod 网络状态丢失,需重建网络接口 | 缓存保留,升级后无缝衔接 |
| 并发 Pod 创建 | IP 分配无锁,冲突概率高 | 缓存文件锁保证原子性 |
1.3 缓存命中与未命中的定义
在 CNI 缓存上下文中,“命中”与“未命中”描述的是 kubelet 调用 CNI 插件时,缓存能否提供有效网络配置记录的状态。
- 缓存命中(Cache Hit): kubelet 传入 Pod 的 UID 或 Sandbox ID,CNI 插件在缓存中找到完全匹配的记录,直接返回已保存的网络配置结果,跳过实际的网络接口创建与 IP 分配流程。
- 缓存未命中(Cache Miss): 缓存中不存在匹配记录,或记录已过期/损坏。CNI 插件必须执行完整的 ADD 流程:分配 IP、创建 veth 对、配置路由、设置 iptables 规则等。
性能差异: 缓存命中时 CNI 插件响应时间通常 < 1ms;缓存未命中时响应时间在 100ms-1s 之间,具体取决于网络插件复杂度与底层网络栈状态。
缓存未命中的常见原因包括:
- 缓存文件被手动删除或清理工具误删。
- Pod 的 Sandbox ID 发生变化(如容器运行时重启)。
- 缓存文件权限错误导致 CNI 插件无法读取。
- 缓存记录格式不兼容(CNI 插件版本升级后缓存结构变更)。
1.4 缓存命中率对集群性能的影响
缓存命中率是衡量 CNI 插件健康度的关键指标。低命中率会引发连锁性能问题:
- Pod 启动延迟增加: 每次未命中都意味着完整的网络栈初始化,在大规模集群中可能造成 Pod 启动队列堆积。
- IP 地址管理(IPAM)压力上升: 频繁的 IP 分配与释放操作增加 etcd 或本地 IPAM 的写入负载。
- 节点资源消耗升高: 完整的 ADD 流程涉及多次系统调用(netlink、iptables、ip link),CPU 和内存开销显著高于缓存命中。
注意: 缓存命中率并非越高越好。当 CNI 插件版本升级或网络策略变更时,旧缓存记录可能已失效。此时强制命中缓存会导致 Pod 网络配置与预期不一致,引发连通性问题。缓存应有合理的过期与失效机制。
下表总结了缓存命中与未命中的典型特征对比:
| 对比维度 | 缓存命中 | 缓存未命中 |
|---|---|---|
| 响应时间 | < 1ms | 100ms - 1s |
| 系统调用次数 | 1-2 次(文件读取) | 10-50 次(网络栈配置) |
| IP 分配 | 不涉及 | 需要分配新 IP |
| 网络接口操作 | 不涉及 | 创建/删除 veth 对 |
| iptables 规则 | 不涉及 | 可能需更新规则 |
| 故障风险 | 低(仅文件 I/O) | 中(系统调用可能失败) |