IT大白鼠@青鸟扫地僧头像
关注

Cilium技术架构与eBPF基础研究:基于Kubernetes的高性能网络、安全与可观测性解决方案

摘要

Cilium作为基于eBPF技术的Kubernetes网络、安全与可观测性一体化解决方案,由Isovalent创建,现为CNCF毕业项目。它利用eBPF在Linux内核中动态注入字节码,实现高性能网络数据路径、深度可观测性和身份感知的安全策略执行,已成为云原生网络领域的事实标准。本文系统研究Cilium的技术架构、性能优势和应用场景,深入分析其基于eBPF的核心技术原理,为云原生架构师和Kubernetes管理员提供全面的技术认知和实践指导。

关键词

Cilium、eBPF、Kubernetes、网络策略、安全防护、可观测性

一、引言

随着云原生技术的快速发展,Kubernetes已成为容器编排领域的事实标准,但其网络层一直是复杂性和性能瓶颈的集中地。传统网络插件依赖复杂的iptables、路由表和额外代理来实现流量控制、安全策略和流量可视化,这不仅增加了系统复杂性,也难以满足现代云原生环境对高性能、高安全性和深度可观测性的需求。在这一背景下,Cilium作为基于eBPF(Extended Berkeley Packet Filter)技术的创新解决方案应运而生,彻底重塑了Kubernetes网络与安全架构。

Cilium项目始于2015年12月16日的第一次提交,从一个实验性的IPv6容器网络项目逐步发展为云原生世界的CNI(容器网络接口)事实标准。作为CNCF(Cloud Native Computing Foundation)的毕业项目,Cilium已被Adobe、Google、Meta等全球顶尖科技公司在生产环境中大规模部署。其核心优势在于利用Linux内核中的eBPF技术,动态地将安全、可观测性和网络控制逻辑注入到操作系统内核中,无需修改内核源码或加载内核模块即可实现高性能的网络处理和深度安全防护。

eBPF技术起源于2014年,作为Linux内核的一项革命性通用执行引擎,允许开发者编写安全、高效的程序并动态加载到内核空间执行。随着Linux内核版本4.19及以上将eBPF作为标准能力,eBPF已从最初的网络包过滤器发展为覆盖系统调用、文件系统、安全框架等多个领域的通用内核编程框架。Cilium正是基于这一技术,为云原生环境提供了高性能、高安全性和深度可观测性的完整解决方案,成为连接传统网络架构与未来云原生基础设施的关键桥梁。

本文将从eBPF技术基础入手,深入解析Cilium的技术架构、核心组件和工作原理,系统分析其网络功能与性能优势,全面研究其安全策略与可观测性功能,并探讨其实际部署与应用场景,旨在为云原生架构师和Kubernetes管理员提供全面的技术认知和实践指导,助力构建更加高效、安全、可观测的云原生基础设施。

二、eBPF技术基础与工作机制

eBPF(Extended Berkeley Packet Filter)作为Linux内核的革命性通用执行引擎,为Cilium提供了坚实的技术基础。这项起源于2014年的技术,通过在Linux内核中运行沙盒程序,允许开发者编写安全、高效的程序并动态加载到内核空间执行,无需修改内核源码即可扩展内核功能。eBPF的出现彻底改变了传统内核模块的开发模式,为系统可观测性、网络性能和安全防护带来了前所未有的可能性。

eBPF在Linux内核中的工作机制

eBPF的工作原理基于一个精心设计的架构,包含多个核心组件协同工作,形成完整的程序生命周期。eBPF程序的生命周期通常包括编写、编译、加载、验证和执行等阶段。开发人员首先使用C等高级语言编写eBPF程序,然后通过LLVM/Clang编译器将其编译为eBPF字节码。接着通过bpf()系统调用将字节码加载至内核,内核中的eBPF验证器对字节码进行严格的安全校验。校验通过后,字节码由解释器执行或通过即时编译(JIT)转换为本地机器码以提高效率。程序以事件驱动方式,在挂载的钩子点被触发执行。

