Podman: Daemonless, Rootless OCI Container Engine
GitHub Repo
Apache-2.0
November 12, 2026 at 01:35 PM
0 views

Podman: Daemonless, Rootless OCI Container Engine

@podman-container-toolsProject Author

What Podman is

Podman, short for "POD MANager", is a command-line tool for managing OCI containers, container images, the volumes mounted into those containers, and pods made from groups of containers. Containers themselves are a Linux kernel feature, so Podman runs containers natively on Linux and reaches macOS and Windows through a Podman-managed virtual machine. The repository also contains libpod, the Go library that does the actual container lifecycle work and exposes APIs for managing containers, pods, images and volumes.

The design choices that define the project are spelled out in the README's scope list: no manager daemon, "for improved security and lower resource utilization at idle"; first-class support for running containers and pods without root or other elevated privileges; a Docker-compatible CLI that can run containers locally or on remote systems; and a REST API that offers both a Docker-compatible interface and a native interface exposing Podman-specific functionality. The project's usage-transfer guide puts the Docker relationship directly: the Podman CLI "is based on the Docker CLI, although Podman does not require a runtime daemon to be running in order to function", and Docker API support is provided through a socket-activated system service.

The docs serve two audiences in particular: a rootless setup guide for administrators and a Docker-to-Podman command map for developers and operators switching tools.

How it works

A fork/exec model instead of a daemon

Every podman invocation is an ordinary process. There is no long-running engine that owns all containers; instead Podman sets up the container and hands it off to a small monitor process. The socket-activation tutorial shows the chain: Podman forks and execs conmon, conmon starts the OCI runtime, and the runtime starts the container. Conmon is described in the README as "a tool for monitoring OCI runtimes, used by both Podman and CRI-O". This model is what lets containers slot into systemd units for Quadlet and socket activation.

Built from shared container libraries

Podman is assembled from a set of OCI projects and libraries, most of them maintained alongside it:

  • Runtime: OCI runtime configurations are generated with the OCI runtime tools and can run on any OCI-compliant runtime such as crun or runc.
  • Images: pulling, pushing and verification use the containers/image library.
  • Storage: container and image storage is handled by containers/storage.
  • Networking: Netavark and Aardvark provide networking and DNS, and rootless networking is handled by pasta.
  • Builds: image builds from a Containerfile or Dockerfile go through Buildah's Go API.
  • Seccomp: a unified seccomp policy is shared by Podman, Buildah and CRI-O.

The README is equally clear about what is out of scope: specialised signing and pushing of images to various storage backends is left to Skopeo, and implementing the Kubernetes CRI interface is left to CRI-O.

Rootless containers and user namespaces

When Podman runs as a normal user, it uses a user namespace so that root inside the container maps to the user running Podman. The rootless tutorial is explicit that rootless Podman "is not, and will never be, root; it's not a setuid binary, and gains no privileges when it runs". It shifts a block of subordinate UIDs and GIDs, listed per user in /etc/subuid and /etc/subgid, into the container using the newuidmap and newgidmap helpers. For containers whose image runs as a non-root USER, the docs say you must use --userns=keep-id when mounting volumes so the user's UID and GID match inside and outside the container.

Rootless users get their own containers.conf, storage.conf and registries.conf under ${XDG_CONFIG_HOME}/containers, and rootless image storage defaults to ${XDG_DATA_HOME}/containers/storage.

Podman on macOS and Windows

The podman machine man page explains why a VM is unavoidable: "containers are Linux - containers do not run on any other OS because containers' core functionality are tied to the Linux kernel." The podman binary on the host acts as a remote client to a Podman service inside the guest. The supported providers are QEMU on Linux, libkrun (the default) and Apple Hypervisor on macOS, and WSL (the default) and Hyper-V on Windows. podman machine init pulls a custom Fedora CoreOS based image from quay.io/podman/machine-os, except on WSL, which uses a custom Fedora image. SSH keys and system connections to both a root and a user account inside the VM are created automatically.

