Loading repository data…
Loading repository data…
clement-tourriere / repository
Open-source container debugger for Docker and Kubernetes. Debug distroless, scratch, and minimal images with a rich Nix-powered shell.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
debux is like docker debug and orb debug, but free, open-source, and Kubernetes-aware.
It starts a temporary debug toolbox next to your target container, shares useful namespaces, and exposes the target filesystem at $DEBUX_TARGET_ROOT. That means you can debug production-style containers without rebuilding them, adding a shell, or shipping troubleshooting tools in your app image.
📚 Full documentation: https://clement-tourriere.github.io/debux/ — includes a Ctrl/Cmd + K search palette.
If debux saves you a debugging session, a GitHub star helps other Docker and Kubernetes users find it.
docker exec is useless — distroless, scratch, Alpine, and tiny production images.curl, strace, tcpdump, vim, jq, dig, nmap, and more.dctl install <pkg> pulls from nixpkgs during a debug session; --tools preloads a set at startup.-p and distroless pods where kubectl cp fails.| Usual option | Where it falls short | Debux approach |
|---|---|---|
docker exec | Requires tools and a shell inside the target image, and the container must be running. | Starts a separate toolbox and attaches it to the target — and falls back to the filesystem (including the writable layer) for stopped or crash-looping containers. |
kubectl debug | Kubernetes-only, and you still need to curate a debug image. | Provides one Docker, Compose, Podman, and Kubernetes workflow with a Nix toolbox. |
kubectl cp | Needs tar inside the target, so it fails on distroless/scratch. | Streams debux cp through the toolbox, so copies work on shell-less images. |
| Rebuilding the app image | Slow during incidents and changes the artifact you are debugging. | Leaves the application image untouched; the toolbox still runs the target's own binaries via chroot when needed. |
| Shipping debug tools in prod | Increases image size and attack surface. | Keeps production images minimal and installs tools on demand. |
Install the latest release binary:
curl -fsSL https://raw.githubusercontent.com/clement-tourriere/debux/main/install.sh | sh
debux docker://
The installer supports Linux/macOS on amd64/arm64 and installs to ~/.local/bin by default.
Release assets are checksum-verified. If cosign is installed and the release includes signature assets, the installer also verifies checksums.txt before using it.
# Pin a version
curl -fsSL https://raw.githubusercontent.com/clement-tourriere/debux/main/install.sh | sh -s -- --version v1.2.3
# Choose another install directory
curl -fsSL https://raw.githubusercontent.com/clement-tourriere/debux/main/install.sh | sh -s -- --bin-dir /usr/local/bin
# Explicitly opt into a source build if a release asset is unavailable
curl -fsSL https://raw.githubusercontent.com/clement-tourriere/debux/main/install.sh | DEBUX_ALLOW_SOURCE_BUILD=1 sh
# Later, check or update from GitHub Releases
debux update --check
debux update
For development from source, use mise:
git clone https://github.com/clement-tourriere/debux.git
cd debux
mise run install # Build and copy debux to ~/.local/bin
mise run image-build # Build ghcr.io/clement-tourriere/debux:latest locally
# For Kubernetes after image changes:
# docker push ghcr.io/clement-tourriere/debux:latest
docker run -d --name my-app nginx:alpine
debux my-app
# or
debux docker://my-app
Interactive picker:
debux docker://
Full-screen target browser with Docker, Kubernetes context/namespace navigation, active session reattach, recent sessions, option toggles, and optional new-terminal launch support:
debux tui
# keys: / filter, enter open/drill down, ←/→ or tab cycle sources,
# 1/2/3/4 jump to Docker/Kubernetes/Active sessions/History,
# b back, s search pods, r reload
The dashboard presents source sections first. Kubernetes pods are loaded only after you pick a context and namespace, and the Kubernetes view includes a current context/default namespace shortcut so common cases are one click. enter opens in the current terminal and returns to the TUI when the shell exits. External launch with t is disabled unless you explicitly set DEBUX_TERMINAL.
Even if the target image has no shell:
docker run -d --name distroless gcr.io/distroless/static-debian12
debux distroless
Even if the container is stopped, exited, or crash-looping:
# debux copies the target filesystem (including its writable layer) into a
# debug container at /target. Changes outside volumes are discarded on exit.
debux my-crashed-app
Docker Compose services and Podman containers work too:
# Resolve a Compose service by name (picks one replica if scaled)
debux compose://web
debux compose://my-project/web
# Debug a Podman container via its Docker-compatible socket
debux podman://my-app
# containerd/nerdctl schemes are recognized but not yet implemented;
# use podman://, docker://, or k8s:// when available.
# Current kube-context namespace
debux k8s://my-pod
# Explicit namespace in the target or with --namespace/-n
debux k8s://my-namespace/my-pod
debux k8s://my-pod --namespace my-namespace
# Specific container in a multi-container pod
debux k8s://my-namespace/my-pod/my-container
# Explicit kube context in the target
debux k8s://@eks-preprod-01/my-namespace/my-pod/my-container
# Or use --context, useful for context names containing slashes
debux k8s://my-namespace/my-pod --context arn:aws:eks:us-west-2:123:cluster/preprod
# Interactive pod picker
debux k8s://
debux k8s://@eks-preprod-01
# If the pod name is not exact, debux proposes running pods matching the substring
debux k8s://my-namespace/webapp-internal-api
If ephemeral containers are blocked by RBAC or admission policy:
debux k8s://my-namespace/my-pod --copy
Copy mode creates a temporary duplicate pod for debugging and deletes it on exit. Use it carefully for workloads with side effects or non-idempotent startup logic.
An ephemeral debug container lives inside the target pod, so it dies whenever
the pod does — a rollout, a Karpenter consolidation, an eviction. A copy pod
does not have that problem: it is not owned by the source Deployment, so
rollouts never replace it, and debux annotates it with
karpenter.sh/do-not-disrupt (and cluster-autoscaler.kubernetes.io/safe-to-evict: "false")
so voluntary node consolidation leaves it alone. Forceful disruption — spot
interruptions, node failure, manual drains — still wins.
# Keep the copy pod when the session ends; it self-destructs after 48h
debux k8s://my-namespace/my-pod --copy --keep --ttl=48h
# See currently reattachable sessions, then pick one from a searchable picker.
# debux remembers recent Kubernetes contexts/namespaces; pass a scope when you
# want to be explicit or use -A when your RBAC allows all-namespace listing.
debux list
debux list k8s://my-namespace/
debux attach
# Come back later: targeting a copy pod reattaches to its debug container
debux attach k8s://my-namespace/debux-copy-abc12
# Done early? Delete it explicitly
debux kill k8s://my-namespace/debux-copy-abc12
Every copy pod carries a kubelet-enforced deadline (activeDeadlineSeconds,
default --ttl=24h), so even one orphaned by a power loss or kill -9 of the
CLI stops consuming resources on time — no controller or cron required. The
Karpenter protection lasts while the copy pod is non-terminal and is bounded by
the same TTL because the deadline marks the pod Failed. Two things to know
about the deadline: Kubernetes only allows shortening it after creation, never
extending it, so size the TTL up front; and an expired pod stays visible as Failed
(DeadlineExceeded) until deleted — debux kill --all sweeps those, or
kubectl delete pod -l app.kubernetes.io/managed-by=debux. --ttl=0 disables
the deadline entirely; the pod is then yours to delete.
Remember the copy runs a fresh instance of the app: it receives no Service traffic and shares no in-memory state with the original.
Force a fresh debug container and pull the newest debug image:
debux k8s://my-namespace/my-pod/my-container \
--fresh \
--pull-policy=Always
Like kubectl debug node/, but with the Nix toolbox. debux node schedules a
host-namespace toolbox pod on the node (hostPID/hostNetwork/hostIPC),
mounts the node root filesystem at /host ($DEBUX_TARGET_ROOT), and tolerates
taints so cordoned or NotReady nodes can still be debugged. Node binaries like
crictl, journalctl, and systemctl run through the chroot fallback with
their original host paths.
# Pick a node interactively
debux node
# Debug a specific node
debux node worker-1
# Privileged session, keep the debug pod after exit
debux node worker-1 --profile=sysadmin --keep
debux does not modify your application image.
$DEBUX_TARGET_ROOT
# usually /proc/1/root
Inside t