Proof of concept. This project was built with heavy use of AI. It should be judged on functionality and the ideas it demonstrates, not on code quality or production-readiness.
A standalone tool that gives you a debug shell into any container or image
managed by Podman -- even shell-less / distroless ones. It works by overlaying
a Nix toolbox image onto the target's filesystem, giving
you access to thousands of debugging tools (curl, strace, gdb, vim,
tcpdump, ...) without modifying the target.
- Mounts the
nixos/niximage to get a/nixstore with tools. - Joins the target container's namespaces (mount, PID, network, IPC, UTS).
- Creates a tmpfs-backed overlay on
/so changes are discarded by default. - Bind-mounts
/nixfrom the toolbox image into the overlay. - Chroots into the merged view and starts a shell.
The container sees no changes. The /nix directory only exists inside the
debug session's overlay and is never visible to the actual container.
| Mode | Target | What happens |
|---|---|---|
| Live | Running or paused container | Joins container namespaces; you see its processes, network, and filesystem. |
| Snapshot | Stopped / exited / created container | Mounts the container's filesystem read-only; overlays on top. |
| Image | Any OCI image | Mounts the image layers; overlays on top. No container needed. |
The mode is selected automatically based on what you pass:
podman-debug my-running-container # live
podman-debug my-stopped-container # snapshot
podman-debug nginx:latest # image
By default all changes are discarded when you exit. Pass --writable (-w)
to write through to a running container's real filesystem:
podman-debug -w my-container
In writable mode a /nix directory is temporarily created on the container's
real filesystem and removed on exit. This is the only trace left behind.
Writable mode is only supported for running containers. It will fail (by design) on read-only containers.
- Linux (x86_64 or aarch64)
- Podman installed and working (rootful or rootless)
- Kernel 5.2+ (for
open_tree()/move_mount()syscalls) - The
nixos/nix:latestimage (pulled automatically on first use)
git clone https://github.com/rsturla/podman-debug.git
cd podman-debug
make build
make install PREFIX=$HOME/.local # installs to ~/.local/bin/
The build runs inside a Podman container (golang:1.26), so you don't need
Go installed locally -- just Podman. The output is a statically linked binary
(CGO_ENABLED=0) with no external library dependencies (~4.5 MB).
You can override the container engine or Go version if needed:
make build CONTAINER_ENGINE=docker GO_VERSION=1.26
podman-debug [options] {CONTAINER|IMAGE} [COMMAND [ARG...]]
# Interactive debug shell into a running container
podman-debug my-container
# Run a one-off command
podman-debug -c "cat /etc/os-release" my-container
# Debug a distroless image directly
podman-debug cgr.dev/chainguard/python:latest
# Use a specific shell
podman-debug --shell sh my-container
# Write changes through to the container
podman-debug -w my-container
# Use a custom toolbox image
podman-debug --image my-toolbox:v1 my-container| Flag | Short | Default | Description |
|---|---|---|---|
--shell |
auto |
Shell to use: bash, sh, auto |
|
--command |
-c |
Execute a command instead of interactive shell | |
--image |
nixos/nix:latest |
Debug toolbox image | |
--pull |
missing |
Pull policy: always, missing, never |
|
--interactive |
-i |
true |
Keep STDIN open |
--tty |
-t |
true |
Allocate a pseudo-TTY |
--writable |
-w |
false |
Write changes through to the container |
Inside every debug session, the following commands are available on PATH:
Install packages from nixpkgs into the debug session. Packages are session-only and discarded on exit.
install curl
install nmap strace tcpdumpRemove a previously installed package from the session.
uninstall curlInspect the ENTRYPOINT and CMD of the container or image being debugged.
entrypoint # Show details + lint
entrypoint --print # Print effective command only
entrypoint --lint # Lint the entrypoint configuration
entrypoint --run # Execute the entrypoint
entrypoint --json # Print raw JSON metadataList all available builtin commands.
Rootless Podman is fully supported. The binary automatically re-execs itself
through podman unshare to enter Podman's user namespace, which provides the
capabilities needed for overlay mounts, chroot, and namespace joins without
real root privileges.
- Linux only. The implementation uses Linux-specific syscalls (
setns,unshare,mount,chroot,open_tree,move_mount). - No remote Podman. The binary shells out to the local
podmanCLI and accesses/proc/<pid>/ns/*directly. It does not work withpodman --remoteor Podman machine VMs on macOS/Windows. - Writable mode + read-only containers. Writable mode requires the container's root filesystem to be writable. This is by design.
/nixconflicts. If the target container already has a/nixdirectory the overlay will shadow it during the debug session.
Apache License 2.0. See LICENSE for details.