前言

在云原生社区及更广泛的技术领域中,eBPF 已成为近年来最热门的技术话题之一。在网络、安全、可观察性等领域,新一代强大的工具和项目正基于 eBPF 平台构建(并不断涌现)。相比从前,它们提供了更好的性能和精度。诸如 eBPF 峰会云原生 eBPF 日等 eBPF 相关会议吸引了成千上万的与会者和观众,截至撰写本文时,eBPF Slack 社区已有超过 14,000 名成员。

为何 eBPF 被选为众多基础设施工具的底层技术?它如何实现所承诺的性能提升?eBPF 如何在从性能追踪到网络流量加密等各不相同的技术领域中发挥作用?

本书旨在解答这些问题,通过让读者了解 eBPF 的工作原理,并提供编写 eBPF 代码的入门介绍。

这本书适合谁

本书适用于对 eBPF 感兴趣并希望深入了解其工作原理的开发者、系统管理员、运维人员和学生。它为那些希望自己编写 eBPF 程序的人提供了基础。由于 eBPF 为新一代的基础设施和工具提供了卓越的平台,因此未来几年内,eBPF 开发者将可能有很好的就业机会。

即使您并不打算亲自编写 eBPF 代码,本书对您仍然有用。如果您在运维、安全或任何涉及软件基础设施的角色中工作,现在或未来几年内,您很可能会接触到基于 eBPF 的工具。了解这些工具的内部工作原理将使您能够更有效地使用它们。例如,如果您知道事件是如何触发 eBPF 程序的,您将能够更好地理解基于 eBPF 的工具在显示性能指标时究竟在测量什么。如果您是一名应用开发者,您也可能会接触到一些基于 eBPF 的工具——例如,当您进行应用性能调优时,可能会使用像 Parca 这样的工具生成火焰图,显示哪些函数耗时最多。如果您在评估安全工具,本书将帮助您理解 eBPF 的优势所在,以及如何避免以一种天真的方式使用它,导致其对攻击的防御效果降低。

即使您现在并没有使用 eBPF 工具,我也希望本书能为您提供一些有趣的见解,让您了解 Linux 的一些您可能从未考虑过的领域。大多数开发者将内核视为理所当然,因为他们使用编程语言提供的便利高级抽象,使他们能够专注于应用开发工作——这已经足够艰难了!他们使用调试器和性能分析器等工具来有效地完成工作。了解调试器或性能工具的内部工作原理可能很有趣,但并非必不可少。然而,对许多人来说,深入挖掘以了解更多是有趣且充实的1。同样,大多数人会使用 eBPF 工具,而无需关心它们是如何构建的。正如 Arthur C. Clarke 所说,“任何足够先进的技术都与魔法无异”。但就我个人而言,我喜欢深入研究,找出魔法背后的原理。您可能和我一样,觉得有必要探索 eBPF 编程,以更好地了解这项技术的潜力。如果是这样,我相信您会喜欢这本书。

本书涵盖的内容

eBPF 正以相当快的速度不断发展,这使得撰写一部不需频繁更新的全面参考书变得相当困难。然而,有些基本原理和基础原则不太可能发生显著变化,这正是本书所讨论的内容。

第 1 章为本书奠定基础,介绍了 eBPF 这项技术为何如此强大,并解释了在操作系统内核中运行自定义程序如何实现诸多令人兴奋的功能。

在第 2 章中,内容变得更具体,您将看到一些 “Hello World” 的示例,向您介绍 eBPF 程序和映射(maps)的概念。

第 3 章深入探讨 eBPF 程序及其在内核中的运行方式,而第 4 章则探讨用户空间应用程序与 eBPF 程序之间的接口。

近年来,eBPF 的一大挑战是跨内核版本的兼容性问题。第 5 章介绍了解决这一问题的“一次编译,到处运行”(compile once, run everywhere,CO-RE)方法。

验证过程也许是区分 eBPF 和内核模块的最重要特征。我将在第 6 章中向您介绍 eBPF 验证器。

在第 7 章中,您将了解许多不同类型的 eBPF 程序及其附加点(attachment points)。其中许多附加点位于网络协议栈中,第 8 章将更详细地探讨了 eBPF 在网络功能中的应用。第 9 章则探讨了 eBPF 在构建安全工具方面的应用。

如果您想编写与 eBPF 程序交互的用户空间应用程序,有许多可用的库和框架来提供帮助。第 10 章概述了各种编程语言的选项。

最后,在第 11 章,我将展望 eBPF 领域可能出现的一些未来发展。

前置知识

本书假设您对 Linux 的基本 shell 命令和使用编译器将源代码转换为可执行程序的概念感到熟悉。书中包含一些简单的 Makefile 示例,假设您至少对 make 如何使用这些文件有最基本的了解。

书中有大量的 Python、C 和 Go 语言的代码示例。您不需要深入掌握这些语言即可从示例中获益,但如果您乐于阅读一些代码,您将能从本书中获得更多收益。我还假设您熟悉指针的概念,它用来标识内存位置。

示例代码和练习

本书包含大量的代码示例。如果您希望亲自尝试这些示例,可以访问 https://github.com/lizrice/learning-ebpf 获取配套的 GitHub 仓库及安装和运行代码的说明。

我还在大多数章节的末尾附上了练习,帮助您通过扩展示例或编写自己的程序来探索 eBPF 编程。

由于 eBPF 不断发展,您可用的特性取决于您运行的内核版本。许多适用于早期版本的限制在后来的版本中已被解除或放宽。Iovisor 项目提供了不同 BPF 特性在各内核版本中添加情况的有用概述,本书中我尽量注明了所描述特性被添加的具体版本。这些示例在 5.15 版本的内核上进行了测试,但在撰写本文时,一些流行的 Linux 发行版尚未支持如此新的内核版本。如果您在本书刚出版时阅读,可能会发现某些特性在您的生产环境所用的 Linux 内核上无法运行。

eBPF 只适用于 Linux 吗?

eBPF 最初是为 Linux 开发的。实际上,这种方法完全可以应用于其他操作系统——事实上,微软已经正在开发基于 Windows 平台的 eBPF 实现。我在第 11 章简要讨论了这一点,但本书其余部分将重点关注 Linux 的实现,所有示例也都基于 Linux。

本书中使用的约定

本书中使用了以下排版约定:

  • 斜体:用于表示新术语、URL、电子邮件地址、文件名和文件扩展名。

  • 等宽字体:用于程序列表,以及在段落中引用程序元素,如变量或函数名、数据库、数据类型、环境变量、语句和关键字。

  • 等宽粗体:显示用户应逐字输入的命令或其他文本。

  • 等宽斜体:显示应由用户提供的值或由上下文确定的值。

tip

此元素表示提示或建议。

note

此元素表示一般说明。

warning

此元素表示警告或注意事项。

1

在2017年巴黎的dotGo会议上,我做了一场展示调试器工作原理的演讲