【AICon】 如何构建高效的 RAG 系统?RAG 技术在实际应用中遇到的挑战及应对策略?>>> 了解详情
写点什么

新手入门:探索 eBPF 的可观测性与安全性工作流

作者;Michael Friedrich

  • 2023-07-28
    北京
  • 本文字数:10791 字

    阅读完需:约 35 分钟

新手入门:探索eBPF的可观测性与安全性工作流

本文分享了学习 eBPF 的经验,eBPF 是一种新的云原生技术,其目标是改善可观测性和安全性工作流。我们可能感觉它的入门门槛很高,通过 eBPF 工具来辅助生产环境调试的步骤会很多。本文将会介绍如何使用相关的工具并将其应用到自己的开发中,请逐步迭代自己的知识,并将其用到更高级的使用场景中。最后,我们会讨论如何在 CI/CD 中实现自动化开发及其面临的挑战。

如何开始入门 eBPF?


我第一次听说 eBPF 是在 2021 年,当时它是与可观测性相关的主题一起出现的,起初我并不能真正理解它的含义。描述中声称这是一种收集事件数据的新方法,有助于提升可观测性,也有助于实现安全的可观测性和实际执行。


实际上,我后来才知道,Falco 使用 eBPF 来探查 Kubernetes 中容器的活动。我的学习历程是将 Falco 视为云原生的安全工具,而没有去质疑其底层的技术。“Hacking Kubernetes”一书帮助我完善了对容器运行时、eBPF 和安全执行的学习。


KubeCon EU 2022上的eBPF日,以及后续的eBPF峰会活动,都有助于说明这一点。eBPF 的学习策略与技术领域的其他知识类似,也就是倾听、做笔记,但你依然无法理解它的所有内容。


参加讲座和阅读文章时,我们经常会遇到一些需要认识的术语模式,比如,我立即记住的术语包括 eBPF、BPF、bcc、bpftrace 和 iovisor。Brendan Gregg的博客也经常被提及。


在一个社区聚会上,通过自由讨论营(barcamp)式的演讲,我问到,“如何开始使用 eBPF?”。随后,我们使用三张幻灯片拉开了关于它如何运行的讨论,一起验证了相关的知识,并思考了其使用场景。在 eBPF 峰会上,有一个名为 Capture-the-Flag的环境可以进行学习,这吸引我停下脚步并亲自进行探索挑战。随后,我决定在自己的公共学习平台 o11y.love 上收集所有的eBPF资源,并决定以公开的方式进行学习,记录在这个过程中遇到的所有错误、误解和问题。


内核开发听起来很难,而且理解和入门 eBPF 可能存在一定的障碍。对于利用 eBPF 的工具和库,改变使用它们的方法,并配合生产环境的用例(例如在生产中进行调试),这极大地帮助了我的学习和迭代。对 Linux 操作系统、资源处理和故障排除的一般理解也很有助益。


更高层次的阐述和 ebpf.io 上的描述图片有助于对 eBPF 架构的一般理解。我非常喜欢来自 Brendan Gregg 的解释


“eBPF 对 Linux 的作用就像 JavaScript 对 HTML 的作用。(某种程度上,可以这么说。)因此,JavaScript 可以让我们定义在点击鼠标等事件中运行的小型程序,而不再是静态的 HTML 站点,这些程序会在浏览器的安全虚拟机中运行。有了 eBPF 之后,我们不再是一个固定的内核,而是可以编写在磁盘 I/O 等事件上运行的小型程序,这些程序会在内核的安全虚拟机中运行。实际上,eBPF 更像是运行 JavaScript 的 v8 虚拟机,而不是 JavaScript 本身。eBPF 是 Linux 内核的一部分。”


eBPF 被添加到 Linux 内核中,以实现小型的沙箱程序。这兼顾了稳定的内核需求和少量的创新可能性,而 eBPF 程序能够有助于扩展和驱动创新,而不会阻碍内核的发展。


eBPF 的用例包括高性能网络和负载均衡、应用程序的追踪和性能问题的排查。此外,细粒度的安全可观测性和应用/容器的运行时安全执行也是我能想到的场景。


