天天看點

使用 Docker Desktop進行 BPF 開發

使用 Docker Desktop進行 BPF 開發

Docker Desktop 是 Windows 和 Mac 上最為流行 Docker 開發環境。我平時很多日常開發和測試也是以 Docker Desktop 為主。之前開發測試eBPF應用大多是直接在Linux上面完成的,是否有辦法在Docker Desktop中,利用容器來使用eBPF呢?本文參考了部分

https://github.com/singe/ebpf-docker-for-mac

相關實作,來幫助大家嘗試一下。

bcc & bpftrace

Docker Desktop for Mac 通過一個虛拟機,來運作基于

Linuxkit

建構的作業系統支援Docker環境。我們無法直接通路Virtual Machine,我們需要在 Docker容器中運作 eBPF 工具, 這需要有如下的前提條件:

  • /usr/src/ 需要包含核心源代碼
  • debugfs 被正确挂載。

    mount -t debugfs debugfs /sys/kernel/debug

  • /lib/modules/ 需要挂載 host 主控端上相關目錄
  • 需要在特權方式運作,比如

    docker run --privileged ...

  • 需要使用主控端 PID 名空間,比如

    docker run --pid=host ...

我們首先擷取目前主控端核心版本資訊

$ docker run -it --rm --privileged --pid=host justincormack/nsenter1
# uname -r
5.10.47-linuxkit
           

在Docker Hub上,Docker 在

docker/for-desktop-kernel

倉庫中釋出了 Docker Desktop 所包含的 linuxkit 核心代碼的容器鏡像。大家根據上面的核心版本資訊就能定位相應的鏡像 tag。

然後,我們來建構屬于自己的 Docker 鏡像,比如我希望建構一個Docker鏡像包含,

bcc

bpftrace

等eBPF開發工具。我們建立如下 Dockerfile.tools 來建構相應鏡像

FROM docker/for-desktop-kernel:5.10.47-0b705d955f5e283f62583c4e227d64a7924c138f AS ksrc

FROM ubuntu:20.04 AS bpftrace
COPY --from=ksrc /kernel-dev.tar /
RUN tar xf kernel-dev.tar && rm kernel-dev.tar
# Use Alibaba Cloud mirror for ubuntu
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/' /etc/apt/sources.list
# Install LLVM 10.0.1
RUN apt-get update && apt install -y wget lsb-release software-properties-common && wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && ./llvm.sh 10
ENV PATH "$PATH:/usr/lib/llvm-10/bin"

# Build/Install bpftrace
RUN apt-get install -y bpftrace

# Build/Install bcc
WORKDIR /root
RUN DEBIAN_FRONTEND="noninteractive" apt install -y kmod vim bison build-essential cmake flex git libedit-dev \
  libcap-dev zlib1g-dev libelf-dev libfl-dev python3.8 python3-pip python3.8-dev clang libclang-dev && \
  ln -s $(which python3) /usr/bin/python
RUN git clone https://github.com/iovisor/bcc.git && \
    mkdir bcc/build && \
    cd bcc/build && \
    cmake .. && \
    make && \
    make install && \
    cmake -DPYTHON_CMD=python3 .. && \
    cd src/python/ && \
    make && \
    make install && \
    sed -i "s/self._syscall_prefixes\[0\]/self._syscall_prefixes\[1\]/g" /usr/lib/python3/dist-packages/bcc/__init__.py

CMD mount -t debugfs debugfs /sys/kernel/debug && /bin/bash           

運作如下指令,建構鏡像 (執行時間較長,可以出去喝喝咖啡,吃吃飯)

$ docker build -t ebpf-for-mac -f ./Dockerfile.tools .
[+] Building 6097.8s (16/16) FINISHED
...           

或者可以直接拉取以建構好的鏡像,

$ docker pull registry.cn-hangzhou.aliyuncs.com/denverdino/ebpf-for-mac
$ docker tag registry.cn-hangzhou.aliyuncs.com/denverdino/ebpf-for-mac ebpf-for-mac           

運作如下指令,來通過Docker鏡像運作 bcc 測試應用。

