Podman Without a Daemon
Start a container, then look for the process that owns it. `pgrep podman` finds nothing, `podman.service` is inactive, and the running nginx is a child of PID 1 by way of a 96-argument monitor called conmon.
Foundations Guide 2 of 47 Beginner
- OSUbuntu 26.04 LTS (resolute)
- Podman5.7.0
- Runtimecrun 1.21
- Networknetavark 1.16.1
- TimeAbout 12 min
- Reviewed22 August 2026
Written against the versions above. Podman follows the distribution here rather than a vendor repository, so the version you get is the one Ubuntu shipped. The commands are stable across 5.x.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| PODMAN01 | 192.168.0.24 | Ubuntu 26.04 LTS | Primary Container Host | 2 Core | 4 GB | 50 GB |
Before you start
- Podman installed - see guide 1.
pstree, from thepsmiscpackage. It is the clearest single piece of evidence here.
-
Start something long-running
A container that exits immediately proves nothing about what supervises it, so start nginx and leave it running.
Then ask the obvious question: which process is Podman?
bash Example session podman run -d --name web docker.io/library/nginx:alpine55f03c179ef1648c4a1fa40440f177a9ef06ff3274cc37e05e77d9bb7c755decpgrep -a podman [exit 1]Expected resultA container ID, then
pgrep -a podmanprinting nothing and exiting 1.Success conditionA container is running and there is no
podmanprocess on the machine. -
One monitor per container, parented to init
There is exactly one new process, and it is not Podman. It is conmon - the container monitor - and there is one of them per running container.
Two fields in the
psoutput carry the whole architecture:- PPID is 1. conmon's parent is
systemd, not a Podman daemon. Podman double-forks it and exits, so conmon is re-parented to init and survives the command that created it. - USER is your own account. Nothing here belongs to root.
pstreedraws it in one line. Read it as the answer to "what would a daemon have been doing":systemd(1)---conmon(4859)---nginx(4861)bash Example session pgrep -c conmon1ps -o pid,ppid,user,comm -p $(pgrep conmon | head -1) PID PPID USER COMMAND 4859 1 sysadmin conmonpstree -sp $(pgrep conmon | head -1)systemd(1)---conmon(4859)---nginx(4861)-+-nginx(4886) `-nginx(4887)Expected resultOne conmon, PPID 1, owned by you, with nginx as its child.
Success conditionYou can point at the process that supervises the container, and it is not a daemon.
- PPID is 1. conmon's parent is
-
Why nothing needs to stay running
The obvious objection: if
podmanhas exited, what cleans up when the container stops? Who removes the network, unmounts the layers, writes the exit code?conmon does, and it was told how at creation time. Its command line is 96 arguments long, and two of them are the answer:
-r /usr/bin/crun- the runtime it drives--exit-command /usr/bin/podman- the command to run when the container dies
That is the trick. Everything a daemon would have remembered is instead passed to the monitor once, up front. There is no shared state to keep in memory, so there is nothing that has to stay running to hold it. The cost is 96 arguments; the benefit is that killing any one container's monitor cannot affect any other container, and there is no single process whose crash takes down everything.
Meanwhile systemd still reports no Podman service, while
podman psanswers perfectly well - becausepodman psreads a database on disk, not a daemon.bash Example session ps -o args= -p $(pgrep conmon | head -1) | tr ' ' '\n' | grep -c .96ps -o args= -p $(pgrep conmon | head -1) | grep -oE '\-r /usr/bin/[a-z]+|--exit-command /usr/bin/[a-z]+'-r /usr/bin/crun--exit-command /usr/bin/podmansystemctl is-active podman.serviceinactive[exit 3]Expected result96 arguments, the crun runtime and the podman exit command, and
inactivefrom systemd.Success conditionYou can explain what replaces the daemon's memory, and it is a list of arguments.
-
Stop it, and watch the monitor go
The lifecycle is symmetric. Stopping the container ends its monitor, and the count returns to zero. No service was started and none is left behind.
This is worth internalising before the Systemd and Quadlet track, because it explains what that track is for: with no daemon to restart your containers at boot, systemd is the thing that does it - not as a Podman service, but as one unit per container.
bash Example session podman stop webwebpgrep -c conmon1podman rm webwebExpected resultThe container name echoed back, then
0conmon processes with exit 1.Success conditionNo container, no monitor, and nothing running that has to be cleaned up.
Troubleshooting
pgrep -a podmanDOES return a process.Why: Either a
podmancommand is genuinely still running - arunin the foreground, abuild, apull- or the API socket is enabled andpodman system serviceis up.Fix:Check with
systemctl --user is-active podman.socket. The socket is opt-in and off by default; it appears in the Compose and Remote Hosts track.pstreeshows conmon's parent as something other than 1.Why: You are looking at a rootful container under a cgroup manager that keeps it under a systemd scope, or the container is in a pod and you found the infra container's monitor.
Fix:
ps -o pid,ppid,args -C conmonlists every monitor with its container ID, so you can match the one you meant againstpodman ps -q.pstree: command not found.Why:
psmiscis not installed. It is not a Podman dependency.Fix:
sudo apt-get install -y psmisc. Or useps -o pid,ppid,comm --forestfor a rougher version of the same picture.