编写 eBPF 程序是很难的,内核期望的是字节码,但是它手动编写的效率并不高。因此,需要有一个抽象层,包括从更高级的编程语言生成字节码的编译器。在这种情况下,经常涉及到的工具是 Cilium、bcc 和 bpftrace。eBPF 程序的校验发生在从字节码向机器特定指令集的即时编译过程中。这使得在 CI/CD 工作流中进行静态校验更加困难。稍后,我们会看到更多这方面的内容。


在了解了需求之后,真正的问题在于,我们有什么实际的例子可以尝试和学习,然后深入研究实际的源码?

正式开始:游乐场


Brendan Gregg 的学习eBPF跟踪:教程和样例博文是一个很好的起点。不同的尝试和路线最终都会回到这里进行自学。在深入研究库和 eBPF 程序如何构建之前,在命令行上尝试不同的工具并测试它们的效果,这是一个很好的策略。


注意:Liz Rice 的“Learning eBPF”一书能够有助于进一步降低入门门槛,该书于 2023 年 3 月出版。


推荐的入门方式是选择具有最新内核(大约 4.17 版本)的 Linux 发行版,如 Ubuntu 22.04 LTS。请使用本地虚拟化方法,或在你喜欢的云厂商上生成一个虚拟机。下面的样例使用 Hetzner Cloud CLI 来生成一个新的 Ubuntu 虚拟机:


$ hcloud server create --image ubuntu-22.04 --type cx21 --name ebpf-chaos
复制代码


请根据你的需要重新创建设置过程,可以考虑编写 Ansible playbooks 或脚本来重复安装步骤。这对跟团队成员分享具体学习环境中使用的工具和库会很有帮助。本文讨论的工具和想法在GitLab上有基于Ansible的样例。有些默认的工具需要安装(git、wget、curl、htop 和 docker),还有 eBPF、混沌实验和可观测性等更具体的用例。


接下来的章节将讨论 eBPF 工具的样例。要构建和安装它们,需要 Linux 内核头文件和额外的依赖。在 Ubuntu 22 LTS 上还有一个额外的步骤就是启用DDebs仓库,以访问调试符号(debug symbol),接下来是一个完整的编译器工具链。该针对eBPF的Ansible配置详细描述了安装步骤。你可以查看 Git 的历史记录,了解学习的步骤以及这个过程中的错误。下面的几节主要是运行这些工具,并阐述它们的使用场景。

跟踪系统调用


你可能已经使用过strace命令来跟踪运行中的二进制文件的系统调用,查看是否有文件被打开和权限错误等。Brendan Gregg 的教程博客建议从提供execsnoop命令的bcc toolchain开始。它可以跟踪exec()系统调用。一个很容易的测试方法是打开 SSH 连接,或者在另外一个终端上执行curl opsindev.news命令。


$ execsnoop -t
115.816 curl 879320 879305 0 /usr/bin/curl opsindev.news118.481 sshd 879322 67197 0 /usr/sbin/sshd -D -R124.287 sshd 879324 67197 0 /usr/sbin/sshd -D -R
复制代码


我们已经学习了一种跟踪系统调用的新方法。bcc 工具链提供了更多实用的工具和用例。从学习的角度来讲,还有哪些工具可以用来深入研究 eBPF 呢?

bpftrace:高级的跟踪语言


Bpftrace提供了自己的高层级跟踪语言,类似于 DTrace 这样的调试框架。乍看上去,在线样例可能会让人无所适从,但由于我们使用的是测试虚拟机,所以可以运行这些样例,以后再分析语言。Bpftrace 允许我们跟踪更多的系统调用,例如open()。这个方法可以用来打开文件、套接字等,更通用地来讲,是进程可以打开的所有内容,不管是善意还是恶意的。它可以视为strace命令的一种更为现代的方式。


为了使用可预测的样例来测试 bpftrace,我们可以使用这个最小化的 C 程序,它打开一个文件句柄来创建新文件(源码):


#include <stdlib.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>
int main(){ int fd;
if ((fd=open("ebpf-chaos.txt", O_WRONLY | O_CREAT, 0660)) == -1) { printf("Cannot open file."); exit(1); }
close(fd);}
复制代码


