一、 Cilium 全景解析:历史、架构与应用
1.1 发展历史与演进历程
Cilium 是基于 Linux 内核核心技术 eBPF(Extended Berkeley Packet Filter) 构建的高性能开源网络、安全与可观测性平台,目前是云原生计算基金会(CNCF)的最高级别毕业项目。
-
诞生与早期探索(2016 - 2018): 由 Isovalent 公司联合创始人 Thomas Graf 等内核网络专家发起。旨在解决传统容器网络(CNI)依赖复杂
iptables或IPVS导致的规则膨胀与性能损耗问题,首次提出通过 eBPF 直接在内核层进行数据包路由与安全过滤。 -
云厂商的全面采纳(2019 - 2021): 伴随着可观测性组件 Hubble 的推出,GCP 选定 Cilium 作为其 Kubernetes Dataplane v2 的标准;AWS 与 Azure 随后也将其作为默认或推荐的 CNI 解决方案。
-
CNCF 毕业与生态确立(2021 - 2023): 2021 年 10 月加入 CNCF 托管,并于 2023 年 10 月正式毕业,标志着其成为云原生网络事实上的新一代标准。
-
企业级融合(2024 - 至今): 随着 Cisco 完成对 Isovalent 的收购,Cilium 被更广泛地推广至企业级数据中心、物理机(Bare Metal)及边缘网络管理领域。
1.2 核心系统架构
Cilium 的核心机制在于"将程序直接注入 Linux 内核中运行",从而绕过传统网络栈。系统由用户空间(User Space)与内核空间(Kernel Space)协同构成:
| 空间维度 | 核心组件 | 主要职责与运行机制 |
|---|---|---|
| 用户空间 | Cilium Agent | 运行在各节点上的守护进程,监听 K8s API,将网络与安全策略编译为 eBPF 字节码并加载进内核。 |
| 用户空间 | Cilium Operator | 集群级控制器,负责全局 IPAM 地址分配、垃圾回收及 Cluster Mesh 凭证同步。 |
| 用户空间 | Hubble | 可观测性平台,利用 eBPF 捕获网络流,提供实时的 L3/L4/L7 网络拓扑与诊断图谱。 |
| 内核空间 | eBPF Programs | 挂钩于 TC、XDP、cgroup socket 等钩子点,直接执行数据包路由、负载均衡与安全拦截。 |
| 内核空间 | eBPF Maps | 高效的高级 Hash 表/数组,用于用户空间 Agent 与内核空间之间同步连接状态与策略规则。 |
1.3 核心应用场景与使用方式
-
无 NAT 负载均衡(Socket-lb): 完全替换
kube-proxy,直接在 Socket 挂钩点完成 Service 流量拦截与转发,极大降低高并发下的网络延迟。 -
身份感知与 L7 细粒度安全: 不依赖易变的 IP 地址,而是基于 Pod 的 K8s Label(Identity)实施策略;支持针对 HTTP、gRPC、Kafka 等应用层协议的精确控制。
-
跨集群连接(Cluster Mesh): 在无需额外网关过渡的情况下,将多个分布在不同区域/公有云的 K8s 集群连接成一个扁平的 Pod 专用网络。
-
透明网络加密: 内置对 IPsec 与 WireGuard 的支持,无需修改任何应用代码即可实现节点间与 Pod 间流量的透明加密。
1.4 未来演进趋势
-
无 Sidecar 服务网格(Sidecarless Service Mesh): 推动 Ambient / eBPF + Node-Level Envoy 架构,消除传统 Sidecar(如 Istio)带来的大量 CPU/内存开销。
-
扩展至 Bare Metal 与 BGP 边缘控制: 结合强化的 BGP 控制平面与 Standalone L4 负载均衡,逐步接管数据中心物理交换机路由与边缘节点网络。
-
内核级 AI 安全防御: 结合 Tetragon(内核安全审计)与 Hubble,利用 AI 建模实时识别并动态阻断内核级别的异常行为与恶意连接。
二、 深度内核探讨:跨网络命名空间套接字迭代技术
以下为 2026 年 Linux 存储、文件系统、内存管理与 BPF 峰会(LSFMM+BPF Summit) 上关于 Cilium 高级 Socket 治理的最新前沿技术研讨报道:
Jordan Rife 的工作涉及为 Cilium 编写 BPF 程序,以使其与 Kubernetes 网络进行交互。作为该工作的一部分,他希望赋予 BPF 程序适当的权限,以便能够遍历不同网络命名空间(network namespace)中的套接字(socket)。在 2026 年 Linux 存储、文件系统、内存管理与 BPF 峰会上,他主持了一场围绕该想法的探讨会,与会的 BPF 开发者们敏锐地提出了一系列相关的替代方案。
Socket-lb 是 Cilium 的一项功能,它利用与特定控制组(cgroup)关联的套接字挂钩(hooks),在远程服务器之间实现连接的负载均衡,同时避免了网络地址转换(NAT)带来的逐包(per-packet)开销。在不使用 socket-lb 的架构中,客户端可能会向前端服务器发送请求,然后前端服务器通过 NAT 将连接透明地路由到选定的后端服务器。Socket-lb 在此基础上作出了改进:直接在客户端设备上透明地向用户空间(user space)进行路由,从而避免了 NAT 带来的额外网络跳数。Rife 表示,在实际应用中 socket-lb 存在一些局限性。例如,如果选定的后端服务器下线,流量仍会继续发送到该已不存在的后端,直到 Cilium 完成清理工作。目前,该软件通过使用 BPF 迭代器(iterators)遍历现有的套接字并在必要时将其销毁来实现清理。
这种方式虽然可行,但只能在特定的网络命名空间内起作用,因为命名空间之间是相互隔离的,无法看到彼此的套接字。在实践中,这意味着 Cilium 的用户空间组件必须进入主机上运行的每个 Kubernetes Pod 的命名空间,扫描其套接字,然后退出该命名空间并继续扫描下一个。这给整个过程带来了巨大的额外开销,而由于 Cilium 本就拥有对所有网络命名空间的管理权限,这种开销其实完全可以避免。
更糟糕的是,内核中的套接字并没有按照网络命名空间进行排序,因此每次 Cilium 的 BPF 程序进行扫描时,都必须遍历整个套接字哈希表;内核会在 BPF 程序看到这些套接字之前,将来自其他网络命名空间的套接字过滤掉。结果就是,Cilium 最终不得不为每个网络命名空间都将系统中的所有套接字列表遍历一遍,效率非常低下。Rife 表示,在他的工作实践中,单台计算机上曾出现过高达 256 个命名空间的情况。
他提出的解决方案很简单:创建一个具备适当特权的 BPF 程序可以使用的新迭代器,该迭代器可以一次性遍历系统中的所有套接字,甚至包括来自其他命名空间的套接字。这样一来,Cilium 就不需要切换网络命名空间了;只需使用 BPF 程序定期扫描整个系统的陈旧 socket-lb 套接字即可。
Jakub Sitnicki 询问,为什么 Rife 不直接维护一份套接字与后端对应关系的列表并直接使用它?BPF 程序可以将指向套接字对象的指针存储在套接字映射(socket map)中,套接字映射可用于存储弱引用(不增加套接字引用计数、因而不会阻止其关闭的指针)。因此,他指出,这种方案不会在套接字自然生命周期结束后还强行维持其存活。Rife 在 2025 年确实尝试过这种方法,但要让其发挥作用比预想的要复杂得多。在当前的内核中,BPF 程序无法在套接字映射迭代器的上下文中销毁套接字,因为这需要获取套接字的锁。要解决这个问题,需要重写大量围绕套接字访问的锁逻辑。
他表示,有一种变通方法是为 bpf_sock_destroy() 添加一个可睡眠(sleepable)的变体,由其自行获取套接字锁,这也是 Martin Lau 曾经向他建议过的。最终 Rife 放弃了这个想法,但如果他提出的"全机迭代器"方案不被接受,他可以重新考虑这个方向。Sitnicki 想知道为什么套接字映射迭代器一开始不是可睡眠的。Rife 并不清楚原因,不过他推测可能与 RCU(读-拷贝修改)和套接字锁之间的相互作用存在某种挑战有关。Lau 补充澄清道,许多 BPF 迭代器都是可睡眠的,只是套接字映射恰好存在这个问题。
Rife 的一位同事正在尝试在单独的映射中跟踪所有套接字的元数据,这也可能是一种变通方案。Rife 表示,另一种方法是让 bpf_sock_destroy() 本身能够直接在套接字映射迭代器的上下文中工作。但这在不增加引用计数(即增加内存开销)或不改变迭代器语义的前提下很难做到。不过在他看来,允许具备足够权限的 BPF 程序遍历所有网络命名空间,从各个方面来看都是一个简单得多的解决方案。
Daniel Borkmann 提到,BPF 维护者们曾讨论过添加一个针对网络命名空间的迭代器;他建议,或许可以将该迭代器返回的引用作为可信输入传递给套接字映射迭代器,这样就能在无需 Cilium 用户空间组件切换网络命名空间的情况下,让现有的套接字映射迭代器正常工作。Rife 则指出,这种做法依然会导致在内核内部多次遍历整台机器上的所有套接字。
Sitnicki 和 Lau 就当前代码如何查找网络命名空间引用以及潜在的改进方案进行了短暂的私下交流。Rife 同意对此进行研究并咨询网络维护者,但他观察到这依然无法解决他的效率问题。
John Fastabend 注意到,由于 BPF 套接字映射不可动态扩容("这很令人讨厌"),Cilium 在多处缓存了原始套接字指针。存储在 BPF 套接字映射中的套接字指针会在套接字销毁时自动清理;而将套接字指针作为不透明值存储在 BPF arena 中虽然在跟踪管理上方便得多,但无法自动清理且无法解引用。Sitnicki 指出,在 BPF arena 中存储套接字指针并不太适合 Rife 的使用场景。Fastabend 回应称这同样不太适合他的需求,但有充分的理由希望将套接字存放在更灵活的地方。他建议将 BPF 套接字映射修改为可动态扩容的形式。
Sitnicki 评论道,如果能够挂载 sockfs(一种允许用户使用文件系统 API 来管理套接字及权限的虚拟文件系统)并以这种方式钉住(pin)套接字,那就太好了。这样就可以完全不需要 BPF 映射了。Lau 点评说,有人正在开发一个与此切向相关的补丁,但他依然认为,能够像 Rife 建议的那样遍历所有内容会非常有用。
Sitnicki 询问,Rife 是否考虑过为可能消失的 UDP 后端进程获取重复的文件描述符(duplicate file descriptor),将其保存在守护进程中,并在需要清理时使用这些引用。Rife 解释说,他更希望整个过程都能在 BPF 内部完成。Fastabend 询问 TCP 套接字是否存在同样的问题。Borkmann 解释称,正常的 TCP 重置机制会处理这些问题,但只有在经历足够长的超时之后才会生效,而某些客户更倾向于 socket-lb 提供的更快速的故障转移,因此该方案同时应用于 UDP 和 TCP。
讨论至此便演变成了关于还有哪些其他应用可以潜在利用可动态扩容套接字映射的探讨,直到时间耗尽。尽管与会开发者对 Rife 的想法提出了诸多替代方案,但似乎无人持敌对态度,只是大家都在热衷于给"自行车棚"刷上不同的颜色而已。截至 8 月初,针对 Rife 的问题尚未有任何被正式接受的解决方案。
三、 总结与展望
从全局来看,Cilium 已经从早期单纯的 CNI 网络插件,蜕变成为掌控云原生数据平面安全、路由与可观测性的基础设施核心。而 Jordan Rife 在 LSFMM+BPF Summit 上引发的关于"全机 Socket 迭代器"的探讨,正是 Cilium 与 Linux 内核深度融合、相互推动演进的缩影。随着单节点容器密度的持续攀升,如何在 BPF 层面兼顾跨命名空间管理的效率与内核锁语义的安全性,将成为推动下一代 Linux 内核网络子系统升级的核心驱动力之一。
