BumbleBee: 如丝般顺滑构建、交付和运行 eBPF 程序
本文地址:https://www.ebpf.top/post/bumblebee
1. 前言
不久前,Solo.io 公司在官网博客宣布了开源了一个名称为 BumbleBee 的新项目。该项目专注于简化构建 eBPF 工具的门槛和优化使用体验,通过将 eBPF 程序打包成 OCI 镜像,带来了与使用 Docker 一致的体验的构建、分发和运行 eBPF 程序。
BumbleBee 目的是让我们专注于编写 eBPF 代码,其负责自动生成与 eBPF 程序相关的用户空间的代码功能,包括加载 eBPF 程序和将 eBPF 程序的数据作为日志、指标和直方图进行展示。
那么我们为什么需要 BumbleBee 项目来管理 eBPF 程序呢?这需要从 eBPF 技术的特点讲起。
2. 构建和分发 eBPF 工具的挑战
eBPF 技术被称之为近 50 年来操作系统最大的变革,解决了 Linux 内核在上游开发、合并和发行功能缓慢的窘境。 eBPF 技术为内核提供了不通过上游实现内核的定制功能的能力,当前已经在可观测、网络和安全等多个领域得到了广泛的应用,尤其是在云原生的技术潮流中,eBPF 技术发挥的能力也越来越重要,诸如当前风头正盛的 Cilium 项目。
但是开发、构建和分发 eBPF 一直以来都是一个高门槛的工作,社区先后推出了 BCC、BPFTrace 等前端绑定工作,大大降低了编写和使用 eBPF 技术的门槛,但是这些工具的源码交付方式,需要运行 eBPF 程序的 Linux 系统上安装配套的编译环境,对于分发带来了不少的麻烦,同时将内核适配的问题在运行时才能验证,也不利于提前发现和解决问题。
近年来,为解决不同内核版本中 eBPF 程序的分发和运行问题,社区基于 BTF 技术推出了 CO-RE 功能(“一次编译,到处运行”),一定程度上实现了通过 eBPF 二进制字节码分发,同时也解决了运行在不同内核上的移植问题,但是对于如何打包和分发 eBPF 二进制代码还未有统一简洁的方式。除了 eBPF 程序,目前我们还需要编写用于加载 eBPF 程序和用于读取 eBPF 程序产生数据的各种代码,这往往涉及到通过源码复制粘贴来解决部分问题。
此外,libbpf-bootstrap 通过 bpftool 工具生成相关的脚手架代码,一定程度上解决了通用代码重复编写的问题,但是对于构建、分发和运行 eBPF 程序上提供的帮助有限。
3. BumbleBee 简介
BumbleBee 项目正是 Solo 公司在企业服务网格 Gloo-Mesh 项目中为方便应用 eBPF 技术而诞生中,其用于解决在构建、分发和运行 eBPF 程序遇到的重复性挑战,
当前该项目还在早期(当前版本 0.0.9),提供的功能场景(Network 和 FileSystem)有限,但是基于特定模板能力来构建 OCI 镜像的思路,为我们在管理 eBPF 程序方面提供了一种高效简洁的实现,值得我们关注。
使用 BumbleBee 工具的前置依赖: 运行的 eBPF 的操作系统开启了 BTF 支持,编写的 eBPF 代码也需要使用 CO-RE 相关函数,关于 CO-RE 相关的技术可以参考这里。
BumbleBee 提供了与 Docker 一致的体验感觉。下图是 Docker 的高层次示意图,BumbleBee 工具完全参考了这个流程。
3.1 构建
BumbleBee 打造 "恰到好处" 的 eBPF 工具链,将 eBPF 程序的构建过程自动化,让你专注于代码本身。 BumbleBee 的 eBPF 代码打包成一个 OCI 标准镜像,这样就可以在基础设施中进行分发。
下述命令可实现将 eBPF 程序 probe.c 的直接编译和打包成镜像 my_probe:v1 。
$ bee build probe.c username/my_probe:v1
3.2 发布
利用 BTF 和 OCI 打包能力,BumbleBee 编写的 eBPF 代码是可移植的,并且可以嵌入到现有的发布工作流程中。 通过将 eBPF 代码构建的镜像,推送到任何符合 OCI 标准的镜像仓库,就可以实现发布给其他用户使用。
下述命令实现了将镜像发布至镜像仓库的功能,使用时可直接使用 bee run 基于镜像运行。
# 推送
$ bee push username/my_probe:v1
# 拉取
$ bee pull username/my_probe:v1
3.3 运行
使用 BumbleBee 提供的 CLI 界面和保存在镜像仓库中的镜像,我们可快速在其他地方运行。 BumbleBee 不但构建了用户空间代码,而且可以利用 eBPF map,来展示日志、指标和柱状图信息。 BumbleBee 使用了 BTF 格式自审能力,获知到需要显示哪些数据类型。
$ bee run my_probe:v1
下面让我们通过一个完整的样例,来体验 BumbleBee 带给我们管理 eBPF 程序的便利。
4. 完整体验
4.1 bee 安装
首先我们需要一个运行支持 BTF 内核的 Linux 操作系统,这里推荐直接使用 ubuntu 2110 版本,搭载的内核已经默认支持了 BTF。如果你选择使用 Vagrant 来管理虚拟机,BumbleBee 仓库中提供的 Vagrantfile 文件可以直接使用。或者你可以使用 mulipass 工具直接启动一个 ubuntu 2110 版本的系统。
这里使用仓库提供的脚本安装,当然也可以直接通过 git clone 仓库的方式进行。
为了快速体验,避免某些场景中的权限问题,这里建议直接使用 root 用户进行安装。
ubuntu@ubuntu21-10:~# curl -sL https://run.solo.io/bee/install | BUMBLEBEE_VERSION=v0.0.9 sh
Attempting to download bee version v0.0.9
Downloading bee-linux-amd64...
Download complete!, validating checksum...
Checksum valid.
bee was successfully installed
Add the bumblebee CLI to your path with:
export PATH=$HOME/.bumblebee/bin:$PATH
Now run:
bee init # Initialize simple eBPF program to run with bee
Please see visit the bumblebee website for more info: https://github.com/solo-io/bumblebee
安装完成后,bee 的主要命令如下:
# bee --help
Usage:
bee [command]
Available Commands:
build Build a BPF program, and save it to an OCI image representation.
completion generate the autocompletion script for the specified shell
describe Describe a BPF program via it's OCI ref
help Help about any command
init Initialize a sample BPF program
list
login Log in so you can push images to the remote server.
pull
push
run Run a BPF program file or OCI image.
tag
version
Flags:
-c, --config stringArray path to auth configs
--config-dir string Directory to bumblebee configuration (default "/root/.bumblebee")
-h, --help help for bee
--insecure allow connections to SSL registry without certs
-p, --password string registry password
--plain-http use plain http and not https
--storage string Directory to store OCI images locally (default "/root/.bumblebee/store")
-u, --username string registry username
-v, --verbose verbose output
Use "bee [command] --help" for more information about a command.
4.2 Bee init 生成 eBPF 程序脚手架
Bee init 命令可通过问题向导模式生成 eBPF 代码脚手架,功能与 libbpf-bootstrap 有些类似,但是通过向导的方式进行更加容易上手。
$ export PATH=$HOME/.bumblebee/bin:$PATH
# ebpf-test && cd ebpf-test
# bee init
Use the arrow keys to navigate: ↓ ↑ → ←
? What language do you wish to use for the filter: # 步骤 选择编写 eBPF 代码的语言
▸ C # 当前仅支持 C,Rust 可能在未来支持
--------------------------------------------- # 步骤 2 选择 eBPF 程序类型
INFO Selected Language: C
Use the arrow keys to navigate: ↓ ↑ → ←
? What type of program to initialize:
▸ Network # 选择编写 eBPF 程序的类型,当前支持 Network 和 File System
File system # 生成的模板分别对应于 tcp_connet 和 open 函数
--------------------------------------------- # 步骤 3 选择 map 类型
INFO Selected Language: C
INFO Selected Program Type: Network
Use the arrow keys to navigate: ↓ ↑ → ←
? What type of map should we initialize:
▸ RingBuffer
HashMap
--------------------------------------------- # 步骤 4 选择 map 导出类型
INFO Selected Language: C
INFO Selected Program Type: Network
INFO Selected Map Type: HashMap
Use the arrow keys to navigate: ↓ ↑ → ←
? What type of output would you like from your map:
▸ print # map 数据的展现方式,日志打印、计数或者指标导出
counter
gauge
--------------------------------------------- # 步骤 5 eBPF 程序保存文件名
INFO Selected Language: C
INFO Selected Program Type: Network
INFO Selected Map Type: HashMap
INFO Selected Output Type: print
BPF Program File Location: probe.c
---------------------------------------------- # 最终完成整个代码生成向导
INFO Selected Language: C
INFO Selected Program Type: Network
INFO Selected Map Type: HashMap
INFO Selected Output Type: print
INFO Selected Output Type: BPF Program File Location probe.c
SUCCESS Successfully wrote skeleton BPF program
# ls -hl
total 4.0K
-rw-rw-r-- 1 ubuntu ubuntu 2.0K Feb 11 11:33 probe.c
通过 init 命令生成的 probe.c 文件格式大体如下:
#include "vmlinux.h"
#include "bpf/bpf_helpers.h"
#include "bpf/bpf_core_read.h"
#include "bpf/bpf_tracing.h"
#include "solo_types.h"
// 1. Change the license if necessary
char __license[] SEC("license") = "Dual MIT/GPL";
struct event_t {
// 2. Add ringbuf struct data here.
} __attribute__((packed));
// This is the definition for the global map which both our
// bpf program and user space program can access.
// More info and map types can be found here: https://www.man7.org/linux/man-pages/man2/bpf.2.html
struct {
__uint(max_entries, 1 << 24);
__uint(type, BPF_MAP_TYPE_RINGBUF);
__type(value, struct event_t);
} events SEC(".maps.print");
SEC("kprobe/tcp_v4_connect")
int BPF_KPROBE(tcp_v4_connect, struct sock *sk)
{
// Init event pointer
struct event_t *event;
// Reserve a spot in the ringbuffer for our event
event = bpf_ringbuf_reserve(&events, sizeof(struct event_t), 0);
if (!event) {
return 0;
}
// 3. set data for our event,
// For example:
// event->pid = bpf_get_current_pid_tgid();
bpf_ringbuf_submit(event, 0);
return 0;
}
基于生成的代码模板,我们需要填写自己的逻辑,这里不是重点,先略过相关代码,完整代码可在官方开始文档中查看。
4.3 构建 eBPF 程序
构建过程需要使用 Docker 或者类型 Docker 的容器引擎,需要提前进行安装。
# apt install docker.io # 安装 docker
# bee build probe.c my_probe:v1
SUCCESS Successfully compiled "probe.c" and wrote it to "probe.o"
SUCCESS Saved BPF OCI image to my_probe:v1
整个构建过程中我们不需要再涉及 clang 等相关编译命令,只需要通过 bee build 命令输入 eBPF 程序文件名和期望生成的镜像即可,编译完成后,eBPF 程序的二进制字节码 probe.o 会自动添加到镜像 my_probe:v1 中,我们可以使用 bee tag 完成镜像仓库的重新定义。
4.4 发布 eBPF 程序
我们可以通过 bee tag 和 push 子命令完成进行镜像仓库的发布工作。
# bee tag my_probe:v1 dwh0403/my_probe:v1
# bee login
# bee push dwh0403/my_probe:v1
看一下上述的几条命令,是不是有些似曾相识的感觉?
4.5 运行 eBPF 程序
构建镜像后,在本地可直接通过 bee run 来运行,运行后 bee 会自动启动 TUI 界面,来展示我们编写 eBPF 程序中的 map 内容,自动生成的 map 名字有些特殊后缀用于 bee TUI 用户空间的程序来读取对应 map 中数据进行展示,比如生成代码模板中的SEC(".maps.print")
,表示该 map 用于打印。
# bee run my_probe:v1
SUCCESS Fetching program from registry: my_probe:v1
SUCCESS Loading BPF program and maps into Kernel
SUCCESS Linking BPF functions to associated probe/tracepoint
INFO Rendering TUI..
5. 总结
至此,我们完成了整个项目功能的体验,bee init 工具可通过向导模式帮助我们生成 eBPF 代码框架,尽管功能还有些单薄,但是对于我们特定场景的使用不失是一种快速便捷的方式。
bee build/push/run 等子命令,将编译的命令、打包镜像、发布镜像和运行镜像的等诸多步骤进行了极大的精简,非常易用,极大地降低了构建、发布和运行 eBPF 程序的重复成本,不得不为作者的思路点赞。
由于通过 bee 生成的工具基于特定场景,功能丰富度还有限,对于编写复杂情况下的 eBPF 程序和功能丰富的用户空间程序还不能适用,但是其构建、发布和运行的整体思路(甚至部分基础功能)却是我们可以直接使用或者借鉴的。
6. 参考资料
- Tutorial
- Solo.io 开源 BumbleBee,用类 Docker 的体验使用 eBPF
- BumbleBee: Build, Ship, Run eBPF tools
- eCHO episode 33: Bumblebee
BumbleBee: 如丝般顺滑构建、交付和运行 eBPF 程序的更多相关文章
- 大促密集,CDN如何保障电商体验如丝般顺滑?
简介: 前不久,阿里云技术天团空降CSDN在线峰会,对核心技术竞争力进行解读.其中,阿里云高级技术专家曾福华分享了<双11: CDN如何保障电商大促如丝般顺滑>的议题.俗话说:养兵千日,用 ...
- 如何把 Caffeine Cache 用得如丝般顺滑?
一.关于 Caffeine Cache 在推荐服务中,虽然允许少量请求因计算超时等原因返回默认列表.但从运营指标来说,越高的"完算率"意味着越完整的算法效果呈现,也意味着越高的商业 ...
- 如丝般顺滑地从Windows迁移SQLServer数据库到Linux
老鸟看过菜鸟的上一篇<MSSQL On Linux备份与还原>文章后,很满意,但是还是忍不住发问:"这篇文章讲的是MSSQL在Linux系统上的备份与还原,如果我之前是Windo ...
- 容器调度 • Docker网络 • 持续交付 • 动态运行应用程序 部署的多元化
<英雄联盟>在线服务运维之道 - InfoQ https://www.infoq.cn/article/running-online-services-riot/ 第一章 简 介 我是Jo ...
- 如丝般顺滑:DDD再实践之类目树管理
在上次反思DDD实践之后,在类目树管理项目中再次实践DDD.从需求分析到建模和具体的落地,结合个人体会,都是干货.
- 微软 Build 大会发布大量开发工具与服务!编码、协作、发布,如丝般顺滑
Microsoft Build 2020开发者大会已经圆满落幕,在连续两天48小时的不间断直播中,来自全世界的开发者共赴盛宴,场面相当壮观.在这一年一度的大聚会里,微软也是诚意满满,带来了一连串的产品 ...
- 想让安卓 APP 如丝般顺滑?
随着安卓手机市场占有率的节节攀升,随便在大街上找几个人估计 80% 用的都是安卓手机吧!用安卓手机的人这么多,不知道大家是否曾经感觉到过 APP 卡顿.死机?是否遇到应用程序无响应.闪退?本文就为大家 ...
- ios滑动流畅(丝般顺滑)滚动
在ios html->body->list(少一个样式都不行!) html->body->list <!DOCTYPE html> <html lang=&q ...
- 【AMAD】django-silk -- 为Django提供如丝般顺滑的性能测量
动机 简介 个人评分 动机 Django作为一个web框架,进行性能测量是很复杂的,不可以使用传统的程序profile工具. 因为,web app的性能是多维度的,不仅仅是代码执行效率,还包括网络延时 ...
随机推荐
- CF612E Square Root of Permutation
题目分析 我们首先模拟一下题意 假设有一个 \(q _1\) \(p\) \(a_1\) \(a_x\) \(a_{a_1}\) \(a_{a_x}\) \(q\) \(x\) \(a_1\) \(a ...
- 03.python封装与解构
封装与结构 基本概念 t1 = 1, 2 print(type(t1)) # 什么类型 t2 = (1, 2) print(type(t2)) Python等式右侧出现逗号分隔的多值的时候,就会将这几 ...
- springCloudGateway-使用记录
一.需求描述 旧项目做好之后,已经维护了一两个月,基本上已经趋于稳定,按照项目的整体进度基本上不会在做什么改动.新项目已经确定 下来,只是有一个大概的需求,unity3d的客户端已经开始做,在这个月2 ...
- 灵雀云Kube-OVN进入CNCF沙箱,成为CNCF首个容器网络项目
昨日,云原生计算基金会 (CNCF) 宣布由灵雀云开源的容器网络项目Kube-OVN 正式进入 CNCF 沙箱(Sandbox)托管.这是全球范围内首个被CNCF纳入托管的开源CNI网络项目,也是国内 ...
- Lucene8.5.x全文检索工具
本文的资源展示: hotword:是热词的文本,比如不是词语的中文,但是是什么人名或者公司名称的词语,需要分词成一个词语的将需要的加入hotword.dic stopword:无意义的词放入的词典,或 ...
- springboot打包第三方jar包是失败
在项目开发时有时我们需要引入一些在maven仓库中不存在的包 一.配置maven环境变量 在path环境变量中添加 %maven_home%\bin (window10环境下) cmd界面输入 mvn ...
- 园子的推广博文:欢迎收看 Apache Flink 技术峰会 FFA 2021 的视频回放
园子专属收看链接:https://developer.aliyun.com/special/ffa2021/live#?utm_content=g_1000316459 Flink Forward 是 ...
- day 21 C语
(1).有以下程序: 执行后的输出结果是[A] (A).256,1 (B).1,256 (C).255,1 (D).256,0 (2).以下选项中与(!a==0)的逻辑值不等价的表达式是[B] (A) ...
- day 10 删除空白字符
(1).有以下程序(大写变小写) (2).有以下程序,在[1]填写程序,使得程序正确运行. 分析:(*p)(int,int)是一个函数指针(一个指针[*p]指向的对象是一个函数),函数的形参是(int ...
- 【刷题-LeetCode】152 Maximum Product Subarray
Maximum Product Subarray Given an integer array nums, find the contiguous subarray within an array ( ...