Cilium网络策略与Serverless性能调优实战 - 第4节
4.1 Pod 网络模型与 Cilium 的 CNI 实现
Kubernetes 的 Pod 网络模型要求每个 Pod 拥有独立的 IP 地址,且所有 Pod 之间可以不通过 NAT 直接通信。Cilium 作为基于 eBPF 的 CNI 插件,在实现这一模型时绕过了传统 iptables 和网桥方案,直接在网络栈的内核层完成数据包转发。
4.1.1 传统 Pod 网络 vs Cilium eBPF 路径
| 对比维度 | 传统方案(Flannel/Calico iptables) | Cilium eBPF |
|---|---|---|
| 数据路径 | 网桥 → iptables → 路由 → 隧道/veth | 直接 eBPF 程序挂载 tc/XDP |
| 网络策略 | iptables 规则链,O(n) 匹配 | eBPF map 哈希查找,O(1) |
| Service 转发 | kube-proxy + iptables/IPVS | eBPF 原生 DSR 或 kube-proxy 替代 |
| 延迟开销 | 多次内核态/用户态切换 | 单次 eBPF 程序执行 |
| 连接跟踪 | conntrack 模块 | eBPF map 自定义跟踪 |
关键结论:Cilium 通过 eBPF 将网络策略、Service 转发、负载均衡全部下沉到内核的 eBPF 虚拟机中执行,消除了 iptables 规则遍历和多次上下文切换的开销。
4.1.2 Cilium 的 Pod 网络数据路径
当 Pod 发送数据包到同一节点或跨节点 Pod 时,Cilium 的数据路径如下:
- 出站方向:Pod 的 veth 对端(cilium_host)触发 eBPF 程序(tc ingress)。
- 策略检查:eBPF 程序查询
cilium_policymap,判断源/目的身份是否允许通信。 - 封装/路由:跨节点时通过 VXLAN/Geneve 隧道或直接路由(Native Routing)转发。
- 入站方向:目标节点 eBPF 程序解封装后,将数据包交付到目标 Pod 的 veth 端。
# 查看 Cilium 为 Pod 分配的 identity
kubectl exec -n kube-system cilium-xxxxx -- cilium endpoint list
# 输出示例:
# ENDPOINT IDENTITY LABELS IP NODE
# 1234 167 k8s:app=frontend 10.0.1.5 node-1
# 5678 289 k8s:app=backend 10.0.2.8 node-2
身份标识(Identity):Cilium 不依赖 IP 地址做策略匹配,而是为每个 Pod 分配基于标签的 Security Identity。即使 Pod 重启 IP 变化,策略依然生效。
4.2 Service 负载均衡:DSR 模式与 kube-proxy 替代
Cilium 提供了两种 Service 负载均衡模式:kube-proxy 替代模式和DSR(Direct Server Return)模式。两者都基于 eBPF 实现,但转发路径和性能特征不同。
4.2.1 kube-proxy 替代模式
Cilium 可以完全替代 kube-proxy,通过 eBPF 程序在节点网络接口上直接处理 Service 流量。相比 iptables 模式,它消除了 DNAT 规则链遍历和 conntrack 表竞争。
# 启用 Cilium 的 kube-proxy 替代
helm upgrade cilium cilium/cilium --namespace kube-system \
--set kubeProxyReplacement=true \
--set k8sServiceHost=192.168.1.100 \
--set k8sServicePort=6443
# 验证 kube-proxy 已被替代
cilium status | grep "KubeProxyReplacement"
# 输出:KubeProxyReplacement: Strict [eth0 192.168.1.10]
| 特性 | kube-proxy iptables | Cilium kube-proxy 替代 |
|---|---|---|
| 规则存储 | iptables 链表,O(n) 遍历 | eBPF map,O(1) 哈希查找 |
| 连接跟踪 | Linux conntrack(全局锁竞争) | eBPF per-CPU map(无锁) |
| 更新延迟 | iptables-restore 全量刷新(秒级) | eBPF map 原子更新(毫秒级) |
| CPU 开销 | 高(规则越多开销越大) | 低(恒定 O(1)) |
4.2.2 DSR(Direct Server Return)模式
DSR 模式的核心思想是:入站流量经过负载均衡节点,但返回流量直接从后端 Pod 返回客户端,避免负载均衡节点成为瓶颈。Cilium 通过 eBPF 在数据链路层实现 DSR,无需修改 IP 头。
DSR 优势:减少负载均衡节点的带宽压力,降低延迟,特别适合 Serverless 场景下大量短连接请求。
# 启用 Cilium DSR 模式
helm upgrade cilium cilium/cilium --namespace kube-system \
--set kubeProxyReplacement=true \
--set loadBalancer.mode=dsr \
--set loadBalancer.dsrDispatch=ipip
# 查看 DSR 是否生效
cilium status | grep "DSR"
# 输出:DSR: Enabled
4.3 eBPF 数据路径详解
Cilium 的核心竞争力在于其 eBPF 数据路径。理解 eBPF 程序在数据包处理流程中的挂载点和执行逻辑,是掌握 Cilium 网络性能优化的基础。
4.3.1 eBPF 挂载点:XDP 与 tc
Cilium 在两种内核钩子处挂载 eBPF 程序:
- XDP(eXpress Data Path):在网络驱动层、SKB 分配之前执行,性能最高,适合 DDoS 防护和早期丢弃。
- tc(Traffic Control):在协议栈处理之后、SKB 分配之后执行,功能更丰富,适合策略执行和转发。
| 挂载点 | 执行时机 | 延迟 | 适用场景 |
|---|---|---|---|
| XDP | 网卡驱动层,SKB 分配前 | < 1μs | DDoS 防护、包过滤、负载均衡 |
| tc ingress | 协议栈处理,SKB 分配后 | 1-3μs | 网络策略、Service 转发、封装/解封装 |
| tc egress | 协议栈处理,SKB 分配后 | 1-3μs | 出站策略、带宽管理 |
4.3.2 eBPF 程序执行流程
以 Pod 访问 Service 为例,Cilium 的 eBPF 程序执行以下步骤:
- XDP 程序(可选):检查源/目的 MAC,如果是已知 Service IP,直接重定向到后端 Pod 的 MAC。
- tc ingress 程序:解析 IP 头,查询
cilium_lb4_services_v2map 获取后端列表。 - 负载均衡选择:使用 Maglev 一致性哈希算法选择后端,查询
cilium_lb4_backends_v2map 获取后端 IP。 - 封装/转发:如果是跨节点,通过 VXLAN 封装;同节点直接修改 MAC 转发。
- 策略检查:查询
cilium_policymap,验证源身份是否允许访问目标身份。
// 简化版 eBPF 程序:Service 负载均衡查找
// 完整代码见 cilium/bpf/lib/lb.h
static __always_inline int __lb4_lookup(struct __ctx_buff *ctx,
struct ipv4_ct_tuple *tuple,
struct lb4_service *svc,
struct lb4_backend *backend,
__u32 *cluster_id)
{
// 1. 从数据包中提取 Service IP 和端口
tuple->daddr = ip4->daddr;
tuple->dport = bpf_ntohs(tcp->dest);
// 2. 查询 Service map
struct lb4_key key = {
.address = tuple->daddr,
.dport = tuple->dport,
};
svc = map_lookup_elem(&cilium_lb4_services_v2, &key);
if (!svc)
return CTX_ACT_OK; // 非 Service 流量,直接放行
// 3. Maglev 一致性哈希选择后端
backend_id = maglev_lookup(svc, tuple->saddr, tuple->sport);
backend = map_lookup_elem(&cilium_lb4_backends_v2, &backend_id);
// 4. 修改目标 IP 为后端 Pod IP
ctx_store_bytes(ctx, offsetof(struct iphdr, daddr),
&backend->address, 4, 0);
return CTX_ACT_REDIRECT;
}
性能注意事项:eBPF 程序必须在内核验证器允许的指令数内完成(初始 4096 条,5.x 内核可扩展)。Cilium 通过 tail call(尾调用)将复杂逻辑拆分为多个 eBPF 程序,避免单程序超限。
4.3.3 eBPF map 与数据共享
Cilium 使用多种 eBPF map 在 eBPF 程序与用户态守护进程之间共享数据:
| Map 名称 | 类型 | 用途 |
|---|---|---|
| cilium_lb4_services_v2 | 哈希 | 存储 Service IP 到后端列表的映射 |
| cilium_lb4_backends_v2 | 哈希 | 存储后端 Pod IP 和端口 |
| cilium_policy | 哈希 | 存储网络策略规则(身份 → 允许列表) |
| cilium_ct4 | LRU | 连接跟踪表,记录五元组和状态 |
| cilium_metrics | 数组 | eBPF 程序统计计数器(丢包、转发等) |
性能调优建议:在 Serverless 场景下,建议启用 XDP 加速(
loadBalancer.acceleration=native)并配合 DSR 模式,可将 Service 转发延迟降低至 1μs 以下。同时监控 cilium_metrics map 中的丢包计数器,判断是否需要调整 eBPF map 大小。