Cilium 实战:用 eBPF 和 XDP 终结 iptables 的容器网络性能困境

Kubernetes 集群中,Pod 数量增长后 iptables 的链式匹配会急剧消耗 CPU,导致网络延迟飙升。Cilium 基于 eBPF 和 XDP 技术,在内核中直接执行数据包处理程序,彻底绕过 iptables 架构。本文面向小白,拆解问题根源、关键技术原理,并给出可上手的部署验证步骤。

Cilium 实战:用 eBPF 和 XDP 终结 iptables 的容器网络性能困境
封面图:ZuCDN · ZuCDN 原创

如果你正在处理Cilium eBPF,先别急着照搬网上的参数。当你第一次成功部署 Kubernetes 集群,看着 Pod 一个个启动,网络通信顺畅无比时,可能觉得容器网络没什么大不了的。但一旦集群规模扩大——比如 200 个节点、上万条网络策略规则——传统的 iptables + kube-proxy 模式就会暴露出严重的性能问题:CPU 飙升、连接延迟忽高忽低、甚至节点陷入半死不活的状态。这正是 Cilium 被越来越多团队选中的原因。它的核心手段是 eBPF 和 XDP,让数据包处理从“内核态规则遍历”变成了“内核级即时裁决”。这篇文章只讲原理和落地,不扯玄学。

Cilium eBPF:传统 iptables 到底卡在哪里?

链式遍历:规则越多,开销越大

Kubernetes 通过 kube-proxy 在节点的 Netfilter 框架中插入大量 iptables 规则,实现 Service 负载均衡、网络策略过滤。每个进入节点的数据包都需要经过 NAT 表、Filter 表的多条链,而每条链上的规则是按顺序匹配的。当规则数量从几十条增长到几千条时,数据包在每个节点上的匹配时间会线性甚至超线性增加。实际线上环境,5000 条规则时 kube-proxy 的 CPU 占用可能达到 2-3 核,转发延迟从微秒级跳到毫秒级。

内核态与用户态上下文切换

iptables 规则每增加或修改一次,都会触发 iptables-restore 将所有规则重新加载到内核中,这个过程中用户态和内核态频繁切换,同时会锁住 Netfilter 子系统,导致短暂的数据包处理停顿。在需要频繁更新 Endpoint 的高密度 Pod 场景下,这种停顿可以被明显感知。

桥接问题:容器网络还多一层桥接

大部分 CNI 插件(如 Calico、Flannel)在节点上创建网桥(cbr0 或 docker0),容器流量先经过网桥,再经过 iptables 做 SNAT 或策略过滤。网桥本身对二层处理有一定损耗,再加上 iptables 的三层处理,整个转发路径长且不可控。

eBPF:让内核变成可编程的“微型应用商店”

eBPF 不是补丁,而是一套虚拟机

Linux 内核从 4.x 就开始集成 eBPF(extended Berkeley Packet Filter)。你可以把它理解成内核内部的一个沙箱化虚拟机——允许用户编写一段 C 或 Rust 代码,编译成 BPF 字节码后,安全地加载到内核的特定 Hook 点(如系统调用、网络设备、函数入口)。代码运行在内核态,但受验证器严格检查:不得有死循环、不得访问未授权的内存、不得执行特权指令。所以既快又安全。

为什么 eBPF 能绕过 iptables?

传统 iptables 是 Netfilter 框架的一个用户配置接口,数据包要经过很多预定义的 Hook 点。而 eBPF 程序可以直接挂载到网络设备(包括虚拟以太网对、网桥、物理网卡)的 tc(Traffic Control)层或 XDP(eXpress Data Path)层。换句话说,eBPF 在网络栈的最前端就拦截数据包,根本不给数据包走到 Netfilter 链条的机会——自然也就绕过了 iptables 的所有开销。

XDP:在网卡驱动里就把活干了

XDP 比 eBPF 更“早”

XDP 是 eBPF 的一个特殊 attach 类型,它运行在网络驱动接收数据包之后、内核协议栈处理之前。也就是说,数据包还在 RX 环上时,XDP 程序已经可以决定:丢弃、转发到另一个网口、提交给上层、还是修改数据包内容。由于不经过协议栈的 skb(套接字缓冲)分配和一系列的 Netfilter 检查,XDP 能达到线速处理,单核吞吐可达几十 Mpps(百万包每秒)。

XDP 对比 iptables 的转发路径

  • 传统路径:网卡 -> 驱动 -> skb 分配 -> 协议栈(IP、TCP)-> Netfilter 钩子(iptables)-> 路由 -> 网卡发送。
  • Cilium + XDP 路径:网卡 -> 驱动 -> XDP 程序(eBPF)-> 重定向到目标网卡(或虚拟网卡)-> 驱动发送。