Key features

  • Pods. Groups of containers that share resources and are managed together.
  • Rootless by design. Containers run with no privileges beyond those of the launching user; the README notes that even --privileged rootless containers "will never have more privileges than the user that launched them".
  • Docker-compatible CLI and API. Most docker subcommands have a direct podman equivalent, and the compat REST API lets Docker clients and tools talk to Podman.
  • Image management. Pull with trust and verification, build from a Containerfile or Dockerfile, commit, and push OCI or Docker format images.
  • Checkpoint and restore. With CRIU 3.11 or later, a running container can be checkpointed to disk, restored at the same point, or exported and restored on another host for live migration.
  • Quadlet. Declarative .container, .pod, .volume, .network, .kube, .build, .image and .artifact files that a systemd generator turns into regular service units.
  • Kubernetes YAML in and out. podman kube generate emits Pod, Deployment, DaemonSet or Job YAML from existing containers and pods, and podman kube play recreates workloads from Kubernetes YAML.
  • Auto-updates. Quadlet's AutoUpdate= key opts a container into podman auto-update, checking either the registry or local storage for a newer image.
  • Socket activation. Both the API service and individual containers can be socket-activated by systemd; container socket activation has been supported since 3.4.0.
  • Podman Desktop. A separate project provides a desktop UI for Linux, Windows and macOS on top of the podman machine backend.

Getting started

Installation instructions live on the podman.io site rather than in the repository; install.md simply points there. The README's smoke test pulls a small image from Quay:

$ podman run quay.io/podman/hello

A first container on Linux

The basic tutorial runs an nginx server in the background, publishes a port, checks it and cleans up. The commands are intended to run as a non-root user:

podman run --name basic_httpd -d -p 8080:80/tcp docker.io/nginx
podman ps
curl http://localhost:8080
podman logs <container_id>
podman stop <container_id>
podman rm <container_id>

In rootless mode the container often has no IP address, which is why the test uses the forwarded port on localhost.

macOS and Windows

Install the client from the podman.io instructions (on Windows, an MSI installer that supports per-user and per-machine scope), then create and start the VM:

$ podman machine init
$ podman machine start

The machine starts in rootless mode. If a container needs root, for example to bind a port below 1024, the Windows guide switches the machine to rootful:

podman machine stop
podman machine set --rootful
podman machine start

On Windows, podman machine start also listens on the default Docker API named pipe, so Docker API clients work without setting DOCKER_HOST when nothing else owns that pipe.

Using the Docker-compatible socket on Linux

For tools that expect a Docker socket, the socket-activation tutorial starts the rootless API socket and points the client at it:

$ systemctl --user start podman.socket
$ export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
$ docker-compose up

Running services with Quadlet and Kubernetes YAML

Quadlet units

Quadlet runs containers as systemd services. Files placed in a search path such as /etc/containers/systemd/ for root or ~/.config/containers/systemd/ for a rootless user are read at boot and on systemctl daemon-reload, and each one produces a similarly named .service unit. The [Container] section is handled by Podman, while every other section passes through to systemd untouched, so dependencies, restart policies and cgroup limits use normal systemd syntax. This is a trimmed version of the test.container example from the man page:

[Unit]
Description=A minimal container

[Container]
Image=quay.io/centos/centos:latest
Volume=test.volume:/data
Network=test.network
Exec=sleep 60

[Service]
Restart=always
TimeoutStartSec=900

[Install]
WantedBy=multi-user.target default.target

Quadlet-generated services are transient, so systemctl enable fails with a "transient or generated" error; the troubleshooting guide's answer is to add an [Install] section instead, which the generator applies itself. After adding or editing a file, reload systemd:

systemctl --user daemon-reload

By default a name.container file creates a name.service unit and a container called systemd-name; the only required key is Image.

Kubernetes YAML

