☰
Cilium实战指南:基于eBPF的Kubernetes网络、安全与可观测性
2026/10/5 3:22:53 网站建设 项目流程

1. 为什么你的Kubernetes网络需要重新选型

不知道你是不是和我一样,被Kubernetes的网络插件逼出过选择困难症。早期大多数集群用的是Flannel,配置简单、通就万事大吉。后来规模一上来,发现Flannel在NetworkPolicy、性能以及可观测性这些维度上完全跟不上步伐,于是很多人转向Calico。可Calico同样有自己的历史包袱,它的iptables转发链路在大型集群里越来越吃力。直到Cilium出现,才真正让我感觉到“原来Kubernetes网络还能这么玩”。

Cilium是CNCF的毕业项目,整个项目围绕一个核心内核技术运作,那就是eBPF。它可以被理解成一套在Linux内核里安全地运行自定义代码的机制,Cilium通过它接管了节点的网络数据路径、安全策略,以及流量的可观测性。相比传统CNI依赖iptables、ipset这种规则匹配模型,Cilium把数据路径的查询过程压缩到了内核态里。这个区别在测试环境中不明显,一旦你跑一个有几百个节点、上万个Pod的生产集群,负载均衡的延迟、策略过滤的CPU消耗、排障时看流量的便捷性,差距会立刻体现出来。

这篇文章我想用一个工程实践者的视角来聊Cilium,不打算把官方文档复述一遍,而是把几个核心的“为什么”讲清楚:为什么它快,为什么它的安全模型和你之前理解的NetworkPolicy不一样,以及你在替换网络的实操中会碰到哪些坑。适合那些已经在使用Kubernetes、正准备优化集群网络的人,也适合刚接触容器网络、想做技术选型的人。

2. 核心技术拆解:eBPF凭什么成为Cilium的根基

2.1 给eBPF一个生活化的理解方式

eBPF这个词刚接触时非常劝退,看起来像是内核大神讨论的黑话。我一般这样跟团队解释:Linux内核原本是一个封闭的操作系统,普通进程只能通过系统调用和它打交道,就像你去银行柜台办业务,只能填指定的表单、走指定的窗口。而eBPF相当于给你发了一张临时通行证,允许你携带一段经过安全校验的脚本,挂载到内核内部特定的执行点,在这些点上面写出自己的处理逻辑。

这张通行证不是随便发的,eBPF程序在加载前会经过严格的验证器检查,它会检查代码是否存在死循环、是否访问了非法内存、是否可能把内核搞崩溃。通过检查之后,程序会被编译成字节码,再经过JIT编译成原生指令,直接跑在对应的事件触发点上。整个过程中数据不需要反复在内核态和用户态之间拷贝,这才是它性能强悍的根本原因。

Cilium做的事情,就是充分利用这种能力,把原本在用户态的代理逻辑,比如kube-proxy的负载均衡、NodePort的转发、NetworkPolicy的包过滤,全部下沉到内核里。你可以把Cilium理解为“在Linux内核里重新写了一套容器网络的转发引擎”。

2.2 Cilium在内核里的数据路径设计

传统数据路径通常是这样:一个数据包到达网卡,内核把它送到iptables规则链里,每一条规则都要遍历检查,一旦匹配了某条规则,就执行对应的target,比如DNAT或SNAT。问题是规则多了以后,这个线性匹配的代价非常高昂。CMB等网络的实践都验证过,当集群中Service数量超过数千个之后,iptables规则更新和包匹配的开销增长非常明显。

Cilium则完全不同。它利用eBPF的hook点,把数据包的解析、策略判定、转发决策,全部编程成在内核中维护的哈希表查询。举个例子,当一个Pod发起连接时,目标Service的ClusterIP和端口不需要再像iptables那样从第一条规则匹配到最后一条规则,而是直接在Cilium维护的BPF Map中做一次哈希查询,直接拿到后端真正的Pod IP,然后执行封装或转发。这个过程是常数级别的复杂度,且每次链路更新时,只需要更新对应的BPF Map,不需要重建整套规则,这带来了极快的数据路径更新速度。

MTU问题值得单独说。很多人部署Cilium时忽略MTU,结果集群之间数据包传输出现奇怪的问题。如果使用VXLAN封装,那么物理网络的MTU需要减去封装头部开销,通常设成1450左右,否则会出现分片和性能衰减。Cilium会尝试自动探测,但在某些云平台上自动探测的结果并不可靠。我的建议是直接根据你的网络环境确认物理链路MTU,减去50字节为VXLAN模式下的Pod MTU保底。

