【linux内核】eBPF基础及应用调研
系列综述:
💞目的:本系列是个人整理为了学习ebpf机制
的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
🥰来源:材料主要源于–知乎ebpf专栏文章
–进行的,每个知识点的修正和深入主要参考各平台大佬的文章,其中也可能含有少量的个人实验自证。
🤭结语:如果有帮到你的地方,就点个赞和关注一下呗,谢谢🎈🎄🌷!!!
请先收藏!!!,后续继续完善和扩充👍(●’◡’●)
文章目录
- 一、eBPF介绍
- 简介
- eBPF特性
- 二、在K8s中eBPF的应用实践
- 概述
- Cilium(纤毛 ,细小而无处不在)
- cilium概述
- 携程 Cilium+BGP 云原生网络实践
- Calico(灵活,多种颜色的棉布)
- Calico概述
- 二、在AI中eBPF的应用实践
- 简介
- 参考博客
😊点此到文末惊喜↩︎
前言
- eBPF提升内核的能效是目标,它要发挥的是瑞士军刀的作用,如果只是为了eBPF而eBPF,那它就是狗皮膏药,你只是为了把它贴到身体的某个地方而已,并且你也会一直找这样的地方,找准机会就贴上去。另一句意思相同的话,大概是如果你有个锤子,那么眼里什么都是钉子
- eBPF应该慎用,其会增加系统的复杂度,从而导致故障概率的提升
一、eBPF介绍
简介
- eBPF概述
- 背景:eBPF(extended Berkeley Packet Filter)是一种扩展的伯克利包过滤器,由原来的网络过滤器BPF 演进成的一个可插拔可编程的内核模块eBPF,可基于此开发性能分析工具、软件定义网络等诸多场景。
- 定义:处于内核中的一个高效与灵活的虚类虚拟机组件,以一种安全的方式在许多内核 hook 点执行字节码。
- 作用
- 内核可编程:基于eBPF可以不需要直接修改和编写内核,实现一种可插拔的内核编程模块
- 内核监控:追踪内核中的各种事件或资源使用情况,从而进行调试或性能优化
- 网络过滤与安全:根据策略规则过滤网络包,提高网络安全性
- 功能直达:绕过内核中非必要的子系统,直接进行数据包的处理和转发
- 特点
- 内核支持函数列表:eBPF 程序不能调用任意的内核参数,只限于内核模块中列出的 BPF Helper 函数
- 有界循环:eBPF 程序中循环次数限制且必须在有限时间内结束,防止系统运行出现死锁
- eBPF的组成
- 用户态程序:负责加载 BPF 字节码至内核,如需要也会负责读取内核回传的统计信息或者事件详情
- 内核态BPF字节码程序: 负责在内核中执行特定事件,如需要也会将执行的结果通过 maps 或者 perf-event 事件发送至用户空间
- 其中用户空间程序与内核 BPF 字节码程序可以使用
map 结构
实现双向通信
- eBPF的执行流程
- 用户态
- 编译:使用 LLVM 或 GCC 工具将编写的
eBPF 程序
编译成eBPF 字节码
- 加载:调用 bpf()系统调用把 eBPF 字节码加载到内核。
- 编译:使用 LLVM 或 GCC 工具将编写的
- 内核态:
- Verfier验证与JIT编译:内核使用
验证器
验证字节码安全性,通过JIT(Just In Time)将 eBPF 字节码编译成机器码(Native Code) - Hook挂载:内核会根据eBPF功能将机器码挂载到内核对应的Hook,当运行到某个Hook就会执行对应的eBPF程序
- 用户态
- eBPF中用户态与内核态的通信方式
- maps方式:将
数据
存储在内核键值对
数据结构中,数据由内核eBPF字节码程序更新,并共享给用户态程序进行周期性查询 - perf-event方式:可用于捕获内核中的多种
软硬件事件
,并将这些事件实时
发送给用户空间程序
- maps方式:将
eBPF特性
- eBPF中的Hook
- 定义:hook是指内核中特定函数(事件)的发生,包括系统调用、函数进入/退出、网络事件等
- 原理:
- tracepoint机制:基于
内核标记点tracepoint
来追踪内核中的特定事件 - kprobes机制:可以在
内核函数的入口或出口
处插入Hook - uprobes机制:可以在
用户空间函数的入口或出口
处插入Hook
- tracepoint机制:基于
- eBPF的Verification
- 过程:每一个 eBPF 程序加载到内核前,都要经过 Verification来保证 eBPF 程序的安全性
- 加载对象:除非节点开启了
unpriviledged 特性
,否则只有高特权级的程序
才能够加载 eBPF 程序 - 作用:
- 核心:保证 eBPF 程序不会崩溃或者使得系统出故障
- 时间:保证 eBPF 程序不能陷入死循环
- 空间:保证 eBPF 程序必须满足系统要求的大小,过大的 eBPF 程序不允许被加载进内核
- JIT Compilation
- 作用:Just-In-Time(JIT) 编译用来将通用的 eBPF 字节码翻译成与机器相关的指令集,从而极大加速 BPF 程序的执行
- 特点:
- 与解释器相比,可以降低每个指令的开销
- 减少生成的可执行镜像的大小
- 针对CISC 指令集(例如 x86),JIT 做了很多特殊优化
- BPF Map
- 定义:驻留在内核空间中高效的
键值存储结构
,用于实现用户态程序、内核态BPF程序以及其他内核态程序间的通信 - 作用:
- 由于安全原因 BPF 程序不允许访问全局变量,可以使用 map 来充当全局变量
- 通过BPF Tail call实现BPF程序间的跳转,主要是通过map获取其他BPF的程序指针实现的
- 注意
- 多对多:一个map可以共享给多个不同的BPF程序,而一个 BPF 程序也可以访问多个不同的map(目前最多64个)
- 多CPU架构:基于 per-cpu类型,每个CPU在同一个map中的数据被相互隔离,从而实现更高效的查找和聚合操作
- 解耦:eBPF 程序不能够随意调用内核函数,避免 eBPF 程序与特定的内核版本的绑定
- 定义:驻留在内核空间中高效的
- BPF辅助函数
- 所有的 BPF 辅助函数都是核心内核的一部分,无法通过内核模块(kernel module)来扩展或添加。
- BPF辅助函数的参数列表和底层系统调用约定相匹配
- Tail Calls(尾调用机制)
- 使用长跳转(long jump)实现的,复用原来的栈帧 ,调用开销小
- 相同类型的程序才可以尾调用,而且它们还要与 JIT 编译器相匹配
- BPF to BPF calls
- 减小了生成的 BPF 代码大小,因此 对 CPU 指令缓存(instruction cache,i-cache)更友好。
- Object Pinning(钉住对象)
- 定义:用于将eBPF程序的map数据固定在内核指定位置,以便快速访问,从而避免eBPF生命周期结束导致map数据的丢失。
通过下面网站进行完善ebpf基础知识,以面试题的形式完善https://developer.aliyun.com/search?k=ebpf&scene=community&page=1
二、在K8s中eBPF的应用实践
概述
- 常见应用
- Cilium
- Calico
- Sysdig实时监控工具
- XDP(eXpress Data Path)
- Falco
- Cilium 是一个使用 eBPF 实现的网络插件,可以为 Kubernetes 提供高度灵活的网络策略实施。Cilium 支持基于标签的网络策略,并且可以实时更新策略。利用 eBPF 实现了高效的网络策略执行、负载均衡和服务发现等功能,还提供了强大的安全功能,如基于身份的网络策略、微分段和入侵检测等。从 1.6 开始,Cilium 可以 100% 替换 kube-proxy,真正通过 eBPF 实现了 kube-proxy 的全部转发功能。
- Calico 是另一个流行的 Kubernetes 网络插件,支持 eBPF 模式。Calico 的 eBPF 模式提供了高性能的网络策略实施,并且可以保留客户端的真实 IP 地址。
- Sysdig 是一个基于 eBPF 的性能监控和故障诊断工具,可以实时展示集群中的各种性能数据。
- XDP 是一种使用 eBPF 实现的高性能网络包处理技术,可以在数据包到达网卡时进行处理。在 Kubernetes 中,可以使用 XDP 来加速网络包处理,减少网络延迟
- Falco 是一个基于 eBPF 的安全工具,可以实时监控 Kubernetes 集群中的系统行为,并检测异常活动。一个云原生的运行时安全项目,使用 eBPF 来检测容器和 Kubernetes 环境中的异常行为。它可以检测到各种安全事件,如文件系统访问、网络连接和系统调用等。Falco 可以与 Kubernetes 集成,提供实时的安全监控和警报,帮助及时发现和应对安全威胁。
- 基本作用
- 网络性能优化:
- 负载均衡:eBPF 可以实现更高效的负载均衡策略,通过直接在网络层进行流量分发,减少内核协议栈的开销,提高网络吞吐量和响应速度。并且可以根据实时的网络状况和后端服务的负载情况动态调整流量分配,确保每个服务副本都能得到合理的负载。
网络流量监控与分析:eBPF 程序可以在网络数据包经过内核时进行捕获和分析,提供详细的网络流量监控,了解每个容器、Pod 或服务的网络流量情况,包括流量大小、协议类型、源地址和目的地址等信息,有助于排查网络问题、优化网络配置以及进行容量规划。
- 负载均衡:eBPF 可以实现更高效的负载均衡策略,通过直接在网络层进行流量分发,减少内核协议栈的开销,提高网络吞吐量和响应速度。并且可以根据实时的网络状况和后端服务的负载情况动态调整流量分配,确保每个服务副本都能得到合理的负载。
- 安全增强:
- 入侵检测与防护:通过监测网络数据包和系统调用,eBPF 程序可以检测到潜在的攻击行为,如端口扫描、恶意软件传播、SQL 注入等。一旦检测到攻击,eBPF 可以立即采取行动,如阻止恶意数据包的传输、隔离受攻击的容器或向管理员发出警报。
- 容器安全:eBPF 可以用于加强容器的安全隔离,确保一个容器的安全漏洞不会影响到其他容器或整个集群。例如,通过 eBPF 限制容器的网络访问权限,只允许其访问特定的端口和地址,防止容器被恶意利用进行横向攻击。
- 资源管理与优化:
- 资源监控与限制:eBPF 可以实时监控容器和 Pod 的资源使用情况,包括 CPU、内存、网络带宽和磁盘 I/O 等。通过收集这些信息,可以更好地了解集群的资源使用状况,进行合理的资源分配和调度。同时,eBPF 还可以用于实现资源限制,确保每个容器或 Pod 不会超过其分配的资源限额,避免因某个容器的资源过度使用而影响到其他容器的正常运行。
- 性能调优:通过分析系统的性能指标,eBPF 可以帮助找到性能瓶颈并进行优化。例如,如果发现某个容器的 CPU 使用率过高,可以通过 eBPF 分析其系统调用和函数调用栈,确定是哪个函数或操作导致了高 CPU 使用率,进而进行针对性的优化。
- 网络性能优化:
- BGP协议
- 定义:BGP(Border Gateway Protocol)协议是用于在不同的自治系统(AS)之间交换路由信息的互联网路由协议
- 作用:
- 路由信息交换:BGP 负责在不同的自治系统之间交换路由信息,使互联网上的数据包能够正确地从一个自治系统传送到另一个自治系统。
- 路由选择:BGP 根据一系列策略和属性来选择最优路径,确保数据包能够通过最优路径传输。
- 网络可达性:BGP 保证了互联网的可达性,即使在网络拓扑发生变化时也能维持网络的连通性。
- 负载均衡:BGP 可以通过多条路径来实现负载均衡,提高网络资源的利用率
Cilium(纤毛 ,细小而无处不在)
cilium概述
- 概述
- 定义:Cilium 是一种面向容器环境的网络插件(CNI),基于eBPF实现了高效的网络连接,网络策略实施和可观测性等特性。
- 作用
- 高效网络代理:基于eBPF实现的零拷贝快速数据包处理和智能路由决策,实现高效的网络流量处理。
- 网络策略实施:允许用户定义和实施精细的网络策略,控制容器之间的网络访问。可以根据容器的标签、命名空间等属性来制定策略,限制特定容器或一组容器的网络访问权限。
- 可观测性:通过运行为每个节点的Hubble 组件和eBPF技术实现集群中流量和其他网络指标的实时观测
- 基于身份的服务通信保护:Cilium 为共享相同安全策略的应用程序容器组分配安全标识。然后,该标识与应用程序容器发出的所有网络数据包相关联,从而允许验证接收节点处的身份
- 基于身份的安全模型:每个容器都有一个唯一的身份标识,为容器和服务提供更细粒度的安全控制。
- 通过Hubble组件实现简单高效的网络可视化功能
- 为什么使用Cilium
- 核心:传统架构使用
静态IP
作为应用识别,但高度动态化微服务
架构需要基于服务的Pod标识,从而避免网络策略表的频繁更新 - 高度动态的微服务:现代数据中心
大型应用程序
通常会被拆分
成更细粒度的微服务
(SOA),而微服务
应用在容器数量不断增大、Pod生命周期不断缩短的趋势下,导致了IP地址的高度动态化 - 传统静态的网络策略:传统的 Linux 通过过滤
IP和端口
实现网络安全,但高度动态的微服务会导致负载均衡表和访问控制列表不断更新
传统架构的静态IP识别方式
- 核心:传统架构使用
- Cilium 如何实现负载均衡
- IPVS:使用内核中的IPVS(IP Virtual Server)根据配置的负载均衡算法选择一个合适的后端端点(Pod),并进行流量转发
- eBPF:BPF maps负责存储服务端点信息和网络策略,eBPF 程序来捕获网络流量,并实现更加细粒度负载均衡逻辑
- cilium与其他工具的集成
- Prometheus:Cilium 可以将收集到的指标暴露给 Prometheus,Prometheus 是一个广泛使用的开源监控系统和时间序列数据库。通过与 Prometheus 集成,Cilium 能够将网络和系统的关键指标以时间序列的形式存储和管理起来,方便用户进行长期的监控和趋势分析,并且可以基于这些指标设置报警规则,及时发现网络或系统中的异常情况。
- Grafana:Grafana 是一个功能强大的数据可视化工具。Cilium 与 Grafana 结合后,用户可以利用 Grafana 丰富的可视化界面和图表功能,将来自 Cilium 的数据以直观、美观的图表形式展示出来,如柱状图、折线图、饼图等,使得网络和系统的状态更加清晰易懂,便于用户从不同角度观察和分析数据,快速获取关键信息。
- 发展
- k8e 使用 Cilium 作为默认的 CNI 实现
- 全面实现kube-proxy的功能,同时提供更好的性能、可靠性以及可调试性
携程 Cilium+BGP 云原生网络实践
- 背景:
Neutron+OVS
难以满足迁移到k8s后的业务需求,调研后选用Cilium+BGP
的组合实现云原生的网络支持 - 如何实现灰度迁移(低风险的逐步过渡到新系统)
- 用
docker-compsoe + salt
来部署:能够独立配置每台node 上的 cilium-agent,实现灰度发布的完全控制,将变更风险降到最低。 - 用
BIRD 作为 BGP agent
:默认的kube-router 开箱即用,但缺少对 ECMP、BFD 等高级功能的支持,不符合我们生产环境的要求。 - 特殊业务的平滑过渡支持:开发了 StatefulSet/AdvancedStatefulSet 固定 IP 的支持(需要 sticky 调度配合)
- 其他:定制化了监控和告警,以及其他一些自定义配置。
- 用
- Cilium+BPG方案架构
宿主机内部
网络:由Cilium
(及内核协议栈)负责- 为容器创建和删除虚拟网络。
- 为容器生成、编译和加载 eBPF。
- 处理同宿主机内容器之间的网络通信
- 跨
宿主机外部
网络:由BGP
(及内核路由模块)负责- 与数据中心网络交换路由(PodCIDRs)。
- 对出宿主机的流量进行路由。
- 跨主机部分BGP peering模型选择需要注意点
- BGP agent 的职责,是作为一个全功能路由控制服务,还是仅用作 BGP speaker?
- 宿主机和数据中心的哪些设备建立 BGP 邻居?
- 使用哪种 BGP 协议,iBGP 还是 eBGP?
- 如何划分自治域(AS),使用哪种 ASN(自治域系统编号)方案?
- 数据中心网络能提供的能力及实际的需求是什么?
- 携程采用的相对简单的BGP模型
- 整体架构
- 每台 node 运行 BIRD,仅作为 BGP speaker(向其他 BGP 对等体宣告自己所连接的网络信息)
- Node 在上线时会自动分配一个 /25 或 /24 的 PodCIDR
- BIRD 和数据中心网络中的两个邻居建立 BGP 连接
- BIRD 将 PodCIDR 通告给邻居,但不从邻居接受任何路由
- 数据中心网络只从 node 接受 /25 或 /24 路由宣告,但不向 node 宣告任何路由。
- 整张网络是一张三层纯路由网络(pure L3 routing network)
- 每台 node 运行 BIRD,仅作为 BGP speaker(向其他 BGP 对等体宣告自己所连接的网络信息)
- 模型简单之处
- 数据中心网络从各 node 学习到 PodCIDR 路由,了解整张网络的拓扑,因此 Pod 流量在数据中心可路由。
- Node 不从数据中心学习任何路由,所有出宿主机的流量直接走宿主机默认路由(到数据中心网络),因此宿主机内部的路由表不随 node 规模膨胀,没有路由条目数量导致的性能瓶颈
- 路由协议
- 老数据中心基于“接入-汇聚-核心”三级网络架构
节点
和核心交换机
建立 BGP 连接。- 使用
iBGP
协议交换路由。
- 新数据中心基于 Spine-Leaf 架构,
节点
和直连的 Leaf 交换机(置顶交换机
)建立 BGP 连接。- 使用
eBGP
协议交换路由。
- 老数据中心基于“接入-汇聚-核心”三级网络架构
- 整体架构
- Cilium+BGP方案流量转发路径:从 Pod 访问 Service
- 访问svc:在 Node1 上的 Pod1 里面访问某个 Service (curl :)
- 服务处理:选择后端进行服务的负载均衡,并将包的目的 IP 地址从 ServiceIP 换成后端 PodIP(即执行 DNAT)
- 内核路由决策:查询系统路由表,根据包的目的 IP 地址确定下一跳和目的mac地址
- 转发:包到达宿主机网卡(bond),通过默认路由发送到宿主机的默认网关(配置在数据中心网络设备上),然后由数据中心网络对包进行路由转发。
- 解析:包达到 Node 2 的网卡(bond)后,由 eBPF 程序提取包头,根据 IP 信息找到 另一段和目的 Pod对应的 eBPF 代码,然后将包交给它
- 入向策略检查:后一段 eBPF 代码对包执行 入向策略检查,如果允许通过,就将包交给 Pod4的虚拟网卡,然后被收起。
- 从集群外访问Service的模型
- L7 模型:称为 Ingress,支持以 7 层的方式从集群外访问 Service,例如通过 HTTP API 访问。
- L4 模型: 包括 externalIPs Service、LoadBalancer Service,支持以 4 层的方 式访问 Service,例如通过 VIP+Port。
- 注意:K8s 只提供了模型,没提供实现,具体的实现是留给各厂商的
- 携程的集群外访问模型——Cilium+BGP+ECMP
- 原理
- 本质上这是一套四层负载均衡器(L4LB),它提供一组 VIP,可以将这些 VIP 配置到 externalIPs 类型或 LoadBalancer 类 型的 Service,然后就可以从集群外访问
- 基于这套四层入口方案部署 istio ingress-gateway,就解决了七层入口问题
- 从集群外访问时,典型的数据转发路由如下:
- 原理
- 落地挑战
- 多集群问题:若所有的应用都运行在 Cilium 集群中,并且客户端和服务端都收敛到一个大集群(大部分公有云厂商都推荐一个 region 只部署一套 K8s 集群,所有访问都收敛到这套集群),那落地起来会简单很多。但大部分有基础设施演进的公司恐怕都不满足这个假设,实际的情况很可能是:业务分散在多个集群。
- 混合基础设施:业务不仅分散在不同集群,而且在不同平台。通常计划是
能迁尽迁
,不能迁移的可能长期存在,但规模会逐渐减小
- 整体方案设计
- 在服务端容器做入向安全策略,客户端可以来自任何平台、任何集群
- 这将范围框定到了已经在 Cilium 网络的服务端容器,是一个不错的起点。
- 传统网络里的服务端容器,会逐渐迁移到 Cilium 网络。
- BM 和 VM 的服务端实例,第一阶段先不考虑安全控制。
- 服务端对所有类型、所有集群的客户端进行限制
- 用 Cilium 提供 ClusterMesh 将已有 Cilium 集群连接起来
- “扩展” ClusterMesh,让它能感知到 mesh 之外的 endpoints,即 BM、BM 和 Neutron Pods。
- 在服务端容器做入向安全策略,客户端可以来自任何平台、任何集群
- 多集群互联
- 本质:如何在多个集群之间同步元数据,并且做到集群变动的实时感知。
- 解决方案- 骗Cilium:让它认为入向的外部实例都是 Cilium endpoints/pods。即将外部实例信息以 Cilium 能感知的方式(格式)同步到 Cilium 集群
- 开发组件:实现多平台实例的创建/销毁/更新信息能够同步更新到 Cilium 集群
Calico(灵活,多种颜色的棉布)
Calico概述
- 基本概述
- 定义:Calico 是一个开源的容器网络接口CNI,旨在为容器环境提供高性能、可扩展的网络功能。
- 作用
- 容器网络:为 Kubernetes 集群提供高性能的三层网络连接,使得容器可以直接通过 IP 地址进行通信,而不需要使用网络隧道技术。
- 网络策略实施:支持细粒度的网络策略,允许管理员定义容器之间的访问控制规则。
- 跨集群网络:支持跨多个 Kubernetes 集群的网络连接,实现统一的网络策略管理。
- BGP 路由:使用 BGP(Border Gateway Protocol)来在集群内的节点之间传播路由信息,确保所有节点都能直接通过三层网络访问任何 Pod。
- 安全性:提供基于网络策略的安全组功能,实现容器级别的网络隔离和安全通信。
- 可扩展性:支持大规模集群,具有良好的可扩展性和高可用性。
- 工作原理
- 三层网络连接:
- Calico 使用三层网络技术(即直接通过 IP 地址进行通信),而不是依赖于网络隧道技术(如 VXLAN 或者 Geneve)。这意味着容器可以直接通过其 IP 地址与其他容器通信,不需要额外的封装和解封装过程。
- 网络策略实施:
- Calico 提供了基于标签(Label)的网络策略,可以定义允许哪些容器之间的通信。网络策略可以应用于特定的标签组合,从而实现细粒度的访问控制。
- BGP 路由:
- Calico 使用 BGP 协议来在集群内的各个节点之间传播路由信息。每个节点上的 Calico 组件(如 Felix)都会根据 BGP 学习到的路由信息来更新其路由表,从而确保集群内所有节点都能够正确地路由到其他节点上的 Pod。
- 组件结构:
- etcd:Calico 使用 etcd 作为其存储后端,存储所有的网络配置信息和状态。
- Calico API Server:负责与 Kubernetes API Server 交互,接收和处理网络相关的配置。
- BIRD:BIRD 是一个路由守护进程,负责在节点之间传播路由信息。
- Felix:Felix 是运行在每个节点上的守护进程,负责根据 BGP 学习到的路由信息来配置节点上的网络设备,确保 Pod 之间的通信。
- 网络策略实现:
- Calico 通过在节点上配置 iptables 规则来实现网络策略。根据定义的网络策略,Felix 会在节点上配置相应的 iptables 规则,从而实现对容器间通信的控制。
- 跨集群网络:
- Calico 支持跨多个 Kubernetes 集群的网络连接,可以通过 BGP 在不同集群的节点之间传播路由信息,实现统一的网络策略管理。
- 三层网络连接:
二、在AI中eBPF的应用实践
简介
🚩点此跳转到首行↩︎
参考博客
- eBPF 完全入门指南.pdf(万字长文)
- 一文看懂eBPF|eBPF实现原理(超详细) - Linux内核库的文章 - 知乎
- x大规模微服务利器:eBPF + Kubernetes 介绍
- x基于 eBPF 的 Kubernetes 可观测实践
- x使用应用监控 eBPF 版实现无侵入的应用可观测
- x阿里云ebpf论坛
- 基于 eBPF 的网络 Cilium
- 携程 Cilium+BGP 云原生网络实践