podman kube generate turns containers, pods or volumes into Kubernetes v1 YAML, producing a Pod by default. Bind mounts become hostPath volumes and named volumes become persistentVolumeClaim volumes; --service adds a Service object, and --type selects Deployment, DaemonSet or Job. Going the other way, podman kube play currently supports the Pod, Deployment, PersistentVolumeClaim, ConfigMap, Secret, DaemonSet and Job kinds, and it can read YAML from a file, stdin or a URL:

$ podman kube generate some-mariadb
$ podman kube play demo.yml
$ podman kube play --down demo.yml

The man page recommends that input YAML ideally be generated by Podman itself, since that "guarantees a smooth import and expected results". Kube play can also build images on the fly when a directory matching the image name contains a Containerfile, and a .kube Quadlet unit runs a YAML file as a systemd service.

Remote clients

The remote client uses a client-server model over SSH. On the Linux server, the user enables the Podman API socket and, for rootless users, enables lingering so the socket survives logout:

systemctl --user enable --now podman.socket
sudo loginctl enable-linger $USER

On the client, a named connection is added and becomes the default if it is the first one:

podman-remote system connection add myuser --identity ~/.ssh/id_ed25519 ssh://[email protected]/run/user/1000/podman/podman.sock

Commands then execute on the server while appearing local. The tutorial recommends ed25519 keys, since RSA keys can cause connection issues, and the remote client drops a few flags that make no sense remotely, such as --latest.

Use cases

  • Local development without root. Run databases and web servers as your own user, with bind-mounted source owned by your UID through --userns=keep-id.
  • Single-host services under systemd. Describe a container, its volume and network as Quadlet files, start them on boot, and let podman auto-update refresh images.
  • Prototyping Kubernetes workloads. Build a pod locally, export it with podman kube generate, and replay or tear it down with podman kube play.
  • Shared Linux hosts. Give each user a subordinate UID range so they can run containers without a privileged daemon or group membership.
  • Docker tooling on top of Podman. Point Docker API clients or docker-compose at the Podman socket on Linux, or the forwarded named pipe on Windows.

How it compares

The obvious comparison is Docker, and the project's own transfer guide is the most reliable source for it. It maps a long list of docker commands one-to-one to podman commands, from attach and build through volume rm and wait. It also lists Docker commands with no Podman equivalent: docker builder, buildx, config, context, container update, node, plugin, stack, swarm and update. For plugins it suggests alternative OCI runtimes or OCI runtime hooks; for swarm it points to Kubernetes via CRI-O; for altering running containers it recommends recreating them with the correct arguments. Podman in turn has commands Docker lacks, such as podman container checkpoint and restore.

The guide flags behavioural differences too. podman volume create errors if the volume already exists, whereas Docker's is idempotent, and podman run -v /tmp/noexist:/tmp reports a missing host path where Docker would create it; the Podman team "sees this as a bug in Docker". Several 6.0 changes were made explicitly to improve Docker compatibility, including network isolation on by default and podman volume prune pruning only anonymous volumes unless --all is passed.

Within the same tool family, the README positions Buildah as the image-building specialist and Podman as the tool for running and maintaining images and long-lived containers; Podman uses Buildah's Go API for builds, but the two keep separate container concepts and cannot see each other's containers. CRI-O is the daemon for Kubernetes' CRI, which Podman deliberately does not implement.