使用 gcc 编译器编译 C 程序,并在启动 bpftrace 命令后运行它。如果opensnoop.bt命令在 Ubuntu 22 LTS 上运行失败的话,请从 DDeb 仓库安装调试符号。


$ gcc sim-open-file.c -o sim-open-file$ chmod +x sim-open-file$ ./sim-open-file
复制代码


$ bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
Attaching 1 probe...sim-open-call /etc/ld.so.cachesim-open-call /lib/x86_64-linux-gnu/libc.so.6sim-open-call
复制代码


跟踪语言允许挂钩进入特定的系统调用。要找到正确的系统调用名称,需要慢慢试验,可能还会遇到错误。我不得不将sys_enter_open改为sys_enter_openat来触发 C 程序中的打开文件的调用。bpftrace -l可以列出所有可跟踪的系统调用。


$ bpftrace -l 'tracepoint:syscalls:sys_enter_open*'tracepoint:syscalls:sys_enter_opentracepoint:syscalls:sys_enter_open_by_handle_attracepoint:syscalls:sys_enter_open_treetracepoint:syscalls:sys_enter_openattracepoint:syscalls:sys_enter_openat2
复制代码


上述代码会将命令和文件名的路径打印到终端上。访问要打印的文件名需要阅读 C 结构的代码,以了解在这种情况下,哪些属性是可用的。


学习曲线的“顿悟时刻(aha moment)”不仅仅会看到文件打开和写入调用,而且还会加载库的依赖关系(stdlib需要libc)。bfptrace 工具对于验证二进制文件是否真的加载了某些库是非常有用的,其次是使用lddnm来窥探依赖关系和调试符号。


$ ldd sim-open-call    linux-vdso.so.1 (0x00007ffe42c78000)    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f24c7247000)    /lib64/ld-linux-x86-64.so.2 (0x00007f24c747d000)
$ nm sim-open-call | grep open U open@GLIBC_2.2.5
复制代码

深入研究源码和 eBPF 程序


BPF编译器集合(BPF Compiler Collection,BCC)提供了一些样例来学习内核和用户空间之间的数据传输和交互。以前的样例只是挂钩系统调用并立即返回。BCC 在 C 代码中提供了内核插装,并允许使用 Python 或 Lua 编写前端用户空间的应用。按照描述,使用场景包括性能分析和网络流量控制,这都是很好的洞察点,并为以后的知识验证增加了学习难度。Python 和 C 语言知识有助于更容易地深入研究这些样例。


另外,基于我的研究过程,推荐libbpf库,因为它的bootstrap项目提供了更多的演示应用。它们提供了真实的程序,可以用来实现自己的第一个 eBPF 程序。其中有一个样例是使用 Rust 编写的,允许我们按照XDP规范检查网络流量以及数据包的大小。eXpress Data Path(XDP)允许在大规模网络调用时挂钩发送/接收的网络数据包,这会发生在中断之后和内存分配之前。例如,这可以用来悄悄地丢弃数据包(请注意后面高级的 eBPF 程序开发用例)。


用户需要指定端口号,这会导致再一轮的试验和错误排查。使用eth0作为接口名称无法成功运行。这个样例的输出源自同一台主机上运行的 Prometheus 服务器实例,产生的网络流量来自以 HTTP 端点探查监控目标的输出。


$ apt install rustc cargo clang rustfmt
$ git clone https://github.com/libbpf/libbpf-bootstrap$ cd libbpf-bootstrap/examples/rust$ cargo build$ cargo run
$ sudo ./target/debug/xdp 1 #if number
$ sudo tail -f /sys/kernel/debug/tracing/trace_pipe
prometheus-660 [001] d.s11 295903.782373: bpf_trace_printk: packet size: 74prometheus-659 [000] d.s11 295903.782735: bpf_trace_printk: packet size: 74prometheus-659 [000] d.s11 295903.782762: bpf_trace_printk: packet size: 54prometheus-671 [001] d.s11 295908.509751: bpf_trace_printk: packet size: 352prometheus-671 [001] d.s11 295908.513184: bpf_trace_printk: packet size: 4162prometheus-671 [001] d.s11 295908.513218: bpf_trace_printk: packet size: 66prometheus-671 [001] d.s11 295908.513295: bpf_trace_printk: packet size: 4162prometheus-671 [001] d.s11 295908.513307: bpf_trace_printk: packet size: 66prometheus-671 [001] d.s11 295908.513368: bpf_trace_printk: packet size: 1630
复制代码


