A minimal, self-contained bpftool image you can schedule as a
DaemonSet to troubleshoot BPF agents running on Kubernetes cluster nodes
(EKS, GKE, AKS, kind, kubeadm - anything).
It runs sleep infinity so the pod stays up and you can exec into it to
inspect the BPF programs, maps, and links that an agent has loaded on the
host kernel.
Images are published to GHCR for linux/amd64 and linux/arm64:
ghcr.io/lazybpf/bpftool-daemon:latest
ghcr.io/lazybpf/bpftool-daemon:v7.5.0 # tagged with the bpftool release
Nothing to clone - label a node and apply the manifest straight from this repo:
kubectl label node <node> bpftool-daemon=truekubectl apply -f https://raw.githubusercontent.com/lazybpf/bpftool-daemon/main/bpftool-daemonset.yamlTip
The DaemonSet uses a nodeSelector (bpftool-daemon: "true") so it only
lands on labelled nodes. Remove the selector to run on every node.
Two manifests, same namespace and same DaemonSet name - pick one, or apply the other later to switch:
| Manifest | Security context | Use when |
|---|---|---|
bpftool-daemonset.yaml |
privileged: true |
Default. Most portable across node images and kernels. |
bpftool-daemonset-least-privilege.yaml |
Explicit capabilities, seccomp + AppArmor on, read-only rootfs | Recent nodes (kernel >= 5.11), or a cluster policy that rules out privileged. |
kubectl apply -f https://raw.githubusercontent.com/lazybpf/bpftool-daemon/main/bpftool-daemonset-least-privilege.yamlkubectl -n bpftool-daemon exec -ti ds/bpftool-daemon -- bpftool prog show
kubectl -n bpftool-daemon exec -ti ds/bpftool-daemon -- bpftool map show
kubectl -n bpftool-daemon exec -ti ds/bpftool-daemon -- bpftool link show
kubectl -n bpftool-daemon exec -ti ds/bpftool-daemon -- bpftool prog tracelog# Dump a pinned map an agent created on the host bpffs:
kubectl -n bpftool-daemon exec -ti ds/bpftool-daemon -- \
bpftool map dump pinned /sys/fs/bpf/<agent>/<map>kubectl delete namespace bpftool-daemonkubectl label node <node> bpftool-daemon-The image builds bpftool from source. Pick a release with the build arg:
docker build --build-arg BPFTOOL_VERSION=v7.5.0 \
-t ghcr.io/lazybpf/bpftool-daemon:latest .Run it locally, without Kubernetes:
docker run --rm -ti --privileged --pid=host \
ghcr.io/lazybpf/bpftool-daemon:latest bpftool prog showThe same thing with the least-privilege set, useful for checking a kernel before rolling out the DaemonSet:
docker run --rm -ti --pid=host --read-only --tmpfs /tmp \
--cap-drop ALL \
--cap-add CAP_SYS_ADMIN \
--cap-add CAP_SYSLOG \
--cap-add CAP_BPF \
--cap-add CAP_PERFMON \
--security-opt no-new-privileges \
-v /sys/fs/bpf:/sys/fs/bpf:ro \
-v /sys/kernel/tracing:/sys/kernel/tracing:ro \
-v /sys/kernel/btf:/sys/kernel/btf:ro \
ghcr.io/lazybpf/bpftool-daemon:latest bpftool prog showThe publish-image workflow is manual:
Actions -> Publish bpftool-daemon image -> Run workflow, then enter the
bpftool release to build (e.g. v7.5.0). It builds multi-arch and pushes
both :<version> and :latest to GHCR.
Apache License 2.0 - see LICENSE. bpftool itself is built from
libbpf/bpftool and carries its own (GPL-2.0/BSD-2-Clause) license.