另一个理解Cilium内核布局的关键,是区分隧道模式和直路由模式。隧道模式适合底层网络不方便统一管理的场景,包通过VXLAN或者Geneve封装后,可以实现跨子网互通,但代价是额外封装导致CPU消耗增加。直路由模式依赖底层网络的路由能力,每个节点把自己子网的路由信息通告出去。生产环境我把超过八成集群都跑在直路由模式上,性能最好,排障也更直观。

2.3 为什么eBPF方案能在性能上全面胜出

有一个容易被人忽视的点是CPU占用率。传统CNI做负载均衡时,每个转发节点上都会有大量的netfilter规则,这些规则在被访问的时候会占用每个CPU核心的资源,尤其是有突发流量时,softirq会迅速跑满。Cilium把规则转化为Map查询后,相同的场景下消耗的CPU会少得多。这不是某个版本某个配置下的特殊结果,而是不同数据路径的执行模型决定的。eBPF在做包处理时采用的是事件驱动加预编译的原生代码执行,相比通过Netfilter框架的规则查找,天然少了很多上下文切换和系统调用开销。

还有一点,Cilium的负载均衡算法支持Maglev一致性哈希,这比普通的随机或轮询方式能更好地避免后端集合变化时的连接重映射。对于一个有大量长连接的业务,比如消息推送服务或者数据库中间层,这种稳定性提升是实打实的用户体验改善。

3. 核心能力全景:网络、安全、可观测性三位一体

3.1 网络功能:不止是替代kube-proxy

很多人在最初了解Cilium时,只知道它可以替代kube-proxy。这个说法没问题,但说实话,它更像是在说“特斯拉是一个可以替代燃油车的代步工具”,确实是对的,但远远不够。

Cilium除了支持ClusterIP、NodePort、LoadBalancer这些Service类型的负载均衡外,还支持DSR模式,也就是Direct Server Return。启用之后,入站请求会直接由后端Pod来回复客户端,不再绕行节点层的代理路径。这样回程路径少了跳数,延迟和带宽占用都明显改善。很多做高性能网关或者对时延极为敏感的业务,会选择开启这个功能。

Cilium还提供了带宽管理和流控能力。借助eBPF,你可以在容器网络栈里直接做带宽限制,不需要额外部署CNI插件或者QoS控制器。这种限制是在数据路径上直接标记的策略,能精确到单个Pod的某个方向。

还有个容易被忽略的是Cilium对IPv6的支持。它原生支持双栈,包括对IPv4和IPv6的负载均衡、策略和观察能力。如果集群未来要面向IPv6过渡,选型时可以省去很大的改造工作量。

3.2 安全模型:从IP地址信任升级到身份信任

传统的网络策略,比如Calico默认用IP作为安全对象,而Cilium引入了Security Identity的概念。每个Pod会在创建时,根据它的标签自动生成一个全局唯一的身份标识,网络策略规则是针对Identity的,而不是IP。这样带来的好处非常明显:IP会变,标签不会。Pod重启、漂移之后,只要身份没变,策略就能无缝生效。

Cilium的NetworkPolicy实现不仅兼容Kubernetes原生Ingress/Egress策略,还扩展了DNS策略,可以基于FQDN控制出站方向。也就是说,你可以允许Pod只访问外部的某个域名,而且默认情况下Cilium会代理解析DNS,再配合策略判定。这在做安全审计时非常有价值。

集群规模达到一定程度后,安全策略的维护本身就是个难题。Cilium提供Identity的全局视图,在Hubble的界面里可以看到每个Pod的身份和它们之间的流量关系。有一次我遇到一个诡异的问题:两个服务之间偶发超时,查了一圈Service和Endpoint都没问题,最后在Hubble依赖图里发现流量竟然经过了我们不希望出现的一个中间节点。这种问题在视觉化工具出现之前,排查成本非常高。

3.3 可观测性:Hubble的前世今生

Cilium的可观测性组件叫Hubble,它的作用是实时捕获节点上的网络流信息,并具有查询、过滤、预警的能力。你不需要在生产环境再额外部署一套抓包系统或者第三方网络监控,只要开启Hubble,就能看到每条TCP流基于身份的源和目的、使用的端口、吞吐量、剩余TTL等。