在构建和运行更多的样例后,我们并不完全清楚复制或修改源码是否为一个好的策略。如何将 XDP 样例缩减至最小的尺寸?也许有更好的方法来逐步入手编写 eBPF 程序代码,并增加学习过程中获得的经验。


eBPF 程序开发,学习更多用例


在深入研究如何开发自己的程序之前,了解 BPF 和 eBPF 的基础知识是很重要的。eBPF 是 Berkley Packet Filter(BPF)的一个扩展版本,它提供了一个运行在 Linux 内核中的抽象虚拟机,在受控的环境中运行 eBPF 程序。从根本上说,Linux 内核中的“老”BPF 标准可以被称为“经典BPF”,以便于和eBPF进行区分


我们可以从尝试 bcc 工具开始,运行 bpftrace 并识别在日常业务和事件中有助于 SRE 和 DevOps 工程师的用例。这可能包括跟踪程序的启动/退出、查看控制组(cgroups)、观察 TCP 连接、检查网络接口等等。建议尽可能保持用例的简单性,以确保稳定的学习曲线。


在验证了关于 eBPF 的基础知识并定义了用例之后,请以库和工具链的形式探寻抽象的概念。现代编译器和库可用于 Go、Rust 和 C/C++。在决定编写 eBPF 程序之前,建议先学习基本的编程语言。根据我自己的经验,在具有 C++或 Python 知识之后,学习 Rust 是一条可行的发展道路。这有助于避免内存处理相关的运行时错误,与 C/C++ eBPF 程序相比,可以说这是一种更安全的方法。


Cillium 在一个Golang的开源库中实现了它的 eBPF 功能。除了学习编写自己的 eBPF 程序外,该库还提供了如下用例:将程序附加到入口/出口、计算 egress 流量包,以及探查网络接口(请注意 XDP 术语,以供后续学习)。XDP 程序可以用 Go 编译器工具链进行构建,并接受接口名称作为命令行参数。它使用 map 来持久化特定 IP 地址的网络包的数量;对于 Kubernetes 节点上的任意类型的网络接口,探查容器流量或跟踪嵌入式硬件的流量都是很好的使用场景。



如果你觉得编写 Rust 代码更舒服的话,aya-rs 的维护者提供了一个Rust开发人员工具链,包含一本带有教程的图书。书中的样例实现了一个类似的 XDP 网络流量场景,可以直接从 Cargo 构建链中运行,使开发过程更加高效。


$ git clone https://github.com/aya-rs/book aya-rs-book$ cd examples/xdp-hello$ cargo install bpf_linker$ cargo xtask build-ebpf$ cargo build
$ RUST_LOG=info cargo xtask run
复制代码


样例程序没有跟踪 IP 地址及其数据包的数量,但是这可以作为一个很好的练习,模仿 Go 库样例中的行为。



aya-rs 的其他实际用例是持续剖析(profiling),Polar Signals 的开发人员将 Rust 库用到了 Parca 代理中,用于自动的函数调用栈分析和更好的内存安全性(来自KubeCon EU 2022 eBPF日上的幻灯片Pull Request)。


有不同的方式来着手开发 eBPF 程序。请记住,该架构遵循将字节码编译的 eBPF 程序加载到内核,并需要一个用户空间的“收集器(collector)”或“打印器(printer)”。通信是通过套接字或文件句柄进行的。

测试和校验 eBPF 程序


在 CI/CD 流水线中自动化测试 eBPF 程序是很棘手的事情,因为内核会在加载时验证 eBPF 程序并拒绝潜在的不安全程序。测试将会需要一个新的虚拟机沙箱,加载 eBPF 程序,并模拟内核和 eBPF 程序相关的行为。需求包括触发事件,再次触发 eBPF 程序代码所订阅的钩子。根据不同的目的,这会涉及到不同的内核接口和系统调用(网络、文件访问等)。创建一个独立的单元测试 mock 是很难的,需要开发人员模拟一个运行中的内核。


