Articles

Docker vs Podman: Container Runtimes Compared

Docker runs containers through a persistent root daemon; Podman runs them daemonless and rootless by default. What that architectural split changes.

Chisato Chisato · · 4 min read
Shipping containers stacked at a port

Docker and Podman both build and run OCI-compliant containers from the same image format, and for most day-to-day commands they’re interchangeable — Podman even aliases its CLI to accept docker command syntax. The difference that actually matters is architectural: Docker runs containers through a long-lived background daemon (dockerd) that typically runs as root, while Podman runs containers as direct child processes of the command that launched them, with no daemon and rootless execution by default.

The daemon vs daemonless split

Docker’s architecture centers on dockerd, a background service that owns every container’s lifecycle. The docker CLI is a thin client that talks to this daemon over a socket; if the daemon crashes or is restarted, every container it manages is affected, and anything with access to the daemon’s socket effectively has root-equivalent control over the host, because the daemon itself traditionally runs as root.

Podman does away with the daemon entirely. Each podman run invocation spawns the container as a direct child process of the Podman command, using the same underlying container APIs and image format Docker uses. There’s no persistent background service to compromise, restart, or lose containers to. The tradeoff is that some daemon-dependent conveniences — like a container continuing to run detached after its parent process exits in certain configurations — need to be handled differently, since there’s no long-running service tracking every container across the whole system.

Rootless by default

This is the security-relevant difference. Docker has supported a rootless mode for years, but it’s opt-in and adds setup friction; the default install still runs the daemon as root, meaning a container escape or a compromised daemon socket can translate directly into host root access — see what a container escape actually is for why that boundary matters.

Podman was built rootless-first. A regular, unprivileged user can run podman run and get a fully functional container without ever touching root privileges, using Linux user namespaces to remap the container’s internal root user to an unprivileged user on the host. That doesn’t make containers inherently secure — a rootless container can still have vulnerabilities — but it removes an entire class of “container escape equals host root” scenarios by default, which lines up with the broader principle of least privilege: give a process only the access it needs, not more.

Comparing the two

DockerPodman
ArchitectureClient talks to a persistent daemonDaemonless — direct child processes
Default privilegeDaemon typically runs as rootRootless by default
CLI compatibilityNativeAccepts Docker-compatible CLI syntax
Compose supportNative docker composepodman-compose, or Docker Compose files via a Podman socket
Systemd integrationIndirectNative — can generate systemd unit files per container
Image formatOCI-compliantOCI-compliant, interoperable with Docker images
Ecosystem maturityLarger, more third-party toolingSmaller but growing, especially in Red Hat–adjacent stacks

Because both consume and produce standard OCI images, a Dockerfile built with Docker runs correctly under Podman and vice versa — the image format was never the point of divergence. The same is true of layer caching behavior and multi-stage builds; the concepts covered in Docker image layers and caching and multi-stage builds apply equally to images built with either tool.

Where the differences show up in practice

Systemd integration. Podman can generate systemd unit files directly from a running container (podman generate systemd), letting a container be managed as a native systemd service with restart policies, dependencies, and logging handled the same way as any other system service. This fits naturally into environments already standardized on systemd for service management, without a separate daemon layer in between.

Pods, not just containers. Podman borrows the Kubernetes concept of a pod — a group of containers that share a network namespace — as a first-class local primitive, which makes it easier to test multi-container setups that mirror how they’ll eventually run in Kubernetes without needing a full cluster locally.

Compose files. Docker Compose remains the more mature, more widely documented tool for multi-container local development, with docker-compose.yml as a near-universal format — see Docker Compose explained. Podman can consume the same Compose files through podman-compose or by exposing a Docker-compatible API socket, but tooling built specifically around docker compose sometimes assumes the daemon is present.

Volumes and bind mounts. The concepts are identical between the two — see volumes vs bind mounts — though rootless Podman requires paying closer attention to file ownership inside bind-mounted directories, since the container’s remapped UID may not match the host user’s UID without explicit configuration.

Picking one

For local development, either works, and switching between them is usually a matter of aliasing docker to podman and adjusting for the small CLI gaps. For anything security-sensitive — CI runners executing untrusted build steps, multi-tenant build infrastructure, or any environment where you want to minimize the blast radius of a compromised container — Podman’s rootless-by-default model is the stronger starting point without extra configuration. For teams already deep in the Docker ecosystem, with tooling and pipelines built around dockerd’s daemon model, migrating has a real cost that needs to be weighed against how much the security tradeoff actually matters for that specific workload.

The takeaway

Docker and Podman produce and run the same OCI images, but they get there differently: Docker through a persistent, typically root-owned daemon, Podman through daemonless, rootless-by-default processes. The image format and most day-to-day commands are compatible enough that switching is rarely a rewrite. The real decision is how much you value removing a root daemon from the equation versus staying inside the more mature, more widely tooled Docker ecosystem.

The Lycoris Team The Lycoris Team · · 4 min read

Docker Multi-Stage Builds Explained

Multi-stage builds let a Dockerfile use one stage to compile code and a separate, minimal stage to ship it — cutting image size and attack surface.

#Docker #DevOps #Containers