Hubble的UI很直观。你可以看到集群内Pod之间的通信关系图,也可以针对某个命名空间做时间线回放。它还能和Prometheus集成,导出标准的网络监控指标。生产上如果遇到“某个Pod偶尔特别慢”这类网络问题,我通常先打开Hubble,筛选源IP、目标IP,结合时间跨度查看丢包率和RTT。这样能在五分钟内缩小问题范围,而不是跑到每台机器上抓tcpdump。

eBPF提供的观测数据是一层独立于应用的文件描述符的视角。应用不感知,也不需要插桩,但内核已经悄悄记录了完整的网络行为。这是传统抓包方式之外最干净、成本最低的一种观测手段。

4. 实操:从零部署Cilium并跑通关键安全功能

4.1 环境准备与预检项

先说一个很多人会踩的坑:拿一台老内核节点直接装Cilium,结果安装Pod一直CrashLoopBackOff,报一些看不懂的BTF错误。Cilium依赖较新的内核特性,如果你的内核低于4.19,很多功能,包括bandwidth manager、eBPF Host Routing都无法使用。生产环境我建议至少使用5.x内核,版本太低建议先做内核升级再继续。

安装前检查内核版本:

uname -r

如果输出是3.10之类的版本,强烈不建议硬着头皮继续。你当然可以在某些模式下降级使用,但会失去Cilium大半优势,不如直接用Calico或Flannel省事。另外确认节点支持BTF,Cilium能通过BTF自动生成适合当前内核的eBPF代码。执行:

ls /sys/kernel/btf/vmlinux

如果文件不存在,需要根据内核版本和发行版安装对应的内核开发包,或者手动开启BTF支持。此外还要检查Mount BPF文件系统。正常情况下Cilium会帮你完成相关配置,但如果你启用了一些安全加固程序,比如AppArmor或者SELinux配置限制了挂载,也必须提前处理。

4.2 使用Helm完成安装

我习惯用Helm管理Cilium版本,升级和回滚都比较稳妥。先添加仓库:

helm repo add cilium https://helm.cilium.io/

然后准备安装参数。我这里列一个生产环境常用的配置模板,你按自己的情况增删:

helm install cilium cilium/cilium --namespace kube-system \ --set routingMode=native \ --set kubeProxyReplacement=true \ --set bpf.masquerade=true \ --set ipam.mode=kubernetes \ --set hubble.relay.enabled=true \ --set hubble.ui.enabled=true \ --set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,http}" \ --set l7Proxy=true \ --set cgroup.autoMount.enabled=false \ --set cgroup.hostRoot=/sys/fs/cgroup

注意其中的routingMode字段,我这里指定的是原生路由模式。如果你的网络环境不支持跨子网路由,就得改用tunnel模式,同时要根据VXLAN默认开销调整MTU。kubeProxyReplacement=true的意思是让Cilium完全接管原本kube-proxy处理的转发任务,安装后不建议再保留kube-proxy的DaemonSet。

安装完成后,先看Pod部署情况:

kubectl -n kube-system get pods -l k8s-app=cilium

等所有Agent处于Running状态后,用Cilium CLI检查状态:

cilium status

正常时会看到类似“KubeProxyReplacement: True”、“BPF Masquerade: Enabled”之类的信息。如果某个模块异常,状态会直接标出来,按提示逐项排查即可。

4.3 跑通Connectivity Test

Cilium自带一套端到端的连通性测试,覆盖面非常全,包括跨节点通信、DNS解析、NodePort访问等。这条命令值得你在任何一次安装或升级之后都跑一遍:

cilium connectivity test

它会临时创建一批带特定标签的Pod,然后执行数百项网络场景验证。第一次跑的时候耗时比较久,耐心等。结果会按通过、失败、跳过分组。最怕的是出现突发性失败,通常和网络策略的FQDN相关,因为测试Pod偶尔需要访问外部地址。也可以加上--include-unsafe跑更多边缘场景。

如果测试全绿,那么恭喜,你的集群网络已经跑在eBPF的数据路径上了。

4.4 实战配置一个FQDN-Based安全策略

安全策略是最能体现Cilium差异化的部分。来看一个实际场景:运维团队希望只允许某个线上服务访问外部的对象存储域名,其他出站流量全部拒绝。

