Language:Chinese VersionEnglish Version

eBPF 已从一种晦涩的内核技术转变为过去十年中最重要的基础设施工具之一。Cilium 使用它来替换 kube-proxy。Falco 使用它进行运行时安全防护。Pixie、Parca 和 Pyroscope 使用它进行无需代码更改的持续性能分析。如果您在 2026 年运行任何重要的 Linux 工作负载,却没有对 eBPF 形成有效的理解,那么您的操作将存在重大盲点。

本文从实践层面解释 eBPF 的工作原理,概述了基于它构建的生产工具,并为您提供一个真实的图景,展示它在哪些方面真正增加了价值,以及在哪些方面炒作超过了现实。

eBPF 的本质

eBPF(扩展伯克利数据包过滤器)是一个内核子系统,允许您在 Linux 内核中运行沙箱程序,而无需修改内核源代码或加载内核模块。这些程序使用受限的 C 语言子集编写,编译为 eBPF 字节码,由内核验证器进行安全性验证,然后通过即时编译(JIT)转换为本地指令。

使 eBPF 有用的关键架构特性:

  • 安全性:验证器会静态分析所有可能的执行路径,确保没有无界循环、没有越界内存访问、没有内核崩溃。
  • 性能:JIT 编译的 eBPF 以接近原生的速度运行。无需切换到用户空间。
  • 挂接点:eBPF 程序可以附加到 kprobes(任意内核函数)、tracepoints(稳定的内核检测点)、XDP(内核网络栈之前的网络数据包处理)、流量控制入站/出站、LSM 钩子(Linux 安全模块)等。
  • 映射:eBPF 程序通过称为映射的类型化键值存储与用户空间通信并共享状态。哈希映射、环形缓冲区、LRU 映射和每 CPU 映射都可用。

重要的实际意义:eBPF 让您可以检测内核和拦截网络数据包,而无需编写内核代码、无需重启、无需修改应用程序。这就是为什么它背后有如此多的现代可观测性和安全工具。

编写一个最小化的 eBPF 程序

理解这些机制能帮助你更有效地使用基于 eBPF 构建的工具。以下是一个使用 libbpf 和 BPF CO-RE(一次编译,到处运行)方法的最小化跟踪示例:

// trace_open.bpf.c — 跟踪每个 openat() 系统调用并记录文件名 + PID
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

struct event {
    __u32 pid;
    char filename[256];
};

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);
} events SEC(".maps");

SEC("tracepoint/syscalls/sys_enter_openat")
int trace_openat(struct trace_event_raw_sys_enter *ctx)
{
    struct event *e;
    e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
    if (!e) return 0;

    e->pid = bpf_get_current_pid_tgid() >> 32;
    bpf_probe_read_user_str(e->filename, sizeof(e->filename),
                            (void *)ctx->args[1]);
    bpf_ringbuf_submit(e, 0);
    return 0;
}

char LICENSE[] SEC("license") = "GPL";

该程序附加到 openat 系统调用跟踪点,捕获 PID 和文件名,并将它们发送到环形缓冲区映射。用户空间消费者从环形缓冲区读取并处理事件。内核验证器会在程序运行前检查此程序 — 确保读取的文件名有边界,检查环形缓冲区分配是否为 NULL,以及程序是否终止。

在生产环境中,你会使用 libbpf、BCC 或 Cilium 的 ebpf-go 等框架,而不是手动编写这些代码,但理解其结构可以解释为什么 eBPF 工具具有特定的功能和限制。

eBPF 用于可观测性:生产工具

Pixie:无需插桩的应用可观测性

Pixie 是一个 CNCF 沙箱项目(由 New Relic 捐赠),它使用 eBPF 为 Kubernetes 工作负载提供自动可观测性 — 无需 SDK 更改、无需 sidecar 注入、无需代码部署。它通过附加到内核级钩子来捕获完整的请求/响应体、延迟直方图、CPU 分析和网络流量。

# 在 Kubernetes 集群上安装 Pixie
curl -s https://work.withpixie.ai/install.sh | bash
px deploy

# 查询服务的 HTTP 延迟(使用 PxL — Pixie 查询语言)
px run px/http_data -start_time '-5m' -- --svc=my-service

Pixie 在调试生产问题时特别有价值,无需预先插桩的跟踪。你可以看到服务实际执行的 SQL 查询、服务之间的 gRPC 负载以及 CPU 火焰图 — 所有这些都来自 eBPF 探针,且无需触碰应用程序代码。

Parca 和 Pyroscope:持续性能分析

持续性能分析是 eBPF 在生产系统中的最佳应用之一。Parca Agent 和 Grafana 的 Pyroscope 都使用基于 eBPF 的性能分析,以低开销(约 1-3% CPU)对所有进程的堆栈跟踪进行采样。

相比传统分析工具的主要优势:持续运行、无需修改应用程序、支持多种语言包括编译后的二进制文件。当生产环境在凌晨3点出现CPU峰值时,您已经拥有了分析数据。

# 运行 Parca Agent(在 Kubernetes 上作为 DaemonSet 部署)
kubectl apply -f https://raw.githubusercontent.com/parca-dev/parca-agent/main/deploy/manifests.yaml

# 或者在单个主机上独立运行
sudo parca-agent --http-address=":7071" 
  --node=my-node 
  --store-address=parca.example.com:7070

Tetragon: 运行时安全执行

Cilium 的 Tetragon 超越了 Falco 仅检测的模式。使用 eBPF LSM 钩子,Tetragon 不仅可以检测可疑行为,还能执行策略——在操作完成前,在内核空间终止进程或阻止网络连接。