有人试图将eBPF验证器转移到内核之外,并允许在 CI/CD 中测试 eBPF 程序。同时,在 CI/CD 中加载 eBPF 程序需要一个运行中的 Linux 虚拟机,其 CI/CD 的 runner/executor 要具有较高的权限。在 Ubuntu 22 LTS 中,加载非特权程序默认已被禁用,可能需要通过运行sudo sysctl kernel.unprivileged_bpf_disabled=0来启用。

CI/CD 中的持续测试


为了提供持续测试的 CI/CD runner 环境,建议使用 Ansible/Terraform 生成一个 Linux 虚拟机,安装 CI/CD runner,将其注册到 CI/CD 服务器上,并准备好加载和运行 eBPF 程序的需求。对于不同的供应商来说,这是一个通用的模式。下面的样例使用 Ansible 安装并注册 GitLab Runner 到 GitLab.com 项目中,然后使用它来构建和运行 eBPF 程序。GitLab Runner 注册了标签ebpf,它将只会执行使用了该标签的 CI/CD job。


---
- name: GitLab Runner for eBPFhosts: allvars:ansible_python_interpreter: /usr/bin/python3tasks:- name: Get GitLab repository installation scriptget_url:url: "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh"dest: /tmp/gitlab-runner.script.deb.shmode: 0744- name: Install GitLab repositorycommand: bash /tmp/gitlab-runner.script.deb.shargs:creates: "/etc/apt/sources.list.d/runner_gitlab-runner.list"become: true- name: Install GitLab Runnerapt:name: gitlab-runnerstate: presentallow_downgrade: truebecome: trueenvironment:GITLAB_RUNNER_DISABLE_SKEL: "true"
- name: Allow the gitlab-runner user to run any commands as root with sudo -u rootcommunity.general.sudoers:name: gitlab-runner sudostate: presentuser: gitlab-runnerrunas: rootcommands: ALL # Review this for production usage. For demos, it is enabled, and forked MR CI/CD builds won't run.
复制代码


注册需要gl_runner_registration_token变量,该变量来自 GitLab 项目中针对 CI/CD Runners 的配置。


---- name: GitLab Runner for eBPF - register oncehosts: allvars:ansible_python_interpreter: /usr/bin/python3tasks:- name: "Configure GitLab Runner (running to populate config.toml)"command: >gitlab-runner register--non-interactive--url "https://gitlab.com/"--executor "shell"--tag-list ebpf--registration-token="{{ gl_runner_registration_token }}"
复制代码


GitLab runner 可以在项目设置的CI/CD > Runners中看到。

在 CI/CD 中测试基于 Rust 的 eBPF 程序


我们使用一个实际的 eBPF 程序来尝试一下 CI/CD 工作流,这里使用 aya-rs Rust 库模板作为演示样例。首先,在 Linux 虚拟机上本地安装 Rust 和所需的 eBPF,以验证一切均能正常运行。


curl https://sh.rustup.rs -sSf | shsource "$HOME/.cargo/env"
rustup install stablerustup install nightly
rustup default stablerustup toolchain add nightlyrustup component add rust-src --toolchain nightly
# required for cargo-generateapt -y install libssl-dev
cargo install cargo-generatecargo install bpf-linkercargo install bindgen-cli
复制代码


接下来,生成一个模板骨架树,用于使用 XDP(eXpress Data Path)类型创建一个演示程序。探查ebpf-chaos-demo-xdp/src/main.rs中的代码,并更新网络接口名。然后,构建并运行程序,将日志级别设置为 info(或 debug)。


cargo generate --name ebpf-chaos-demo-xdp -d program_type=xdp https://github.com/aya-rs/aya-template.git
RUST_LOG=info cargo xtask run
复制代码