Things to know before adopting

  • Rootless needs administrator setup. Each user needs a unique range in /etc/subuid and /etc/subgid, a user-mode networking tool (pasta, from the passt package) must be installed, and the docs warn that "podman commands can easily fail" when subordinate IDs are missing. Changing these ranges later requires podman system migrate.
  • Rootless limitations are real. The project's shortcomings page lists no binding to ports below 1024 without changing net.ipv4.ip_unprivileged_port_start; no support for NFS or parallel filesystem home directories; a writable home directory not mounted noexec or nodev; only the overlay (optionally via fuse-overlayfs) and VFS storage drivers; images are hard to share with other users; a standard configuration maps 65,536 UIDs, so images with higher UIDs cannot be used; device nodes cannot be created; and CRIU checkpoint and restore require root.
  • Rootless networking quirks. Because pasta copies the main interface's IP address, connections from containers to that address do not work without extra pasta configuration, and the default rootlessport forwarder rewrites the source IP for UDP, loopback and same-host traffic. Source-IP preservation through pasta is marked experimental.
  • Containers stop at logout unless lingering is on. Rootless detached containers are stopped when the user session ends; the fix is loginctl enable-linger.
  • cgroups v2 is mandatory. Podman 6.0 removed support for cgroups v1 systems, along with iptables (use nftables), CNI networking (use Netavark) and slirp4netns (use pasta). Quadlet has required cgroup v2 independently. On some systemd hosts, rootless CPU and cpuset limits also need controller delegation configured by an administrator.
  • A VM is required on macOS and Windows. Every container runs inside a podman machine guest. Podman 6.0 dropped support for Intel Macs and Windows 10; Windows needs Windows 11, hardware virtualization and WSL 2.5.1 or later, and the installer no longer installs WSL for you. Hyper-V is limited to Enterprise, Pro and Education editions and needs administrator rights or a one-time podman system hyperv-prep. WSL and Hyper-V machines cannot run at the same time, and rootful and rootless machine modes keep separate container state.
  • Version alignment matters. A mismatch between Podman on the host and Podman inside the machine is unsupported, and for remote setups the troubleshooting guide says client and server "must be upgraded to the same version".
  • Only the latest release is supported upstream. The README states that only the most recent release receives upstream support, with occasional LTS exceptions, and the troubleshooting guide notes that many reported issues are already fixed in newer versions. If your distribution ships an older Podman, expect to check the latest release before filing bugs.
  • Major versions break things. 6.0 required matching Buildah, Skopeo, Netavark and Aardvark versions, migrated BoltDB databases to SQLite, rewrote config parsing, changed volume and filter semantics, and broke volume mounts on existing Linux podman machine VMs, which have to be recreated. Read the release notes before upgrading.
  • Docker compatibility is broad, not total. Swarm, stacks, plugins, contexts, buildx and in-place container updates are missing, and some commands behave differently, as covered above.
  • Quadlet differs from plain systemd. Units cannot be enabled with systemctl enable, the User=, Group= and DynamicUser= options are not supported (rootless Quadlets go in a user's search path instead), and image pulls can exceed systemd's default 90-second start timeout.

Project activity

As of November 2026 the repository has about 33,200 stars and roughly 3,450 forks. It was created on 1 November 2017, is written in Go, and is licensed under Apache-2.0. The project publishes a major or minor release four times a year, in the second week of February, May, August and November, with patch releases in between, and all releases are PGP signed. The latest entry in the release notes is 6.1.0, which added podman volume rename, podman machine restart and healthchecks as livenessProbe in generated Kubernetes YAML.

The repository now lives in the podman-container-tools organization; the 6.0.0 release notes describe the Go import path changing to go.podman.io/podman/v6 "as part of our move into a CNCF-owned GitHub organization". Community meetings and office hours are open to everyone and hosted through the CNCF and Linux Foundation, and security issues go privately to [email protected] rather than the public tracker.

Source code and issues are at github.com/podman-container-tools/podman, the project site is podman.io, and documentation is at docs.podman.io.

Enjoying this project?

Discover more amazing open-source projects on TechLogHub. We curate the best developer tools and projects.

Project
podman
Created
November 12
Last Updated
November 12, 2026 at 01:35 PM

Maintain Podman: Daemonless, Rootless OCI Container Engine? Add the badge to your README

Show that the project is featured on TechLogHub and send readers to this write-up.

Featured on TechLogHub
[![Featured on TechLogHub](https://techloghub.com/badge-neutral.svg)](https://techloghub.com/open-source/podman?utm_source=techloghub_badge&utm_medium=referral&utm_campaign=readme)

Find more projects like this

One email a week: new and trending developer tools, fresh comparisons, and what shipped. Unsubscribe in one click.