Learning eBPF: 为什么被创造出来

  • jkrishna
  • 发布于 2025-08-21 14:28
  • 阅读 30

本文介绍了eBPF的背景、发展历程及其在Linux内核中的作用。传统内核交互的风险促使eBPF的诞生,它通过动态加载、安全验证和高性能,为内核扩展提供了一种更安全、灵活的方式,尤其在云原生环境中,无需修改应用代码即可实现深度系统级可见性。

摘要

这篇博客基于 Liz Rice 的书籍 Learning eBPF

这本书清晰地阐述了 eBPF 是什么,它为什么被创造出来,以及它如何在 Linux 内核中工作。

如果我们真的想理解 Linux 系统内部发生了什么,我们需要查看 Linux 内核。

但是接触内核一直都是危险的。即使是内核代码中的一个小错误也可能导致整个系统崩溃,并且变得无法访问。最重要的是,内核变更需要数年才能到达生产系统,而且在云环境中,我们通常甚至不知道我们的代码在哪个服务器上运行。

长期以来,这迫使人们做出一个令人不安的权衡:保持安全和盲目,或者强大但有风险

eBPF 的存在是因为这种权衡不再可以接受。

BPF 的简短历史和 eBPF 的演变

eBPF 代表 extended Berkely Packet Filter(扩展的伯克利包过滤器)。

最初,BPF 被引入作为一种简单而有效的方式来过滤网络数据包。程序使用一种类似汇编语言的小型指令集编写,它们可以决定是否应该接受或拒绝一个数据包。

这个早期版本通常被称为 classic BPF (cBPF)。虽然有用,但它的范围有限,主要集中在网络方面。

随着时间的推移,Linux 系统不断发展,对更好的可观测性、安全性和性能的需求变得越来越重要。这导致了 cBPF 向 eBPF 的演变。

eBPF 带来了重大改进:

  • • 更好支持 64 位系统
  • • 一个重写且更高效的执行模型
  • • eBPF maps(eBPF 映射)的引入,允许在内核空间和用户空间之间安全地共享数据
  • • 一组不断增长的 helper functions(辅助函数),允许 eBPF 程序与内核特性进行交互

最重要的补充之一是 eBPF verifier(eBPF 验证器)。在允许 eBPF 程序运行之前,验证器会检查它的安全性。这确保了程序不会导致内核崩溃、永远运行下去或以不安全的方式访问内存。

另一个关键的里程碑是将 eBPF 程序附加到 kprobes(k 探测点)的能力。Kprobes 允许检测内核中几乎任何指令。2015 年左右增加了对将 eBPF 程序附加到 kprobes 的支持,这极大地扩展了 eBPF 可以观察的内容。

到 2016 年,eBPF 已经被用于生产系统。Brendan Gregg(顺便说一句,看看他的作品,太棒了)在 Netflix 上进行性能跟踪的工作帮助 eBPF 广为人知,经常将其描述为赋予 Linux “superpowers”(超能力)

此后不久,一些大型项目开始采用 eBPF:

  • Cilium 使用 eBPF 构建高性能容器网络
  • Katran 是 Facebook 的一个开源项目,使用 eBPF 进行可扩展的 4 层负载均衡

随着采用率的增长,eBPF 成为一个独立的 Linux 子系统,有数百名内核开发人员为其做出贡献。多年来,指令数量上限等限制显著增加,从而允许更复杂和更强大的 eBPF 程序。

如今,eBPF 不再仅仅是关于数据包过滤,它是一种通用的、安全的和高性能的方式来扩展 Linux 内核。

内核空间 vs 用户空间

要理解 eBPF,我们首先需要清楚地理解 Linux kernel space(内核空间)和 user space(用户空间)之间的区别。

Linux 内核空间 是应用程序和它们运行的硬件之间的软件层。应用程序运行在一个称为 用户空间 的非特权层中,该层无法直接访问硬件。相反,应用程序使用 system calls (syscalls)(系统调用) 向内核发出请求。这些 syscalls 作为内核代表应用程序执行操作的接口。

硬件访问涉及许多操作,例如读取和写入文件、发送或接收网络流量以及访问内存。

以下是用户空间和内核空间之间的协调方式: 用户空间中的应用程序使用 syscall 接口向内核发出请求

作为应用程序开发人员,我们通常不直接使用系统调用。编程语言提供高级抽象和标准库来隐藏这些细节。

由于这种抽象,我们通常不知道内核在我们的程序运行时做了多少工作。为了更好地理解这一点,我们可以使用 strace 等工具,它显示了应用程序发出的所有系统调用。

例如,即使是像使用 cat 打印单词 hello 这样的简单命令也涉及 100 多个系统调用: strace 示例图示

由于应用程序严重依赖内核,因此观察它们与内核的交互可以让我们了解很多关于应用程序行为的信息。


为什么内核变更和模块有风险?