示例代码由两部分组成:ebpf-chaos-demo-xdp-ebpf/src/main.rs中的内核空间 eBPF 程序和ebpf-chaos-demo-xdp/src/main.rs中的用户空间程序,后者会加载 eBPF 程序并将其附加至内核跟踪点。为了只构建 eBPF 程序,我们可以调用build-ebpf xtask 并使用llvm-objdump命令检查字节码:


cargo xtask build-ebpf
llvm-objdump -S target/bpfel-unknown-none/debug/ebpf-chaos-demo-xdp
复制代码


完整的源代码位于该GitLab项目中,可以使用 GitLab CI/CD 流水线进行测试。注意,它需要在 runner 环境中安装 Rust 工具链。随后的流水线运行将会使用配置好的缓存。该流水线有三个 job:


  • install-deps准备 Rust 环境,这需要将CARGO_HOME变量指定为 runner 的项目目录。

  • aya-rs-xdp-build-ebpf构建核心 eBPF 程序,并运行llvm-objdump命令。

  • aya-rs-xdp-run运行用户空间程序,这需要 sudo 权限。它会将命令放到后台,捕获 stdout,睡眠 60 秒,然后使用pkill来杀死 xtask 命令,最后打印捕获到的输出。


对输出分析进行增强以及思考运行 eBPF 程序的更多测试报告是留给读者的练习。


# eBPF GitLab Runner required for this project# Note: Various commands need sudo/root access on the Linux host, see ansible-config/.# By default, for security reasons, CI/CD pipelines are not run from forks in the parent project.# See https://docs.gitlab.com/ee/ci/pipelines/merge_request_pipelines.html#use-with-forked-projects  default:  tags:    - ebpf
stages: - pre - build - run
variables: RUST_LOG: "info" RUNTIME: 300 # set to >= 5*60 = 300s because cargo xtask run also compiles the binary first
# These steps should not take long after subsquent runs on the Linux VMinstall-deps: stage: pre script: - sudo apt install libssl-dev # required for cargo-generate on Ubuntu 22 LTS - curl https://sh.rustup.rs -sSf -o rustup.sh - sh rustup.sh -y --profile default - source "$HOME/.cargo/env" - rustup install stable - rustup install nightly - rustup default stable - rustup toolchain add nightly - rustup component add rust-src --toolchain nightly # 'cargo install' is not idempotent. --force takes too long. Treat an error as 'ok, installed' here. - cargo install cargo-generate bpf-linker bindgen-cli || true
aya-rs-xdp-build-ebpf: stage: build script: - cd examples/ebpf-chaos-demo-xdp - source "$HOME/.cargo/env" - cargo xtask build-ebpf - llvm-objdump -S target/bpfel-unknown-none/debug/ebpf-chaos-demo-xdp
aya-rs-xdp-run: stage: run # We need to send the cargo xtask run command into the background, capture stdout, kill it after a defined interval, and generate a test report for CI/CD script: - cd examples/ebpf-chaos-demo-xdp - source "$HOME/.cargo/env" - rm ${CI_PROJECT_DIR}/run.pid - nohup cargo xtask run > ${CI_PROJECT_DIR}/nohup.out 2>&1 & echo $! > ${CI_PROJECT_DIR}/run.pid - sleep $RUNTIME - kill -s TERM `cat ${CI_PROJECT_DIR}/run.pid` || true - rm ${CI_PROJECT_DIR}/run.pid - cat "${CI_PROJECT_DIR}/nohup.out" - echo "Finished running eBPF program. TODO - analyze the output more." artifacts: expire_in: 30 days paths: - ${CI_PROJECT_DIR}/nohup.out
复制代码


该截屏显示了运行 eBPF 程序的 job,以及捕获网络数据包的日志输出。根据对源代码的修改,输出会发生变化并且可以进行测试。一个思路是以机器可读的格式总结捕获到的数据包,并在终止时创建一个汇总表。在 CI/CD 以及命令行中,这种方式更易于消费和理解。