先创建CiliumNetworkPolicy,只允许从应用Pod访问对象存储域名:

apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: allow-s3-egress namespace: production spec: endpointSelector: matchLabels: app: file-transfer egress: - toFQDNs: - matchName: "s3.amazonaws.com" toPorts: - ports: - port: "443" protocol: TCP

这个策略会直接体现在每个Pod的CiliumEndpoint上。过几分钟你就能在Hubble界面里看到该Pod的出站流量,以及哪些被策略放行,哪些被Drop。调试时甚至可以临时给策略加一个label和description,方便在Hubble中按策略维度过滤。

有一个细节:DNS服务器地址需要保持正常。Cilium做FQDN策略时依赖DNS查询。如果你的Pod内配置了非集群DNS或者自定义DNS解析,策略可能无法正常匹配域名。启动事件里看到类似“DNS proxy”报错,先检查解析链路。

5. 避坑指南:生产环境实战中踩过的典型坑

5.1 内核版本兼容性的老生常谈

我在一次升级测试中,曾把内核从4.19一下子跳过到5.4,结果原本正常的所有节点都出现“dropped by ebpf policy”的流量丢失。后来排查发现,是内核变化导致了BTF信息变更,Cilium的Agent自动重新编译了eBPF程序,但部分编译参数与新内核不完全对齐,导致策略行为产生了不同。这种问题在线上环境极难排查,因为流量不是完全不通,而是偶发性丢包。

建议是:任何内核变更,包括内核小版本升级,都必须在测试环境重跑一次cilium connectivity test。另外升级Cilium和升级内核不要同时进行,一次只动一个变量。

5.2 kube-proxy替换时的误区

把kube-proxy摘掉这件事,很多人以为只是关掉一个Deployment。实际上Cilium还需要接管一部分原本由kube-proxy维护的NodePort和ExternalTrafficPolicy逻辑。如果参数配置不一致,会出现集群外部访问Service时偶尔不通。

我常用的处理方式:保留kube-proxy容器暂停,不直接删除,等验证完所有外部访问链路后再彻底移除。另外要确认各节点的kube-proxy标记是否清理干净。Cilium接管后,你会在节点上看到很多名为from-container的eBPF程序,这是正常现象。

5.3 MTU引起的体验劣化

MTU问题在云环境里最容易阴沟翻船,因为你总以为云厂商网络会自动协商。实际上,当启用隧道模式后,如果Cilium采用的MTU与实际物理链路不一致,会出现两个Pod可以互联,但大包传输超时、小包传输正常的情况。表现非常迷惑,会让人觉得是应用层的问题。

排查手段很简单:在故障Pod内ping对端Pod的IP,同时限制包大小,对比:

ping -M do -s 1372 <target-pod-ip> ping -M do -s 1400 <target-pod-ip>

如果1400字节的包失败,1472字节的正常,基本可以确认是MTU配置小了。把Cilium配置里的mtu参数与物理链路对齐即可。

5.4 排障速查表

我整理了一张表格,遇到问题可以直接对照,能省去不少查文档的时间。

现象可能原因排查手段
安装后Agent CrashLoop内核过老、BTF缺失检查uname -r,确认BTF文件存在
跨节点通信时断时通MTU不匹配ping -M do对比测试
外部访问Service超时kube-proxy未完全卸载检查kube-proxy标记
Hubble页面无数据Relay未启动、指标未开启检查hubble.relay.enabled和metrics配置
策略放行后流量仍被DropIdentity未刷新、DNS缓存重启测试Pod,重建Endpoint
性能下降剧烈误开了隧道模式且底层网络是VPC切换为native路由模式
升级后安全策略失效策略命名空间和Pod标签变更在Hubble中按策略ID过滤流量

6. 最后再分享一点我的实际体会

Cilium这个项目最打动我的地方,不是某个单项指标最强,而是它把“网络、安全、可观测性”三条线统一到了一套架构里。过去你要装Flannel解决连通、装Calico解决策略、抓tcpdump分析问题,现在一个Cilium加一套Hubble全部覆盖,且每一项都做得足够深入。

如果你是第一次接触,不用被那一大堆eBPF概念吓到。先按文中的步骤部署起来,跑通connectivity test,再用Hubble看看集群内的流量地图,你会很快理解它到底解决什么问题。等真正进入排障场景时,那种“一眼看到问题根因”的体验会让你觉得这次技术的切换非常值得。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询