CertGrid CertGrid
Hands-on Lab·Podman

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

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.

Every command on this page ran on podman01.
Server NameIP AddressOSRolesCPURAMHDD
PODMAN01192.168.0.21Ubuntu 26.04 LTSPrimary Container Host2 Core4 GB50 GB

Before you start

  1. 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. --rm removed 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 --rm it would still be listed - in Exited state, 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       STATUS

    Expected resultThe echoed line, then an empty container list even with -a.

    Success conditionYou ran a container and it left nothing behind.

  2. Detached, named, and reachable

    Three flags do most of the work in practice:

    • -d detaches. The command returns the container ID instead of blocking, and the process keeps running.
    • --name site gives it a name you choose. Skip it and Podman generates one - the --rm container in step 1 was called objective_elgamal, which you will see in the event log later. Memorable, but not something to write a script against.
    • -p 8081:80 publishes container port 80 as host port 8081. Host port first, and the order being easy to reverse is why podman port exists.

    curl returns http=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=200

    Expected resultA container ID, one row showing 0.0.0.0:8081->80/tcp, and http=200.

    Success conditionA named container is running detached and answering on a host port.

  3. Stop, and notice what stop does not do

    podman stop site prints 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 ps showing nothing does not mean the host is clean, and a name stays taken until the container is removed - which is why run --name site will 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       STATUS

    Expected resultAn empty podman ps and a site Exited (0) row under podman ps -a.

    Success conditionYou can tell the difference between a stopped container and no container.

  4. Start, restart, and remove

    podman start site brings the same container back - same writable layer, same name, same configuration. Anything written inside it before the stop is still there.

    podman restart site is 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 stop and rm, and podman ps -a is empty. The lifecycle in full: created, running, stopped, running again, removed. Only the last one is irreversible - rm discards 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 sitesite

    Expected 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

Official sources