将进程放入后台的方法可能无法正确地唤醒它,这可能需要更好的信号处理实现。它远远谈不上完美,你可以在这个合并请求中看到我的学习历史。可能有更好的方式来构建要发布的二进制文件,并通过supervisorctlsystemd命令来启动它,这是下一个学习步骤。终止和卸载过程的实现比较棘手。下面的代码片段实现了正确的信号处理,但是无法始终从运行中的内核卸载已注册的 XDP 链接。另一种方法是为每次的 CI/CD 运行生成一个新的 Linux 虚拟机,以避免这些可重复性相关的失败。但是,其缺点是我们需要一个 Rust 构建的远程缓存,以避免较长的 CI/CD 构建运行时间。


// Implement signal handling for CTRL+C and SIGTERMuse tokio::signal::unix::{signal, SignalKind};

let program: &mut Xdp = bpf.program_mut("ebpf_chaos_demo_xdp").unwrap().try_into()?; program.load()?; program.attach(&opt.iface, XdpFlags::default()) .context("failed to attach the XDP program with default flags - try changing XdpFlags::default() to XdpFlags::SKB_MODE")?;

// Implement signal handling for CTRL+C (SIGINT) and SIGTERM // CTRL+C can be used for terminal tests // SIGTERM will be sent from CI/CD jobs to the background process let mut sigterm = signal(SignalKind::terminate())?; let mut sigint = signal(SignalKind::interrupt())?;
tokio::select! { _ = sigterm.recv() => { println!("SIGTERM shutting down") } _ = sigint.recv() => { println!("SIGINT shutting down") } }
Ok(()) // Destroying the bpf object will detach and cleanup the loaded program. // Debug with 'bpftool link show'}
复制代码

CI/CD 和 DevSecOps 工作流的额外待办事项

剩下的挑战就是扩展 eBPF 程序以生成测试报告,并创建运行时测试环境,即通过用 curl 命令运行网络流量测试周期,并验证输出包的确切大小。另外,架构也很重要,要么 eBPF 程序被加载到内核中,并且有一个用户空间应用来读取其结果,要么 eBPF 程序是一个单一的二进制文件,直接附加其探针。后者需要在 CI/CD job 中将程序发送至后台,捕获它的输出,执行测试,然后合并测试报告。对于 DevSecOps 工作流来说,这个过程还有许多需要改进的地方,但我相信在不久的将来我们会达到最终的目的。


代码覆盖是测试 eBPF 程序的另一个新领域。目前并没有太多的工具帮助开发人员理解代码在 Linux 内核中运行时的路径,哪些代码区域会受到影响,哪些代码没有被覆盖到。bpfcov是由Elastic的工程师创建的,以帮助解决这个问题,让开发人员了解 eBPF 程序的代码执行路径。在 CI/CD 中运行自动化的代码质量和安全扫描也是一项挑战:如何确定一个有可能拖慢内核操作的编程错误呢?比较有意思的是,我们可以看一下 eBPF 程序的持续剖析(continuous profiling)是否可以实现(本身就是使用 eBPF 的,如Parca项目)。还有一些编程模式会规避内核验证器,并造成对软件供应链的安全攻击,通过贡献的拉取和合并请求,将恶意代码注入到已发布的 eBPF 程序中。这需要DevSecOps工作流来确保安全措施行之有效。AI 可能也会提供一些帮助。

结论


eBPF 是一种收集可观测性数据的新方法,它有助于实现网络洞察力,以及安全的可观测性和执行。为了获得最好的库、工具和框架,我们需要一起公开学习,以降低知识的壁垒,并使每个人都能做出贡献。从测试现有的工具到编写 eBPF 程序的详细教程,我们还有很长的路要走。在 CI/CD 中进行 eBPF 程序测试和验证是一项重要的工作,接下来就是将所有的想法带到上游,降低使用和贡献 eBPF 开源项目的入门门槛。


要想开始相关的工作,需要启动一个 Linux 虚拟机,使用脚本/Ansible 进行可重复的设置,并进行测试和开发。当接口名称和内核技术阻碍学习的进度时,那就回退一步,你并没有必要完全理解 eBPF 的全部内容。当遇到生产环境中断时,对数据收集有一般化的了解能够提供一定的帮助。最后,但同样重要的是,这里有个提示,那就是当调试 eBPF 程序时,考虑在多个发行版上进行测试,避免遇到内核相关的缺陷。