核心组件包括

  • eBPF虚拟机:eBPF程序运行在一个轻量级的eBPF虚拟机上,该虚拟机包含11个64位寄存器(R0-R10),其中R0通常用于存放函数返回值或程序退出值,R1-R5用于传递调用参数,R6-R9为通用寄存器,R10是只读的栈帧指针。虚拟机为每个程序提供独立的栈空间,最大为512字节。eBPF拥有自定义的指令集,指令格式通常包含操作码、寄存器、偏移量和立即数字段。
  • eBPF验证器:这是eBPF安全机制的核心,在加载前对字节码进行安全性检查。验证器会进行有向无环图检查以防止循环,并通过路径模拟执行来验证所有可能的控制流路径中寄存器和栈的状态都是确定且安全的。验证器的工作流程分为三步:首先进行控制流图检查,确保程序是无环的且有明确的退出路径;然后进行寄存器状态检查,模拟执行每一条指令,跟踪所有寄存器和栈上变量的类型与边界;最后确保程序最终会退出,防止无限循环。从Linux 5.3开始,验证器支持有界循环(bounded loops),之前eBPF程序完全不允许循环。
  • JIT编译器:验证通过后,eBPF字节码被JIT编译为本地机器指令(x86_64、ARM64等均支持)。在/proc/sys/net/core/bpf_jit_enable设为1时开启。JIT后的eBPF程序执行开销与内核原生代码相差无几,单次事件处理开销在纳秒级。
  • eBPF映射(Maps):这是用于内核与用户空间之间共享数据的键值存储,也是eBPF程序之间共享数据的核心机制。主要类型包括哈希表(O(1)时间复杂度的键值查找)、数组(固定大小的连续存储,适合索引访问)、LRU表(自动淘汰最近最少使用条目)、环形缓冲区(高效的内核-用户态数据传输通道)等。BPF Maps作为内核与用户态共享的键值存储,支撑了eBPF的复杂状态管理需求。
  • eBPF钩子(Hooks):这些是内核中的特定位置,程序可挂载于此。不同类型的钩子包括kprobes(内核函数入口/出口)、uprobes(用户态函数入口/出口)、tracepoints(内核静态跟踪点)、perf events(性能监控单元)、XDP(网络数据路径)等。当内核到达钩子时,它会运行附加的eBPF程序。
  • 辅助函数(Helper Functions):这是一组内核提供的安全API,供eBPF程序调用以完成特定任务。因为eBPF无法生成任意函数且必须保持与每个可能内核版本的兼容性,辅助函数弥补了这一差距,让eBPF程序可以完成不受指令集直接支持的复杂操作。

高效执行模型方面,eBPF采用JIT即时编译技术将字节码转为原生指令,执行效率接近内核原生代码。创新状态机设计优化内核态与用户态数据交互,结合环形缓冲区与Perf事件机制,确保数据传输高效稳定。eBPF程序是事件驱动的,只在触发时才运行,JIT编译后以原生机器指令执行,单次事件处理开销在纳秒级,这意味着可以在生产环境长期开启eBPF监控,而不会显著影响性能。

eBPF的安全沙箱机制

eBPF的安全沙箱机制是其设计的核心,通过多重安全保障确保内核稳定性。安全性是eBPF设计的核心,程序在加载前必须通过eBPF验证器的严格检查,确保其不会导致内核崩溃、死锁或越界访问。

三重安全保障包括

  1. 静态验证阶段:通过内核验证器检测死循环、越界访问等风险。验证器使用深度优先搜索(DFS)算法遍历程序的控制流图,确保它是一个有向无环图(DAG),这对于保证程序不会进入无限循环至关重要。验证器还会检查可能的越界内存访问,这些访问可能导致数据损坏或安全漏洞。除此之外,它还考虑到硬件漏洞,如幽灵(Spectre),执行缓解措施以防止此类旁路攻击。
  2. 权限控制:限制仅授权守护进程可操作程序加载。在程序加载前,内核的验证器会对代码进行静态分析,确保程序不包含任何有害操作,例如无限循环、非法指令或越界内存访问。它还有助于确保程序的所有数据路径成功终止。
  3. 程序签名机制:验证字节码来源可信性,形成立体化安全防护体系。验证器会构建程序的控制流图,检查所有可能的执行路径是否满足:无后向分支(防止无限循环)、寄存器访问越界检查、栈深度限制(默认512字节)。

