在最近的 Linux Plumbers Conference 上,至少有 30 个关于 eBPF(扩展伯克利数据包过滤器)的演讲,并且它的受欢迎程度在过去几年中一直在持续增加。它很快不仅成为一项无价的技术,而且成为一项急需的技能。本博客试图分享我对 eBPF 的理解、观点以及对该技术如何发展的预测。我希望这篇博客能激发您更仔细地了解这项技术并对其产生欣赏。
在我们深入研究有趣的用例之前,让我们回顾一下对 eBPF 的理解。
什么是 BPF/eBPF,为什么它很重要?
BPF(Berkeley Packet Filter)是一种小型虚拟机,可以在内核空间运行从用户空间注入的程序,而无需更改/重新编译内核代码,它首先在 Linux 内核 3.15(1992)中实现,更广为人知的名称是数据包过滤语言tcpdump。
从 2014 年内核版本 3.18 开始,BPF 演变为我们所说的“扩展 BPF”或“eBPF”。
eBPF 是一项革命性的内核技术,它允许开发人员编写可以动态加载到内核中的自定义代码,从而改变内核的行为方式。
这使得新一代高性能网络、可观察性和安全工具成为可能。正如您将看到的,如果您想使用这些基于 eBPF 的工具来检测应用程序,则无需以任何方式修改或重新配置应用程序,这要归功于 eBPF 的优势 - 在内核中的强大且特权地位,如图2所示。
您可以使用 eBPF 执行以下操作:
- 几乎系统任何方面的性能跟踪
- 高性能网络,具有内置可见性
- 检测并(可选)防止恶意活动
图2. eBPF 程序附加到内核中的事件
eBPF 程序是事件驱动的,当内核或应用程序通过某个挂钩点时运行。预定义的钩子包括系统调用、函数入口/出口、内核跟踪点、网络事件和其他几个,如图 3 所示。
图3.具有预定义钩子(如系统调用)的 eBPF
如果不存在满足特定需求的预定义挂钩,则可以创建内核探针 (kprobe) 或用户探针 (uprobe) 来将 eBPF 程序附加到内核或用户应用程序中的几乎任何位置,如图 4 所示。
图4.带有用户探针和内核探针的 eBPF
eBPF程序是如何编写的?
在很多场景中,eBPF 并不直接使用,而是通过Cilium、bcc或bpftrace等项目间接使用,这些项目在 eBPF 之上提供抽象,不需要直接编写程序,而是提供指定基于意图的定义的能力,这些定义是然后用eBPF实现。
图5.带有 Clang(编译器前端)的低级虚拟机 (LLVM) 创建 eBPF 字节码
如果不存在更高级别的抽象,则需要直接编写程序。 Linux 内核期望 eBPF 程序以字节码的形式加载。虽然直接编写字节码当然是可能的,但更常见的开发实践是利用低级虚拟机 ( LLVM)等编译器套件将伪 C 代码编译为 eBPF 字节码。
Map
eBPF 程序使用 eBPF 映射跨内核和用户空间存储、共享和检索数据,从而实现状态存储和信息共享
图7. eBPF 映射用于在内核和用户空间之间共享数据
以下是支持的映射类型的不完整列表,以帮助您了解数据结构的多样性。对于各种Map类型,可以使用共享版本和每个 CPU 版本。
- 哈希表、数组
- LRU(最近最少使用)
- 环形缓冲器
- 堆栈跟踪
- LPM(最长前缀匹配)
总之,eBPF 程序允许通过以下方式安全高效地访问内核操作:
- 为基于系统调用、内核函数、网络事件和其他触发器的程序提供内置钩子
- 提供运行前编译和验证代码的机制,有助于保证系统的安全性和稳定性
- 提供比 LKM(Linux 内核模块)更直接的增强内核功能的方法,从而使小型团队也能高效地开发在内核空间中运行的安全程序
用于网络的 eBPF
图8.使用 eBPF 绕过 iptables 和 conntrack 处理
从图中可以看到,发往应用程序的入口数据包必须经过主机上的网络堆栈,然后再次经过 pod 网络堆栈,添加 eBPF 可以避免此类重复遍历。
图 9.与内核旁路相比,基于 eBPF 的 XDP(快速数据路径)简化了网络
基于 eBPF 的 XDP(快速数据路径)在 Linux 内核中提供高性能数据包处理,非常适合分布式拒绝服务 (DDoS) 缓解和数据包监控等任务 内核旁路技术,例如数据平面开发套件 (DPDK),旨在实现甚至通过完全绕过内核来降低延迟并提高吞吐量。这两种方法都有其优点和缺点,XDP 提供基于内核的效率和兼容性,而内核旁路提供超低延迟,但代价是增加用户空间应用程序的复杂性。
现在我们已经了解了 eBPF,接下来让我们探讨一下目前在网络故障排除、安全性和可观察性方面如何以及在何处利用它。
Kubernetes 中的 eBPF
eBPF 代表了一种更现代、更强大的方法,解决了 iptables 的许多固有限制。目前 Kubernetes 使用 iptables
- kube-proxy:通过 DNAT iptables 规则实现服务和负载均衡的组件
- CNI(容器网络接口)插件
iptables 受到广泛支持,是新 Kubernetes 集群的默认操作模型。不幸的是,它遇到了一些问题:
- iptables 更新是通过在单个事务中重新创建和更新所有规则来进行的。
- iptables 被实现为链表中的规则链,因此所有操作都是 O(n)。
- iptables 将访问控制实现为规则的顺序列表(也是 O(n))。
- 每次有新的 IP 或端口需要匹配时,都需要添加规则并更改链。
- Kubernetes资源消耗较高。
- 从 iptables 到 eBPF 的转变带来了实实在在的好处:提高了应用程序性能、简化了网络操作并增强了安全性,从而节省了成本并提高了资源利用率,如图 10 所示。
图 10. eBPF 将搜索/插入/删除的时间复杂度降低至 O(1)
在大流量或频繁更改的情况下,iptables 由于其顺序规则评估和需要一致的规则更新而导致不可预测的性能下降,从而导致大规模的重大惩罚。例如,华为发现,更新 20,000 个服务集群的 iptables 规则可能需要长达 5 个小时。
如图 10 所示,在 Kubernetes 网络中将 iptables 替换为 eBPF 后,吞吐量、CPU 使用率和延迟的性能测试表明,即使有 100 万条规则,eBPF 也能有效扩展。相比之下,iptables 的可扩展性较差,与 eBPF 相比,即使规则数量较少(例如 1k 或 10k),性能也会受到相当大的影响。
eBPF 安全性
安全工具和报告事件的可观察性工具之间的区别在于,安全工具需要能够区分正常情况下预期的事件和表明可能发生恶意活动的事件。策略不仅要考虑系统功能齐全时的正常行为,还要考虑预期的错误路径行为。
安全工具将活动与策略进行比较,并在活动超出策略时采取一些操作,使其变得可疑。该操作通常涉及生成安全事件日志,该日志通常会发送到安全信息事件管理 (SIEM) 平台。它还可能会向人员发出警报,要求人员调查发生的情况。
当 eBPF 程序在系统调用的入口点被触发时,它可以访问用户空间传递给该系统调用的参数。如果这些参数是指针,则内核需要在对数据进行操作之前将所指向的数据复制到自己的数据结构中。如图 11 所示,在 eBPF 程序检查该数据之后、内核复制该数据之前,攻击者有机会修改该数据。因此,所处理的数据可能与 eBPF 程序捕获的数据不同
Linux 安全模块 (LSM) 接口提供了一组钩子,每个钩子都在内核即将对内核数据结构进行操作之前发生。钩子调用的函数可以决定是否允许操作继续进行。
图 11. eBPF 保护内核
防火墙和 DDoS 保护非常适合早期附加在网络数据包入口路径中的 eBPF 程序。由于 XDP 程序有可能卸载到硬件,恶意数据包甚至可能永远不会到达 CPU
为了实现更复杂的网络策略,例如确定允许哪些服务相互通信的 Kubernetes 策略,附加到网络堆栈中的点的 eBPF 程序可以在确定数据包不符合策略时丢弃数据包。
eBPF 在安全方面的使用已经从对系统调用的低级检查发展到更复杂地使用 eBPF 程序进行安全策略检查、内核内事件过滤和运行时执行
用于网络可观察性的 eBPF
eBPF 提供了一个有趣的工具,允许我们收集 /proc 或其他静态系统表示中无法获得的数据。
Cilium 是一个开源项目,它是在 eBPF 之上设计的,旨在取代 iptables,以满足容器工作负载的网络、安全性和可见性要求。
全面的连接可观察性需要跨所有层的洞察力,而不仅仅是单层或仅应用程序(仅限于 L7 层)。由 eBPF 提供支持的 Cilium 可以实现这一点,如图 12 所示。
图 12.跨所有层进行监控
Prometheus 是云原生计算基金会拥有的时间序列数据库。 Prometheus 的第三方集成称为“导出器”,它允许 Graphana 等工具以各种格式绘制各种指标。
Grafana 是由 Grafana Labs 创建的开源数据分析和可视化 Web 应用程序。它允许您通过将时间序列数据编译成图表、图形或Map来可视化它们,甚至在连接到支持的数据源时提供警报。
Prometheus 和 Grafana Agent 的组合使您可以控制要报告的指标、它们来自哪里以及要去哪里。数据进入 Grafana 后,就可以存储在 Grafana Mimir 数据库中。 Grafana 仪表板由从 Prometheus 数据源查询的数据填充的可视化内容组成。 PromQL 查询过滤并聚合数据,为您提供所需的见解。通过这些步骤,我们将软件生成的原始数据传送到 Prometheus,再传送到 Grafana,由 PromQL 查询,并由 Grafana 进行可视化,如图 13 所示。
图 13.使用 Graphana Dashboard 将 Linux 内部的原始数据转化为视觉洞察
eBPF 成功用例
- Netflix 大规模使用 eBPF 来获取网络洞察
- Apple 通过 Falco 使用 eBPF 进行内核安全监控
- 宜家 通过 Cilium 使用 eBPF 在其私有云中进行网络和负载平衡
- 沃尔玛 使用 eBPF 进行边缘云负载平衡
- Cruise 使用 eBPF 监控 GPU 性能
- Sysdig 使用 eBPF 实现高性能系统调用跟踪、促进容器感知故障排除、进行安全审计并提供来自内核的丰富见解和数据
- Meta 使用 eBPF 来处理和负载平衡进入其数据中心的每个数据包(请参阅项目 Katran)
- Bell Canada 使用 eBPF 通过分段路由 (SR) 改进电信网络
通过 AI/ML 集成增强 eBPF 功能
现在我们了解了 eBPF,让我们探索一下 eBPF 与 AI/ML 的超能力相结合的未来用例。
- AI 支持的网络安全:eBPF 可用于实时监控网络流量,允许 AI 模型分析模式并检测异常或潜在的安全威胁,例如 DDoS 攻击或网络入侵。通过提供对数据包流和系统调用的详细洞察,eBPF 使 AI 系统能够在阻止恶意活动或向管理员发出警报方面做出明智的决策。
- ML 支持的性能监控和优化:eBPF 可以从应用程序和内核收集详细的性能指标,这些指标可以输入到 ML 模型中以预测潜在的瓶颈或故障。这些见解有助于自动调整系统参数以获得最佳性能,或动态调整资源分配以提高效率并减少延迟。
- AI 模型训练可观察性:训练 AI 模型可能会占用大量资源且耗时。 eBPF 可用于在训练过程中细粒度地观察和收集资源使用情况(CPU、内存、I/O)的指标。这些数据可以帮助识别效率低下的地方并优化培训流程,从而有可能减少所需的时间和资源。
- 欺诈检测中的人工智能:在金融服务中,eBPF 可用于实时监控和记录交易。人工智能模型可以分析这些数据,以检测表明欺诈的异常模式。这种方法可以立即检测并采取缓解措施,从而显着降低欺诈活动的风险和影响。
- 使用机器学习进行预测性维护:在物联网和工业环境中,eBPF 可以从各种传感器和设备收集数据,这些数据可以通过机器学习模型进行分析,以在设备故障发生之前进行预测。这种预测性维护可以通过提前安排维修或更换来节省成本并防止停机。
- 基于AI的动态负载均衡:对于云服务和分布式系统,eBPF可以监控流量和系统指标,使AI算法能够动态调整负载均衡策略。这可以通过减少响应时间和避免瓶颈来确保最佳的资源利用率并改善用户体验。
- AI/ML 支持的遥测根本原因分析:eBPF 可以提供有关系统行为和应用程序性能的详细遥测。 AI/ML 模型可以分析这些数据,以自动分析系统问题的根本原因,从而减少诊断和解决问题所需的时间。