eBPF 提供了强大的跟踪、探测以及高效内核网络等功能,但由于其接口处于操作系统底层,新手入门起来还是有很大难度。幸好,eBPF 的维护者也看到了这个问题,并开发了一系列的工具来简化 eBPF 程序的开发和使用。这其中,最常用的两个工具是 BCC 和 bpftrace。
BCC
BCC(BPF Compiler Collection) 在 eBPF 编程接口之上封装了 eBPF 程序的构建过程,提供了 Python、C++ 和 Lua 等高级语言接口,并基于 Python 接口实现了大量的工具,是新手入门体验 eBPF 的最好项目。
BCC 的安装比较简单,比如 Ubuntu 和 RHEL 直接运行下面的命令就可以(其他发行版可以参考 INSTALL 安装):
# Ubuntu
sudo apt-get install bpfcc-tools linux-headers-$(uname -r) linux-tools-common
# RHEL
sudo yum install bcc-tools
安装后,BCC 会把所有示例(包括 Python 和 lua),放到 /usr/share/bcc/examples 目录中。
不过发行版自带的 BCC 版本通常比较旧,并不包含很多已经修复的问题或者新的特性,在运行时可能会碰到意想不到的错误。比如,在 Ubuntu 18.04 中,执行 /usr/sbin/tcpconnect-bpfcc 你会碰到下面的’asm goto' 问题:
error: 'asm goto' constructs are not supported yet
这是一个已知的问题,BCC Github 上面对应的 issue 是 #2119。
所以,在学习的时候,更推荐从源码安装最新版本:
apt-get install -y build-essential git bison cmake flex libedit-dev libllvm6.0 llvm-6.0-dev libclang-6.0-dev python zlib1g-dev libelf-dev python3-distutils libfl-dev
git clone https://github.com/iovisor/bcc.git
mkdir bcc/build && cd bcc/build
cmake ..
make && make install
cmake -DPYTHON_CMD=python3 .. # build python3 binding
pushd src/python/
make && make install
这样,所有的 BCC 工具会安装到 /usr/share/bcc
目录中。比如,你可以通过 /usr/share/bcc/tools/tcpconnect
命令来执行 tcpconnect 工具。
$ /usr/share/bcc/tools/tcpconnect
Tracing connect ... Hit Ctrl-C to end
PID COMM IP SADDR DADDR DPORT
192664 curl 4 10.240.1.2 39.156.69.79 80
bpftrace
bpftrace 类似于 DTrace 或 SystemTap,它在 eBPF 之上构建了一个简化的跟踪语言,通过简单的几行脚本,就可以达到复杂的跟踪功能。多行的跟踪指令也可以放到脚本文件中执行,脚本后缀通常为 .bt
。
Ubuntu 19.04 或者更新的系统可以直接通过 apt-get 命令安装 bpftrace:
# Ubuntu
sudo apt-get install -y bpftrace
而在其他系统或者生产环境中,推荐使用 docker 来运行 bpftrace。比如:
$ docker run -ti --rm -v /usr/src:/usr/src:ro \
-v /lib/modules/:/lib/modules:ro \
-v /sys/kernel/debug/:/sys/kernel/debug:rw \
--net=host --pid=host --privileged \
quay.io/iovisor/bpftrace:latest \
tcplife.bt
Attaching 3 probes...
PID COMM LADDR LPORT RADDR RPORT TX_KB RX_KB MS
192855 curl 10.240.1.2 44790 220.181.38.148 80 0 0 233
bpftrace 文档 提供了很多的单行示例,可以作为学习 bpftrace 的入门教程:
# Files opened by process
bpftrace -e 'tracepoint:syscalls:sys_enter_open {printf("%s %s\n", comm, str(args->filename)); }'
# Syscall count by program
bpftrace -e 'tracepoint:raw_syscalls:sys_enter {@[comm] = count(); }'
# Read bytes by process:
bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret/ {@[comm] = sum(args->ret); }'
# Read size distribution by process:
bpftrace -e 'tracepoint:syscalls:sys_exit_read {@[comm] = hist(args->ret); }'
# Show per-second syscall rates:
bpftrace -e 'tracepoint:raw_syscalls:sys_enter {@ = count(); } interval:s:1 { print(@); clear(@); }'
# Trace disk size by process
bpftrace -e 'tracepoint:block:block_rq_issue {printf("%d %s %d\n", pid, comm, args->bytes); }'
# Count page faults by process
bpftrace -e 'software:faults:1 {@[comm] = count(); }'
在 Kubernetes 集群中,你可以通过 kubectl trace 简化 bpftrace 的调度和运行。其运行原理如下图所示:
kubectl trace 支持单行方式或者脚本文件方式,比如
# Run a program from string literal
kubectl trace run node-1 -e "tracepoint:syscalls:sys_enter_* {@[probe] = count(); }"
# Run a program from file
kubectl trace run node-1 -f read.bt
kubectl trace 也可以通过 uprobe 直接跟踪一个 Pod:
小结
BCC 和 bpftrace 是两个最简单易用的 eBPF 跟踪工具,推荐初学者先学会它们的使用方法,并作为排错和性能调优的工具应用到实际系统中。
欢迎扫描下面的二维码关注漫谈云原生公众号,回复任意关键字查询更多云原生知识库,或回复联系加我微信。