验证器的工作原理包括:

  • 遵循控制流程图:验证器首先通过构建并遵循eBPF程序的控制流程图(CFG)来进行其分析。它细致地计算出每条指令的所有可能状态,同时考虑BPF寄存器集和堆栈。然后根据当前的指令上下文进行安全检查。
  • 控制流程图的回边处理:验证器通过识别CFG中的回边来有效处理eBPF程序内的循环。通过模拟所有迭代直到达到预定的上限,从而确保循环不会导致无限制执行。
  • 处理大量潜在状态:验证器需要处理程序执行路径中大量潜在状态带来的复杂性。它运用路径修剪逻辑,将当前状态与之前的状态进行比较,判断当前路径是否与之前的路径"等效",并且有一个安全的出口。这样减少了需要考虑的状态总数。
  • 逐函数验证以减少状态数量:为了简化验证过程,验证器进行逐函数分析。这种模块化的方法使得在任何给定时间内需要分析的状态数量得以减少,从而提高了验证过程的效率。
  • 按需标量精度追踪以进一步减少状态:验证器运用按需标量精度追踪来进一步减少状态空间。通过在必要时对标量值进行回溯,验证器可以更准确地预测程序的行为,优化其分析过程。
  • 超过"复杂性"阈值时终止并拒绝:为了保持实用性能,验证器设定了一个"复杂性"阈值。如果程序分析超过此阈值,验证器将终止过程并拒绝该程序。这样确保只有在可管理的复杂性范围内的程序被允许执行,实现了安全性与系统性能的平衡。

安全机制的其他方面

  • 类型安全:通过防止类型混淆错误,eBPF验证器利用BPF类型格式(BTF),它允许准确理解和检查内核的复杂数据结构,确保程序对这些结构的操作是有效和安全的。
  • 防止硬件异常:硬件异常,如除以零,可能导致程序突然终止和内核恐慌。为了防止这种情况,验证器包括检查未知标量的除法,确保指令按照与aarch64规范一致的方式重写或处理,这些规范规定了这类异常的安全处理。
  • 内存安全:内存安全在内核操作中至关重要。验证器检查可能的越界内存访问,这些访问可能导致数据损坏或安全漏洞。它还防范使用后释放的错误和对象泄漏,这些是常见的可被利用的漏洞。

eBPF验证器代表了现代计算安全领域的创新,它巧妙地在最大化程序可编程性和在内核级别保持坚固防御之间找到了平衡。通过这些机制,eBPF验证器在维护内核的安全性和稳定性中发挥了关键作用,成为eBPF基础设施中不可或缺的组成部分。

eBPF与传统内核模块的技术差异

eBPF技术相比传统内核模块具有显著的技术优势,这些优势使eBPF成为现代云原生基础设施的理想选择。通过对比分析,我们可以更清晰地理解为什么Cilium选择eBPF作为其技术基础。

技术特性

eBPF

传统内核模块

安全性

内置验证器确保程序安全,不会导致内核崩溃

可能导致内核恐慌,安全性依赖开发者经验

性能开销

JIT编译后接近原生性能,单次事件处理纳秒级

需要用户态-内核态切换,性能开销较大

部署灵活性

无需重启系统,支持动态加载和卸载

通常需要重新编译内核或重启系统

兼容性

通过辅助函数和抽象层保持跨版本兼容性

依赖特定内核版本,兼容性差

可维护性

程序与内核解耦,维护成本低

与内核紧密耦合,维护成本高

eBPF的这些技术优势使其特别适合云原生环境的动态性和安全性要求。Cilium正是充分利用了这些优势,在Kubernetes环境中提供了高性能、高安全性的网络、安全和可观测性解决方案。随着Linux内核版本的演进,eBPF技术也在不断发展,为Cilium提供了更强大的技术基础和更广阔的应用前景。

三、Cilium技术架构与核心组件

Cilium作为基于eBPF技术的云原生网络、安全与可观测性一体化解决方案,其技术架构经过精心设计,以充分发挥eBPF的技术优势。Cilium的架构由四个关键组件构成:核心模块Cilium、可观测性模块Hubble、内核层eBPF程序模块以及存储模块。这种分层架构确保了高性能、高安全性和深度可观测性的完美结合。

Cilium的核心架构

Cilium的核心架构基于eBPF技术,通过在Linux内核中动态注入字节码实现高性能网络数据路径、深度可观测性和身份感知的安全策略执行。其架构设计充分考虑了云原生环境的动态性和复杂性,提供了从L3网络层到L7应用层的全面覆盖。

核心模块Cilium是整个架构的基石,由在集群节点和服务器上运行的代理(Cilium Agent)、控制平面(Cilium Operator)、命令行管理界面(Cilium CLI)以及网络插件(Cilium CNI)等部分组成。Cilium Agent以daemonset形式运行在每个节点上,负责与Kubernetes API服务器交互同步集群状态,管理Linux内核中的eBPF程序和map,实现网络数据路径配置、策略执行和服务发现。Cilium Operator作为集群级控制平面,管理IP地址池、处理节点拓扑变化和维护集群级资源,但不处于关键转发路径上,即使暂时不可用集群仍能继续运行。Cilium CLI提供了命令行管理界面,方便管理员进行配置和故障排查。Cilium CNI作为Kubernetes容器网络接口插件,负责Pod的网络配置和IP地址分配。