$ docker run -it --rm \
  --name ebpf-for-mac \
  --privileged \
  -v /lib/modules:/lib/modules:ro \
  -v /etc/localtime:/etc/localtime:ro \
  --pid=host \
  ebpf-for-mac
  
# wget https://raw.githubusercontent.com/singe/ebpf-docker-for-mac/main/hello_world.py

# python3 hello_world.py
b'      kube-proxy-5454    [003] d... 10679.347316: bpf_trace_printk: Hello world'
b''
b'      kube-proxy-5469    [002] d... 10679.355387: bpf_trace_printk: Hello world'
b''
b'         dockerd-1807    [001] d... 10680.178545: bpf_trace_printk: Hello world'
b''
b'            runc-95361   [003] d... 10680.191472: bpf_trace_printk: Hello world'
b''
...           

bpftrace 是IO Visor開發的eBPF的追蹤工具。它允許開發者用簡潔的DSL(Domain Specific Language)編寫eBPF程式,而不必在核心中手動編譯和加載它們。具體驗證可以參考 Brendan Gregg 的[A thorough introduction to bpftrace

](

https://www.brendangregg.com/blog/2019-08-19/bpftrace.html)

在Kubernetes上排程 bpftrace 應用

Docker Desktop也内置了Kubernetes叢集開發環境。為了幫助國内開發者解決由于無法通路 gcr.io 鏡像倉庫,導緻無法開啟 Kubernetes 的問題,阿裡雲團隊維護了一個簡單的 helper 工具可以解決相應問題,請參考:

https://github.com/AliyunContainerService/k8s-for-docker-desktop

kubectl-trace 是可以讓使用者在Kubernetes叢集中安排執行bpftrace程式的kubectl插件。它的架構圖如下,當通過

kubectl trace

指令建立一個trace應用時,kubectl-trace插件會在Kubernetes叢集上,通過API建立一個被稱作“trace-runner”的臨時任務來執行bpftrace應用,可以排程到指定的節點或者Pod對其進行追蹤。

使用 Docker Desktop進行 BPF 開發

kubectl-trace的安裝過程比較簡單,請參考

Installing

進行操作。然而其預設帶的 trace-runner 鏡像是不支援 Docker Desktop,執行會自動退出。我們來根據上文原理,hack 一個擴充的版本。其中的代碼實作在

https://github.com/denverdino/trace-runner-for-docker-desktop

項目中。

其實作與上文類似,在 /usr/src/ 中添加核心源代碼,并挂載 debugfs , 然後就可以愉快的玩耍了。具體實作可以參見項目中 Dockerfile 與 main.go ,此處不在贅述。其運作效果如下:

$ kubectl trace run docker-desktop --imagename=registry.cn-hangzhou.aliyuncs.com/denverdino/kubectl-trace-runner -e "tracepoint:syscalls:sys_enter_* { @[probe] = count(); }"
trace 7b64f4b4-226e-4aaf-83b1-94858c72f91f created

$ kubectl trace attach 7b64f4b4-226e-4aaf-83b1-94858c72f91f
Attaching 327 probes...

^C
first SIGINT received, now if your program had maps and did not free them it should print them out

@[tracepoint:syscalls:sys_enter_getrlimit]: 1
@[tracepoint:syscalls:sys_enter_newstat]: 1
@[tracepoint:syscalls:sys_enter_fsync]: 1
@[tracepoint:syscalls:sys_enter_rt_sigsuspend]: 2
...
           

或者利用别名來簡化指令使用

$ alias kubectl-trace-run="kubectl trace run --imagename=registry.cn-hangzhou.aliyuncs.com/denverdino/kubectl-trace-runner"
$ kubectl-trace-run docker-desktop -e 'tracepoint:syscalls:sys_enter_open { printf("%s %s\n", comm, str(args->filename)); }'
trace 96209723-f439-4fb8-8bdc-d32e41e53e35 created

$ kubectl trace attach 96209723-f439-4fb8-8bdc-d32e41e53e35
Attaching 1 probe...
sntpc /etc/services
sntpc /dev/urandom
sntpc /dev/urandom
...
           

Have fun and Happy Halloween!

繼續閱讀