这个差异在容器网络里尤其明显。节点上的每个 Pod 的 veth 对都可以被 XDP 程序接管,数据包从 Pod 出来的一瞬间就被 Cilium 决定去哪,而不需要经过任何 bridge 和 iptables 规则。

Cilium 的架构设计:如何组织 eBPF 和 XDP?

Cilium Agent 是大脑,eBPF 是手脚

Cilium 在每个节点上运行一个 Agent(通常以 DaemonSet 部署)。这个 Agent 负责与 Kubernetes API Server 交互,收集 Service、Endpoint、NetworkPolicy 等信息,然后编译成对应的 eBPF 程序(C 代码)并加载到内核。它本身不处理数据包,只负责管理 eBPF 对象。

数据面:三种 Hook 点协同

  • XDP:用于入口流量(Ingress),直接挂载在物理网卡或 veth 对的主机端。适合做 DDoS 防护、负载均衡的快速重定向。
  • TC Ingress/Egress:在协议栈的 tc 层挂载 eBPF,用于处理更复杂的逻辑(如 L7 协议过滤、IP 伪装)。Cilium 默认使用 tc 作为主力数据面,因为它的 API 更容易操作 skb。
  • cgroup 挂载点:用于限制特定 cgroup 中进程的网络访问,主要用于安全策略。

用 Map 代替规则列表

传统 iptables 使用链表存储规则,匹配时遍历。Cilium 使用 eBPF Map(哈希表或数组),查表时间复杂度 O(1)。例如,流量策略记录在 bpf_policy_map 中,数据包到达时直接 key 查找,秒级匹配。当 Service Endpoint 变更时,Agent 只更新 Map 条目,不需要重载整个规则集,更新开销可忽略不计。

上手体验:用 kind 启动 Cilium 集群——Cilium eBPF

环境准备

确保你的 Linux 内核版本 ≥ 5.10(建议 5.15+)。使用 kind(Kubernetes in Docker)快速搭建测试集群:

kind create cluster --name cilium-demo

安装 Cilium

cilium install --version 1.15.0 --set kubeProxyReplacement=true

kubeProxyReplacement=true 是关键配置:完全接管 kube-proxy 的职责,关闭节点上的 iptables 转发。

验证 eBPF 数据面是否生效

cilium status --verbose

你会看到类似如下输出:

...
╟ Host Routing: Legacy
╟ KubeProxyReplacement: Disabled (iptables mode disabled: eBPF mode enabled)
╟ Bandwidth Manager: Enabled with EDT
...

同时可以查看挂载的 eBPF 程序:

bpftool prog list | grep cilium

你会看到一系列 cil_* 命名的程序,挂载在 tc 和 xdp 上。

测试网络延迟变化

部署一个测试 Pod:

kubectl run test --image=busybox -- sleep 3600

在 Pod 内执行 ping 外部 Service,观察延迟:

ping 10.96.0.1 (kubernetes service IP)

对比传统 iptables 模式(可以临时用 kube-proxy 重跑测试),你会发现延迟抖动明显减少,尤其是在 Service 名称解析和连接建立阶段。

风险与回滚:从 iptables 切换到 eBPF 需要注意什么?

内核版本兼容性

Cilium 1.15 要求内核 ≥ 4.19,但 XDP 降级功能会受限;推荐 5.10 以上。如果你的节点使用的是 CentOS 7(内核 3.10),基本无法运行 Cilium 的 eBPF 数据面,必须考虑升级内核。

kubeProxyReplacement 的副作用

开启完全替换后,节点上的 iptables 将不再用于 Kubernetes 流量。如果你有第三方工具也依赖 iptables(比如某些网络监控 agent、手动配置的 DNAT 规则),它们会失效。建议先在测试环境验证所有依赖。

回滚方案

cilium uninstall
kubeadm upgrade node ... 或重新启用 kube-proxy

Cilium 卸载后 eBPF 程序自动释放,节点恢复使用 iptables。注意 CNI 配置文件也会被清理,重新安装 kube-proxy 即可。

总结:无 iptables 开销不是魔法,是内核工程取舍

先看关键判断

Cilium 并没有发明新硬件,而是把 Linux 内核自 2014 年就开始提供的 eBPF 能力真正用到了容器网络场景。它牺牲了 iptables 的通用性(任何用户都能写规则),换取了极高的性能和灵活性。对于日均千万级连接或超大规模集群来说,这个取舍非常值得。下一次当你面对 kube-proxy 导致的性能瓶颈时,别再想着拷打运维加机器了——试试 Cilium,把数据包处理权从小黑屋的 iptables 手里夺回来。按这个顺序复查,Cilium eBPF遇到异常时也更容易定位。

延伸阅读