├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .dockerignore ├── .github └── workflows │ └── publish-image.yml ├── Dockerfile ├── LICENSE ├── README.md ├── docker-bpf-env └── Dockerfile ├── entrypoint.sh └── kernel-headers └── Dockerfile /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/ubuntu/.devcontainer/base.Dockerfile 2 | 3 | # [Choice] Ubuntu version (use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon): ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 4 | ARG VARIANT="jammy" 5 | FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} 6 | 7 | # [Optional] Uncomment this section to install additional OS packages. 8 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 9 | # && apt-get -y install --no-install-recommends 10 | 11 | 12 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/ubuntu 3 | { 4 | "name": "Ubuntu", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 8 | // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. 9 | "args": { "VARIANT": "ubuntu-22.04" } 10 | }, 11 | 12 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 13 | // "forwardPorts": [], 14 | 15 | // Use 'postCreateCommand' to run commands after the container is created. 16 | // "postCreateCommand": "uname -a", 17 | 18 | // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 19 | "remoteUser": "vscode", 20 | "features": { 21 | "docker-from-docker": "latest" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | -------------------------------------------------------------------------------- /.github/workflows/publish-image.yml: -------------------------------------------------------------------------------- 1 | name: Publish image 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | env: 9 | REGISTRY: ghcr.io 10 | IMAGE_NAME: ${{ github.repository }} 11 | 12 | jobs: 13 | publish: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: read 17 | packages: write 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v3 21 | - name: Set up QEMU 22 | uses: docker/setup-qemu-action@v2 23 | - name: Set up Docker Buildx 24 | uses: docker/setup-buildx-action@v2 25 | - name: Login to GitHub Container Registry 26 | uses: docker/login-action@v2 27 | with: 28 | registry: ghcr.io 29 | username: ${{ github.actor }} 30 | password: ${{ secrets.GITHUB_TOKEN }} 31 | - name: Docker meta 32 | uses: docker/metadata-action@v4 33 | id: meta 34 | with: 35 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 36 | tags: | 37 | latest 38 | type=sha 39 | - name: Build and push 40 | uses: docker/build-push-action@v3 41 | with: 42 | context: . 43 | platforms: linux/amd64,linux/arm64 44 | push: true 45 | tags: ${{ steps.meta.outputs.tags }} 46 | labels: ${{ steps.meta.outputs.labels }} 47 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.16.2 2 | 3 | RUN apk add --no-cache docker-cli 4 | 5 | WORKDIR /app 6 | 7 | COPY . . 8 | 9 | ENTRYPOINT ["/app/entrypoint.sh"] 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Hemslo Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-bpf 2 | 3 | `docker-bpf` is a tool to help you run your BPF programs in Docker containers. 4 | 5 | It will automatically mount linuxkit kernel headers, BTF and debugfs into the container. 6 | So you can run BPF programs in Docker Desktop for Mac/Windows(WSL), and Linux of course. 7 | 8 | Details can be found in [this blog post](https://hemslo.io/run-ebpf-programs-in-docker-using-docker-bpf/). 9 | 10 | ## Usage 11 | 12 | ### Default 13 | 14 | ```shell 15 | docker run --rm -ti -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/hemslo/docker-bpf:latest 16 | ``` 17 | 18 | By default, it will launch a container with bcc and bpftrace installed. 19 | 20 | ### With your own BPF image 21 | 22 | If you already packaged your program in docker image, you can set the `BPF_IMAGE` environment variable to use that image instead. 23 | 24 | ```shell 25 | docker run --rm -ti -e BPF_IMAGE=quay.io/iovisor/bpftrace:latest -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/hemslo/docker-bpf:latest 26 | ``` 27 | 28 | Note you need to make sure the image matches the architecture of the host. 29 | For example, if you are running on a M1/M2 Mac, you need to use `arm64` image. 30 | 31 | ### With additional arguments 32 | 33 | Additional commands can be passed to the container. 34 | 35 | ```shell 36 | docker run --rm -ti -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/hemslo/docker-bpf:latest bpftrace --info 37 | ``` 38 | 39 | ### With data volume mount 40 | 41 | Additional data can be mounted into the container by setting `DATA_MOUNT` environment variable. 42 | 43 | ```shell 44 | docker run --rm -ti -e DATA_MOUNT=$PWD:/data -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/hemslo/docker-bpf:latest 45 | ``` 46 | -------------------------------------------------------------------------------- /docker-bpf-env/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.16.2 2 | 3 | RUN apk add --no-cache \ 4 | bcc-doc \ 5 | bcc-tools \ 6 | bpftrace \ 7 | bpftrace-doc \ 8 | bpftrace-tools \ 9 | bpftrace-tools-doc 10 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -eu 4 | 5 | cd "$(dirname "$0")" 6 | 7 | BPF_IMAGE="${BPF_IMAGE:-"docker-bpf-env:latest"}" 8 | DATA_MOUNT="${DATA_MOUNT:-"/tmp/docker-bpf-env:/tmp/docker-bpf-env"}" 9 | 10 | KERNEL_HEADERS="/usr/src" 11 | OS_RELEASE=$(docker run --rm -it alpine:3.16.2 uname -r) 12 | 13 | build_linuxkit_headers() { 14 | KERNEL_VERSION=$(echo "$OS_RELEASE" | cut -d - -f 1) 15 | 16 | docker build \ 17 | --build-arg KERNEL_VERSION="${KERNEL_VERSION}" \ 18 | -t linuxkit-kernel-headers:"$KERNEL_VERSION" \ 19 | ./kernel-headers 20 | 21 | docker run --rm \ 22 | -v linuxkit-kernel-headers:/usr/src \ 23 | linuxkit-kernel-headers:"$KERNEL_VERSION" 24 | 25 | KERNEL_HEADERS="linuxkit-kernel-headers" 26 | } 27 | 28 | docker volume create --driver local --opt type=debugfs --opt device=debugfs debugfs 29 | 30 | if [ "$BPF_IMAGE" = "docker-bpf-env:latest" ]; then 31 | docker build -t docker-bpf-env:latest ./docker-bpf-env 32 | fi 33 | 34 | case $OS_RELEASE in 35 | *linuxkit*) build_linuxkit_headers ;; 36 | esac 37 | 38 | docker run -ti --rm \ 39 | -v $KERNEL_HEADERS:/usr/src:ro \ 40 | -v /lib/modules/:/lib/modules:ro \ 41 | -v /sys/kernel:/sys/kernel:ro \ 42 | -v debugfs:/sys/kernel/debug:ro \ 43 | -v "$DATA_MOUNT" \ 44 | --net=host \ 45 | --pid=host \ 46 | --privileged \ 47 | "$BPF_IMAGE" "$@" 48 | -------------------------------------------------------------------------------- /kernel-headers/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG KERNEL_VERSION 2 | FROM linuxkit/kernel:${KERNEL_VERSION} as kernel 3 | FROM alpine:3.16.2 4 | WORKDIR / 5 | COPY --from=kernel /kernel-dev.tar . 6 | RUN tar xf kernel-dev.tar 7 | --------------------------------------------------------------------------------