可观测性模块Hubble是一个分布式网络和安全观测平台,包括Web界面(Hubble UI)、数据采集服务(Hubble Server)、数据聚合服务(Hubble Relay)以及命令行管理界面(Hubble CLI)等组件。Hubble利用eBPF技术提供的深度可观测性能力,实时采集网络流量、安全事件和性能指标,为运维人员提供全面的网络可见性。Hubble UI提供了直观的拓扑可视化界面,能够展示服务依赖关系和通信模式;Hubble Server在每个节点上运行,负责本地数据采集;Hubble Relay作为数据聚合服务,连接所有Hubble Server,提供集群范围内的网络可见性;Hubble CLI则提供了命令行查询工具,支持复杂的网络流量分析。

内核层eBPF程序模块是Cilium的数据平面核心,通过利用内核中的各种挂载点和eBPF运行时,确保Cilium数据平面的高性能和高安全性。Cilium的eBPF程序按照其挂载位置和程序类型的不同,可以分为四类。第一类是XDP程序,XDP程序位于网络驱动的最早阶段,负责在接收到数据包时触发eBPF程序的执行。由于XDP程序的执行速度极快,Cilium利用它实现了高性能负载均衡,从而加速LoadBalancer和NodePort类型的服务。第二类是TC程序,TC程序在内核协议栈初始化之后、L3协议处理之前执行,支持接收和发送两个方向。因此,Cilium使用TC程序来实现网络策略校验、连接跟踪、NAT转换等功能。第三类是套接字操作程序,套接字操作程序挂载在cgroup上并在TCP事件上运行。Cilium将套接字操作程序挂载到根cgroup,用以监控TCP状态转换和套接字信息维护等任务。第四类是套接字发送/接收程序,套接字发送/接收程序挂载在TCP套接字上,并在发送TCP请求时运行。Cilium利用这类程序加速本地数据路径的重定向。

存储模块负责存储集群状态,并在不同节点之间进行同步,支持Kubernetes CRD和etcd。Cilium使用etcd作为键值存储来维护集群状态,包括网络配置、安全策略、服务发现信息等。这种分布式存储设计确保了集群状态的一致性和可靠性,即使在节点故障的情况下也能保持服务的连续性。

Cilium数据平面处理流程

Cilium的数据平面处理流程因Pod位置不同而有所差异,充分体现了eBPF技术的高效性和灵活性。通过分析不同场景下的数据包处理流程,我们可以更深入地理解Cilium的技术优势。

同节点Pod间通信:当两个Pod位于同一节点上时,数据包的流程如下:在Pod将数据包发送至套接字之后,套接字操作程序(bpf_sockops)将对其进行拦截。当检测到目标地址位于同一节点时,它会直接通过重定向(bpf_redir)跳过内核协议栈,将数据包发送到目标Pod的套接字中,进而传递给目标进程。如果发送数据包的Pod设置了七层出口策略,数据包将首先转发至用户态代理(即Envoy)以进行出口安全策略验证,然后再重定向至目标Pod。如果目标Pod同时配置了七层入口策略,数据包将再被转发至用户态代理(即Envoy)进行入口安全策略验证,然后再重定向到目标Pod。从这个过程中可以看出,套接字操作程序(Sockops)使得Cilium能够绕过主机内核协议栈,从而实现Pod之间的直接通信。

跨节点Pod间通信:当两个Pod位于不同节点上时,它们的处理路径相对复杂。源Pod出口路径中,Pod发送数据包到套接字之后,套接字操作程序(sockops)对其目标地址进行检查,当检测到目的地址不在同一节点后,数据包继续发送到容器虚拟网卡对端设备。挂载到容器虚拟网卡对端设备的TC程序(bpf_lxc)进行网络策略校验、连接跟踪、DNAT等处理,然后发送到主机TC程序(bpf_host)进行南北向数据包处理。如果发送数据包的Pod配置了七层出口策略,那么数据包还会被先转发到用户态代理(即Envoy)进行安全策略验证,之后再发送到主机TC程序(bpf_host)进行南北向数据包处理。之后数据包进入内核协议栈进行路由选择后,经主机网卡发送到目的节点。