# 示例 Tetragon TracingPolicy:阻止容器中任何 /bin/bash 的执行
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: block-shell-exec
spec:
  kprobes:
  - call: "security_bprm_check"
    syscall: false
    args:
    - index: 0
      type: "linux_binprm"
    selectors:
    - matchArgs:
      - index: 0
        operator: "Equal"
        values:
        - "/bin/bash"
        - "/bin/sh"
      matchActions:
      - action: Sigkill

此策略会终止任何尝试执行 shell 二进制文件的进程。无需内核补丁,无需重启,并且在 shell 运行前就会触发。这种运行时执行本可以防止多起知名的容器逃逸攻击。

eBPF 在网络中的应用:Cilium 和 XDP

Cilium:完全替代 kube-proxy

Cilium 使用基于 eBPF 的数据平面替代 kube-proxy,完全在内核中处理 Kubernetes 服务路由、NetworkPolicy 执行和负载均衡——无需 iptables 规则,无需东西流量的 conntrack 表。

性能差异并非微不足道。iptables 的规则处理复杂度为 O(n),其中 n 是规则数量。而 eBPF 映射的查找复杂度为 O(1)。在规模上(数千个服务,数百个节点),这决定了网络堆栈是否会成为瓶颈。

# 安装 Cilium 并替代 kube-proxy
cilium install 
  --set kubeProxyReplacement=strict 
  --set k8sServiceHost=<API_SERVER_IP> 
  --set k8sServicePort=6443

# 验证 kube-proxy 已完全替代
cilium status --verbose | grep "KubeProxyReplacement"
# KubeProxyReplacement:    Strict

XDP:数据包处理的内核旁路

eXpress Data Path (XDP) 是一个 eBPF 钩子,在内核网络堆栈分配套接字缓冲区之前运行。此时可以以极低的开销丢弃、修改或重定向数据包——通常每个数据包 1-2 微秒,而通过完整堆栈则需要 30-50 微秒。

这使得 XDP 在 DDoS 缓解方面变得实用(以线路速率丢弃攻击流量而不使内核饱和)、负载均衡(Facebook 的 Katran 使用)以及不需要内核 TCP/IP 的自定义协议实现。

全面投入前需要了解的 eBPF 局限性

内核版本要求

现代 eBPF 功能需要现代内核。BPF CO-RE 至少需要 5.2 版本。BTF(BPF 类型格式,启用 CO-RE)必须编译到内核中。许多 eBPF 安全功能需要 5.7+ 版本。实际上:

  • Ubuntu 22.04 LTS 内核 5.15 — 完全支持
  • RHEL 8 内核 4.18 — 有限支持,有反向移植的功能
  • Amazon Linux 2 内核 4.14 — 显著限制
  • Amazon Linux 2023 内核 6.1 — 完全支持

在采用任何基于 eBPF 的工具之前,请审核您集群中的内核版本。异构环境使这一过程变得困难。

验证器严格且错误信息晦涩难懂

直接编写 eBPF 程序意味着要处理验证器的拒绝。像 invalid indirect read from stack off -16+0 size 4 这样的错误信息需要理解验证器的内存模型。libbpf、ebpf-go 和 BCC 等框架抽象了这一点,但当生产工具出现问题时,调试需要理解验证器正在执行什么。

仍需要特权访问

加载 eBPF 程序通常需要 CAP_BPF(内核 5.8+)或 CAP_SYS_ADMIN。存在用于有限用例的无特权 eBPF,但无法访问大多数有用的钩点。在容器中运行的基于 eBPF 的工具需要提升的权限 — 这是评估这些工具时的重要安全考虑因素。

实际采用路径

对于希望开始从 eBPF 获得价值而不直接深入编写程序的团队:

  • 步骤 1: 如果您还没有锁定其他选择,请将 Cilium 作为您的 Kubernetes CNI 部署。kube-proxy 替代方案提高了网络性能,并基于身份提供 NetworkPolicy 执行。
  • 步骤 2: 添加 Tetragon 以获得运行时安全可见性。即使在审计模式(无执行)下,进程和网络事件流对于理解您的工作负载实际执行的操作也非常有价值。
  • 步骤 3: 评估 Parca 或 Pyroscope 进行持续性能分析。将代理作为 DaemonSet 部署,并通过 Pyroscope 数据源与您现有的 Grafana 堆栈集成。
  • 步骤 4: 在您操作这些工具几个月并培养了对 eBPF 模型的直觉后,考虑使用 ebpf-go 构建自定义程序,用于工作负载特定的检测。

结论

eBPF 已经从根本上改变了 Linux 可观测性、网络和安全领域的可能性。基于 eBPF 构建的工具 — Cilium、Tetragon、Pixie、Parca — 已经投入生产环境并大规模部署。性能和可见性的提升是真实且经过验证的。

入门门槛在于内核版本要求以及需要转变思维模式来理解内核钩子点和映射。但你不需要编写 eBPF 程序就能从生态系统中受益。从这些工具开始,建立直觉,当你的需求超出现成解决方案时,再逐步添加自定义程序。

趋势很明显:eBPF 正在变得像 cgroups 和 namespaces 一样成为 Linux 基础设施的重要组成部分。深入理解 eBPF 的团队将在性能优化和安全态势方面获得持久的优势。

By Michael Sun

Founder and Editor-in-Chief of NovVista. Software engineer with hands-on experience in cloud infrastructure, full-stack development, and DevOps. Writes about AI tools, developer workflows, server architecture, and the practical side of technology. Based in China.

Leave a Reply

Your email address will not be published. Required fields are marked *

You missed