作者简介:

Michael Friedrich 是 GitLab 的高级开发人员布道者,专注于可观测性、DevSecOps 和 AI。Michael 创建了 o11y.love 作为可观测性学习平台,并在他的 opsindev.news 通讯中分享技术趋势以及对 day-2ops、eBPF、AI/MLOps 的见解。在没有旅行和远程工作的时候,他喜欢搭建乐高模型。


原文链接:

Learning eBPF for Better Observability


相关阅读:

颠覆传统、应用大爆发,eBPF 何以改变 Linux?

2023-07-28 08:003774

评论

发布
暂无评论
发现更多内容

分布式AI在LLM时代的技术深度探索

不在线第一只蜗牛

人工智能 AI lee

销售易取得500强客户背后的实践与进化

B Impact

海外HTTP代理哪家最好用?Rola-IP与StormProxies的全方位数据对比

Geek_bf375d

矢量图设计软件层出不穷,CorelDRAW为何无人能替?

淋雨

设计 矢量图 CorelDraw 绘画 设计软件

Mac 版截图工具链

Eric 老乌龟

macos 工具

Linux cat命令

攻城狮Wayne

一物一码需求,标签制作功能轻松解决

草料二维码

二维码 二维码生成 标签制作 一物一码

低代码工具的常见用例与受众市场

树上有只程序猿

低代码

荣誉 | 观测云登榜「2023 中国好 SaaS TOP 10 SaaS 企业 」

观测云

可观测性 SaaS

IP代理哪家好用? 必看经典文

Geek_bf375d

【Data & AI Con Shanghai 2023】嘉宾专访|西电王皓:认清边界 大胆创新

白玉兰开源

人工智能 白玉兰开源

首届OpenHarmony竞赛训练营结营颁奖,75所高校学子助力建设开源生态

OpenHarmony开发者

OpenHarmony

喜报 | MIAOYUN通过2023年度四川省“专精特新”中小企业认定!

MIAOYUN

专精特新 MIAOYUN 高新技术企业 专精特新中小企业 专精特新企业

聊聊低代码技术

互联网工科生

软件开发 低代码

Go类型嵌入介绍和使用类型嵌入模拟实现“继承”

快乐非自愿限量之名

Go 编程 教程 语言 教程分享

哪些行业发展需要用到代理IP?罗拉ROLA-IP告诉你什么是专业

Geek_bf375d

8款好用的笔记软件,让你的读书笔记独一无二!

彭宏豪95

读书笔记 效率 软件推荐 在线白板 笔记软件

inBuilder低代码平台新特性推荐-第5期

inBuilder低代码平台

低代码

“箭在弦上”的边缘计算,更需要冷静和智慧

脑极体

服务器

Python 机器学习入门:数据集、数据类型和统计学

小万哥

Python 程序员 软件 后端 开发

剑指数据结构—实现动态数组

少年游侠客

数据结构 数组 ArrayList Java’

软件测试/测试开发丨性能测试体系学习笔记

测试人

软件测试

Unity中国全面支持OpenHarmony游戏开发,多款游戏率先完成适配

最新动态

海外IP代理rola-ip表现突出,全球覆盖面广,技术支持优秀

Geek_bf375d

华为云开源 | 线下meetup · 电子科技大学站圆满收官

华为云开源

云原生 开源项目 开源社区

ROLA-IP海外IP代理为第四届全球跨境电子商务大会注入活力

Geek_bf375d

OpenAI 深夜炸场,更强更便宜;英特尔 CEO 分享三大失败原因;黄仁勋说成龙长得像他丨 RTE 开发者日报 Vol.79

声网

云电脑与5G网络的结合将会带来什么

青椒云云电脑

云电脑

瓴羊X阿里云上的Salesforce联合解决方案正式发布

ToB行业头条

投资机构Janus Capital Group为Rola-IP品牌融资700万美元

Geek_bf375d

领跑同一阵营!百分点科技入选Forrester AI/ML权威报告

百分点科技技术团队

人工智能 数据科学 百分点科技

新手入门:探索eBPF的可观测性与安全性工作流_可观测_InfoQ精选文章