Podman and Buildah
Podman runs the same OCI images with a Docker-compatible CLI, but with no central daemon: each podman run forks the container as a child of your shell, and it runs rootless by default. That architectural difference removes the root-owned dockerd socket that Chapter 1 and Chapter 10 flagged as a root-equivalent risk.
Where Docker bundles build, run, and image transfer into one binary, Podman splits them across focused tools: Podman runs, Buildah builds, and skopeo moves images between registries and stores. Three tools, the same OCI artifact, no always-on root process owning everything.
dockerd) owns containers, builds, and the socket — root by default, one binary for everything.Daemonless, Fork/Exec
There is no podman daemon owning your containers. Podman forks and execs each container directly via runc or crun, so a crashed Podman does not take the containers with it, and there is no always-on root socket to compromise. The container is a child of the process that launched it, which is a smaller attack surface and a simpler failure model than a central daemon that everything routes through.
$ podman run -d -p 8080:8080 \
--name driftwood-web \
registry.driftwood.example/driftwood/web:1.4.0
$ podman ps
# most existing Docker commands work unchanged:
$ alias docker=podman
$ docker build -t driftwood/web:1.4.0 .
# run a Linux host's containers as services, surviving logout/reboot:
$ podman generate systemd --new --name driftwood-web > driftwood-web.service
The alias covers the common path, but it is not byte-identical to Docker — Compose, the socket API, and a few flags differ. Treat alias docker=podman as a strong default that you verify, not a guarantee, especially for any script that talks to docker.sock directly.
Rootless by Default
Podman runs as your user using user namespaces — the rootless model Chapter 10 presented as an opt-in is Podman's default. A container breakout therefore lands as an unprivileged user, not as host root, which shrinks the blast radius of an escape to whatever your own account can touch. This is the single biggest reason to reach for Podman on a multi-user or hardened host: there is no root daemon to compromise in the first place.
Pods — A Kubernetes-Shaped Primitive
Podman groups containers into a pod sharing a network namespace — the same concept Kubernetes uses, and the source of the name. podman generate kube emits Kubernetes YAML from running containers, and podman kube play runs a Kubernetes manifest locally. That round-trip makes Podman a natural on-ramp to the sibling Kubernetes course: you model the workload in the same shape locally before a cluster ever enters the picture.
Buildah and skopeo — Unbundled
Buildah builds OCI images, either from a Dockerfile or scriptably step by step without a full Dockerfile at all. skopeo inspects and copies images between registries and stores without a daemon and without running anything — skopeo copy moves driftwood/web from one registry to another, and skopeo inspect reads a manifest without pulling it. Docker folds these jobs into one engine; Podman splits them into tools you can use independently in CI.
systemd and Quadlet — Running Containers as Services
Because there is no daemon to own restarts, Podman integrates with systemd. A Quadlet unit file declares a container as a native systemd service with restart policies and dependencies, so the OS — not a container daemon — handles bringing Driftwood's containers up at boot and back after a crash. A container started loose in your shell does not survive logout; a Quadlet unit survives logout and reboot because systemd owns it.
Docker — a long-lived root daemon (dockerd) owns all containers, builds, and the socket: one binary, the dominant ecosystem, rootful by default with rootless as an opt-in. Choose it for the largest tooling support and the Docker Desktop and Compose workflows most teams already run.
Podman — daemonless and rootless by default, CLI-compatible (alias docker=podman), with builds via Buildah and a native systemd/Quadlet integration. Choose it when a root daemon is unacceptable — multi-user hosts, hardened servers — or you want a Kubernetes-shaped local pod model. Both run identical OCI images.
- Assuming
alias docker=podmanis 100% transparent — Compose, thedocker.sockAPI, and a few flags differ;podman composeand the Podman socket exist but are not byte-identical, so test any script that talks to the socket. - Expecting a Podman container started in your shell to keep running after you log out without arranging supervision — there is no daemon babysitting it; use a Quadlet/systemd unit for anything that must survive logout or reboot.
- Running Podman rootless and being surprised that binding port 80 fails or that heavy overlay I/O behaves differently — rootless cannot bind low ports without configuration and uses user-namespace mappings that change file-ownership semantics.
- Treating Buildah and
docker buildas producing different artifacts — both emit OCI images the other can run; the difference is the build tooling, not the outputdriftwood/web.
- Choose Podman when a root-owned daemon is the unacceptable risk — multi-user or hardened hosts — since rootless-by-default shrinks the blast radius of a breakout to an unprivileged user.
- Run single-host production containers under Quadlet/systemd units rather than leaving them as shell children, so restarts, ordering, and boot-time start are the OS's job.
- Use skopeo to inspect and copy images between registries in CI without pulling and running them, keeping image movement off any container runtime.
- Keep building OCI-standard images with Buildah or Docker so the choice of engine never locks in the artifact —
driftwood/webruns under either.
Knowledge Check
What is the architectural difference between Podman and Docker?
- Podman is daemonless and rootless by default; each container is forked from your shell with no central root daemon
- Podman uses its own proprietary image and layer format that the Docker engine simply cannot pull, load, or run at all
- Podman runs a heavier always-on root daemon than dockerd does, listening on its own socket on the host
- Podman only works as a component running inside an already-provisioned Kubernetes cluster
Why does running rootless by default reduce risk?
- A container breakout lands as an unprivileged user, not host root, so the blast radius is limited to your account
- It encrypts the container's root filesystem at rest so even a successful breakout reveals nothing useful to the attacker
- It makes container breakouts technically impossible at the kernel level under any workload
- It blocks all outbound and inbound network access from inside the container by default
What do Buildah and skopeo do that Docker folds into one engine?
- Buildah builds OCI images and skopeo inspects and copies them between registries without a daemon
- They convert standard images into a Podman-only proprietary on-disk format before storing them
- They schedule and orchestrate containers across multiple hosts in a cluster, replacing the need for Kubernetes
- They both run containers as well, just faster and with less memory than Podman itself does
A Podman container started in your shell stops when you log out. What is the right fix for a single-host service?
- Declare it as a Quadlet/systemd unit so the OS owns restarts, ordering, and boot-time start
- Install dockerd so its always-on root daemon keeps the container alive after you log out
- Add a longer restart timeout flag and leave the container running in your login shell session
- Rebuild the image so the entrypoint relaunches itself in the background after you log out
You got correct