eBPF is a technology allowing you to dynamically program the kernel using a virtual machine approach. Several development frameworks exist, with the top choice for Rust developers being Aya.
Because of the deep integration between eBPF and the Linux kernel, it can be challenging to create a local development environment that works across different development machines. To date, I’ve taken to developing eBPF programs on EC2 instances using the AWS Cloud9 development environment. This works, but comes with its own issues and won’t be for everyone.
An alternative I’ve been exploring lately is using devcontainers to create a reproducible Docker container for eBPF development. Although devcontainers are best supported by Visual Studio Code, the hope is that this standard becomes more widely used and applicable to other environments.
Dockerfile
The Dockerfile I’ve built for this purpose is based on the devcontainer
image available from Microsoft. From this starting point, we install
llvm
alongside required dependencies. This is done using the llvm.sh
script. Note that we need to also install the development packages for
libclang
, libpolly
, and libzstd
. Rust is installed using the nightly toolchain as prescribed by the Aya
documentation. Lastly, we install Aya’s BPF tools.
Putting this all together gives the following Dockerfile:
FROM mcr.microsoft.com/devcontainers/rust:1-bullseye
# Install llvm
RUN apt-get update \
&& apt install -y lsb-release wget software-properties-common gnupg \
&& wget https://apt.llvm.org/llvm.sh \
&& chmod a+x llvm.sh \
&& ./llvm.sh 18 \
&& apt install -y libclang-18-dev libpolly-18-dev libzstd-dev
# Install Rust with nightly sources
ENV RUST_VERSION=stable
USER vscode
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=$RUST_VERSION
RUN rustup toolchain install nightly --component rust-src
RUN export LLVM_SYS_160_PREFIX=/usr/include/llvm-18
ENV PATH "/usr/include/llvm-18/bin:$PATH:/usr/local/cargo/bin"
# BPF and aya tools
RUN cargo install --no-default-features bpf-linker
RUN cargo install bindgen-cli
RUN cargo install --git https://github.com/aya-rs/aya -- aya-tool
devcontainer.json
With our Dockerfile in place, the only thing we need is
a devcontainer.json
file that references the Dockerfile. The relevant
sections of this JSON file are to run the container as a privileged user
so we can add eBPF programs to the kernel using "privileged": true
, add
the BPF capability to the container using --cap-add=CAP_BFP
, and mount
the debug filesystem with sudo mount -t debugfs debugfs /sys/kernel/debug/
as a post create command.
Together, we get the following JSON file.
{
"name": "epbf-devcontainer",
"build": {
"dockerfile": "Dockerfile"
},
"privileged": true,
"runArgs": [
"--cap-add=CAP_BPF"
],
"postCreateCommand": "sudo mount -t debugfs debugfs /sys/kernel/debug/"
}
Place these two files in a .devcontainer/
folder and enjoy writing eBPF
programs in a portable developmet environment!