数据包在到达目标主机网卡后的入口路径处理流程是:数据包进入目标主机网卡后,主机cilium_host TC程序(bpf_host/bpf_overlay)进行南北向数据包处理(如果目的地址是LoadBalancer或NodePort类型Service地址,则先会进入主机网卡的XDP负载均衡处理程序)。接着,cilium_host TC程序找到目的Pod,将数据包重定向到它的虚拟网卡对端设备。虚拟网卡对端设备挂载的TC程序(bpf_lxc)会进一步对入口流量进行处理。最后数据包经过虚拟网卡被发送到目的Pod内部的虚拟网卡,最终到达容器进程。针对入口路径和出口路径,如果配置了加密策略,则在相应的TC程序前后还需进行加解密处理(bpf_network)。如果配置了七层策略,数据包会先转发至用户态代理(即Envoy),在通过安全策略验证后,才会发送至目标Pod的虚拟网卡对端设备。

内核态与用户态交互:内核态的eBPF程序与用户态进程进行交互需要通过BPF映射。Cilium Agent与各种eBPF程序正是通过BPF映射存储了连接跟踪、NAT转换、IP地址、临接表等各种信息。从这些入口路径和出口路径的处理流程可以看出,Cilium使用eBPF简化了Linux内核原有的连接跟踪、网络安全策略、路由转发、负载均衡等功能,从而显著提升了网络处理的性能。

Cilium核心组件协同工作原理

Cilium的各个核心组件通过eBPF技术实现紧密集成,形成了完整的网络、安全与可观测性解决方案。这些组件各司其职又协同工作,共同构建了高性能、高安全性的云原生网络基础设施。

Cilium Agent作为数据平面的核心组件,以daemonset形式运行在每个节点上,承担着多重职责。首先,Cilium Agent负责与Kubernetes API服务器交互,实时同步集群状态,包括Pod的创建销毁、服务的变更、网络策略的更新等。其次,Cilium Agent管理Linux内核中的eBPF程序和map,根据集群状态动态加载、更新或卸载eBPF程序,确保网络数据路径的正确配置和安全策略的有效执行。第三,Cilium Agent负责节点级别的网络配置,包括Pod IP地址分配、路由表维护、网络策略实施等。最后,Cilium Agent还提供本地监控和日志收集功能,为Hubble可观测性平台提供数据支持。Cilium Agent的高效运行是Cilium整体性能的关键,它通过eBPF技术将大部分网络处理逻辑放在内核态执行,避免了传统方案中用户态与内核态频繁切换的性能开销。

Cilium Operator作为控制平面的核心组件,以deployment形式运行在集群中,负责集群级别的资源管理和配置维护。Cilium Operator的主要职责包括:管理集群的IP地址池,确保Pod IP地址的合理分配和回收;处理节点拓扑变化,维护节点间的网络连接关系;管理集群级别的网络配置,如Cluster Mesh多集群配置、BGP路由配置等;维护Cilium的自定义资源定义(CRD),如CiliumNetworkPolicy、CiliumEndpoint等。Cilium Operator的一个关键设计特点是它不处于关键转发路径上,即使Cilium Operator暂时不可用,集群的网络功能仍能继续运行,这大大提高了系统的可靠性。Cilium Operator通过Kubernetes控制器模式工作,持续监控集群状态的变化,并采取相应的行动来维持期望的系统状态。

Hubble组件作为可观测性平台的核心,由多个子组件构成,提供全面的网络可见性。Hubble Server在每个节点上运行,负责从Cilium Agent收集基于eBPF的可观测性数据,并提供gRPC服务接口。Hubble Server能够捕获网络流量、安全事件、性能指标等多种数据,为运维人员提供全面的网络可见性。Hubble Relay作为数据聚合服务,连接所有Hubble Server,提供集群范围内的网络可见性,特别适用于大规模集群和Cluster Mesh多集群场景。Hubble UI是基于Web的界面,提供交互式拓扑视图、网络策略实施信息和流详细信息,使运维人员能够直观地理解网络结构和流量模式。Hubble CLI则提供了强大的命令行查询工具,支持复杂的网络流量分析和故障排查。Hubble组件的分布式设计确保了可观测性平台的高可用性和可扩展性,能够适应各种规模的集群环境。

组件间协同机制:Cilium的各个组件通过eBPF技术和Kubernetes API实现了紧密的协同工作。Cilium Agent与Kubernetes API服务器交互,获取集群状态信息,并将这些信息传递给eBPF程序,指导网络数据包的处理。Cilium Operator通过Kubernetes CRD定义网络策略和服务配置,Cilium Agent将这些配置转换为eBPF程序和map,在内核中实施。Hubble组件从Cilium Agent获取基于eBPF的可观测性数据,经过聚合处理后提供给用户界面和命令行工具。这种协同机制确保了网络配置、安全策略和可观测性的一致性和实时性,为云原生环境提供了高性能、高安全性的网络基础设施。

组件名称

部署形式

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_28608175/article/details/163587006

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--