Linux 内核非常复杂,有超过 3000 万行代码。对如此庞大的代码库进行更改需要对现有代码有深入的了解,这使得内核开发对大多数开发人员来说具有挑战性。

为 Linux 内核做贡献不仅是一个技术挑战,也是一个社会挑战。由于 Linux 是一种通用的操作系统,被广泛使用,因此更改必须被社区,特别是 Linus Torvalds,接受为对整个生态系统有益。

这并不容易。只有大约三分之一的提交的内核补丁被接受。

即使在经过技术上合理的更改讨论、开发和合并之后,它也不会立即到达用户手中。虽然 Linux 每两到三个月发布一个新内核,但大多数用户依赖于 Debian、Red Hat、Alpine 或 Ubuntu 等发行版,它们发布的是较旧且更稳定的内核版本。因此,被接受的内核更改可能需要数年才能出现在实际生产环境中。

如下图所示,新功能从想法到生产可能需要数年时间: 向内核添加特性(Vadim Shchekoldin, Isovalent 的卡通)


内核模块

由于直接向内核添加特性需要花费大量时间和精力,因此内核模块提供了一种替代方案。内核模块可以按需加载和卸载,并允许开发人员扩展或修改内核行为,而无需更改核心内核。它们独立于官方 Linux 内核,不需要被接受到上游代码库中。

然而,这引入了一个主要的担忧:内核模块是否安全运行?

我们如何才能确保内核模块不包含攻击者可以利用的漏洞?用户如何信任模块不包含恶意代码?

因为内核代码以完整的系统权限运行,任何漏洞或恶意行为都可能产生严重的后果。这是 Linux 发行版需要很长时间才能采用新内核版本的主要原因之一。

eBPF 提供了一种非常不同的安全方法。eBPF 验证器 确保只有在 eBPF 程序安全运行时才加载它。它保证程序不会导致系统崩溃、进入无限循环或危及系统数据。

动态加载 eBPF 程序

eBPF 程序可以动态地加载到内核中并从内核中移除。一旦附加到事件,它们会在该事件发生时被触发。

例如,如果一个 eBPF 程序附加到文件打开 syscall,它将在任何进程打开文件时运行。当加载程序时,进程是否已经在运行并不重要。

与升级内核相比,这是一个主要的优势,升级内核通常需要系统重启。

因此,基于 eBPF 的可观测性和安全工具可以立即获得对系统上发生的一切的可见性。

开发人员可以使用 eBPF 快速创建新的内核级功能,而无需强制所有 Linux 用户接受相同的内核更改。 使用 eBPF 添加内核特性(Vadim Shchekoldin, Isovalent 的卡通)

eBPF 程序的高性能

eBPF 程序是一种非常有效的添加检测的方式。一旦加载,eBPF 程序会使用 JIT 编译器进行编译,并在 CPU 上作为原生机器指令运行。

此外,eBPF 程序避免了用户空间和内核空间之间的频繁切换,这些切换是昂贵的操作。这使得 eBPF 适用于高性能的可观测性和安全用例。

为什么云原生使情况变得更糟?

之前,我假设组织直接在他们自己的服务器上运行应用程序。实际上,大多数现代系统运行在云编排平台(如 Kubernetes、ECS)或无服务器平台(如 Lambda、Cloud Functions 或 Fargate)上。

在这些环境中,工作负载是自动调度的,在无服务器设置中,我们通常甚至不知道哪个物理服务器正在运行我们的代码。 内核中的 eBPF 程序可以观察运行在 Kubernetes 节点上的所有应用程序

由于这种抽象,传统的基于主机或应用程序级别的检测变得困难。我们通常不控制服务器,无法预测工作负载将在何处运行,并且无法轻易地修改应用程序代码或部署配置。

这就是 eBPF 变得强大的地方。

由于 eBPF 程序在内核内部运行,因此它们自动获得对节点上运行的所有进程的可见性,无论它们属于容器、Pod 还是无服务器工作负载。

与动态加载相结合,基于 eBPF 的工具提供了主要优势:

  • • 无需修改应用程序
  • • 无需更改 Kubernetes YAML 和配置
  • • 可以立即观察已经运行的工作负载

这使得基于 eBPF 的可观察性和安全工具在云原生环境中具有独特的超能力:深度、系统范围的可见性,而无需接触应用程序代码、Pod 生命周期或编排逻辑,这是基于 sidecar 的方法无法完全实现的。

总结

本章解释了为什么与 Linux 内核交互一直都很困难和有风险,以及 eBPF 如何通过提供一种安全、灵活和高性能的方式来扩展内核行为来改变这一点。它为理解 eBPF 的工作原理以及为什么它在现代系统中变得如此重要奠定了基础。

在接下来的章节中,还有更多关于 eBPF 和内核的知识需要学习和理解。因此,我尽量保持它们简单易懂,而不会扰乱书中实际的上下文。

  • 原文链接: jkrishna.xyz/blog/learni...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
jkrishna
jkrishna
江湖只有他的大名,没有他的介绍。