Living without docker: podman as a daily driver
Podman is a near drop-in replacement for the Docker CLI. Daemonless, rootless by default, ships in immutable distros. Muscle-memory translation and the few places the abstraction leaks.
Podman ships on most modern Linux desktops, Bazzite included. The CLI is intentionally docker-compatible (most subcommands and flags work identically), but two things differ under the hood:
- No daemon. Podman invokes containers directly via
runc/crun. There's no long-running root service. - Rootless by default. Each user has their own container store under
~/.local/share/containers/. Containers run mapped to your UID via user namespaces.
Both are a security win. They also remove the "is the daemon running?" and "is my user in the docker group?" failure modes.
# Common docker commands as podman commands
docker pull alpine → podman pull alpine
docker run -it alpine sh → podman run -it alpine sh
docker build -t foo . → podman build -t foo .
docker compose up → podman compose up # via podman-compose
docker ps → podman ps
docker exec -it <id> sh → podman exec -it <id> sh
docker logs -f <id> → podman logs -f <id>
docker network ls → podman network ls
docker volume create x → podman volume create x
If your fingers keep typing docker, install podman-docker. It symlinks /usr/bin/docker to /usr/bin/podman so old scripts keep working. Bazzite ships it by default.
# Where the abstraction leaks
docker composev2 vspodman-compose. Parity is close but not perfect. The compose plugin shipped with Podman 5.x handles most multi-container apps. If you hit a wall, Quadlet units are closer to how production actually runs anyway.- Docker socket. Tools that hardcode
/var/run/docker.sockneed a podman socket. Runsystemctl --user enable --now podman.socket, then point them atDOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock. - NVIDIA passthrough. The container toolkit supports both runtimes. The podman path needs
--security-opt=label=disableon SELinux distros. - Buildkit features.
docker build --secret,--ssh,--mount=type=cacheall have podman equivalents. Flag names differ slightly. Checkpodman build --help. - macOS / Windows. Podman runs a Linux VM under the hood (
podman machine). Resource limits and bind mounts work, buthost.docker.internalbecomeshost.containers.internal.
# Why it matters on immutable distros
On Bazzite and other rpm-ostree systems, you avoid layering RPMs into the base image (see rpm-ostree: rebase, pin, rollback). Containers are how you install traditional CLI tooling. distrobox and toolbx both wrap Podman to give you a transparent shell into a container with your home directory mounted in. That's where gcc, kubectl, terraform, etc. should live.
# Related
- Bazzite: an immutable gaming-first Fedora variant
- rpm-ostree: rebase, pin, rollback