Running and Managing Podman Containers
The five states a container moves through, and the two flags that decide whether you ever see it again. An unnamed container gets a name like `objective_elgamal`, and `--rm` means it is gone before you can list it.
Containers and Images Guide 5 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.21 | Ubuntu 26.04 LTS | Primary Container Host | 2 Core | 4 GB | 50 GB |
Before you start
- Podman installed - see guide 1.
curlon the host, to prove the published port works.
-
A container that is already gone
The simplest possible container: run a command, print a line, exit.
Then list containers including stopped ones with
-a, and the list is empty.--rmremoved it the moment it exited.This is worth doing first because it establishes what a container is: a process that ran and finished. It is not a machine that stays up. Without
--rmit would still be listed - inExitedstate, taking up a name and a little disk - which is where the pile of dead containers on an untended host comes from.bash Example session podman run --rm docker.io/library/alpine echo "this container is already gone"this container is already gonepodman ps -a --format 'table {{.Names}} {{.Status}}'NAMES STATUSExpected resultThe echoed line, then an empty container list even with
-a.Success conditionYou ran a container and it left nothing behind.
-
Detached, named, and reachable
Three flags do most of the work in practice:
-ddetaches. The command returns the container ID instead of blocking, and the process keeps running.--name sitegives it a name you choose. Skip it and Podman generates one - the--rmcontainer in step 1 was calledobjective_elgamal, which you will see in the event log later. Memorable, but not something to write a script against.-p 8081:80publishes container port 80 as host port 8081. Host port first, and the order being easy to reverse is whypodman portexists.
curlreturnshttp=200, so nginx is genuinely serving through the published port - not merely running.bash Example session podman run -d --name site -p 8081:80 docker.io/library/nginx:alpine725ae48d0232417bb7f90921514bb13971b4a5f6b7018c4775fd48a89eda8cd8podman ps --format 'table {{.Names}} {{.Image}} {{.Status}} {{.Ports}}'NAMES IMAGE STATUS PORTSsite docker.io/library/nginx:alpine Up Less than a second 0.0.0.0:8081->80/tcpcurl -s -o /dev/null -w 'http=%{http_code}\n' http://localhost:8081http=200Expected resultA container ID, one row showing
0.0.0.0:8081->80/tcp, andhttp=200.Success conditionA named container is running detached and answering on a host port.
-
Stop, and notice what stop does not do
podman stop siteprints the name back. Now the important pair:podman ps- empty. Nothing is running.podman ps -a-site Exited (0).
The container still exists. Stopping is not removing. It keeps its name, its configuration, its writable layer and its logs, and the
(0)is its exit code - a clean exit rather than a crash.That distinction is the one beginners lose most time to.
podman psshowing nothing does not mean the host is clean, and a name stays taken until the container is removed - which is whyrun --name sitewill refuse while this one exists.bash Example session podman stop sitesitepodman ps --format 'table {{.Names}} {{.Status}}'NAMES STATUSpodman ps -a --format 'table {{.Names}} {{.Status}}'NAMES STATUSExpected resultAn empty
podman psand asite Exited (0)row underpodman ps -a.Success conditionYou can tell the difference between a stopped container and no container.
-
Start, restart, and remove
podman start sitebrings the same container back - same writable layer, same name, same configuration. Anything written inside it before the stop is still there.podman restart siteis stop and start in one step. Worth knowing that it goes through the same SIGTERM path a stop does, so on a container that ignores SIGTERM a restart costs the full timeout - see guide 15.Then
stopandrm, andpodman ps -ais empty. The lifecycle in full: created, running, stopped, running again, removed. Only the last one is irreversible -rmdiscards the writable layer, so anything the container wrote outside a volume is gone with it.bash Example session podman start sitesitepodman restart sitesitepodman ps --format 'table {{.Names}} {{.Status}}'NAMES STATUSpodman stop sitesitepodman rm sitesiteExpected resultThe name echoed by each command, a running container in between, and nothing left at the end.
Success conditionYou have driven one container through its whole lifecycle deliberately.
Troubleshooting
Error: creating container storage: the container name "site" is already in use.Why: A stopped container still holds the name.
Fix:
podman ps -ato find it, thenpodman rm site. Or usepodman run --replaceto remove and recreate in one step.podman runblocks and you cannot get your prompt back.Why: No
-d, so the container is in the foreground.Fix:Ctrl-C stops it. Re-run with
-d. Note that Ctrl-P Ctrl-Q to detach only works if you started it with-it.The container is
Upbutcurlto the host port is refused.Why: Either nothing is listening inside, or the ports are the wrong way round.
Fix:
podman port siteshows the mapping as Podman understands it.-p HOST:CONTAINERis the order.Exited (137)rather thanExited (0).Why: 137 is 128+9 - the process was killed with SIGKILL, usually a stop timeout or the out-of-memory killer.
Fix:
podman inspect site --format '{{.State.OOMKilled}}'distinguishes the two.