close

DEV Community

David Tio
David Tio

Posted on • Originally published at blog.dtio.app

Run Your First Podman Container: Images, Lifecycle, and Flags (2026)

🐳 Run Your First Podman Container: Images, Lifecycle, and Flags (2026)

Quick one-liner: Pull images, run containers, manage their lifecycle, and understand the flags that make Podman different from Docker.


🤔 Why This Matters

In Ep 1, you installed Podman, set up shared storage, and verified rootless operation. Now it's time to actually do something with it.

This post walks you through:

  • Finding and pulling images from container registries
  • Running your first container with the right flags
  • Managing container lifecycles (start, stop, restart, remove)
  • The key differences between podman run and docker run

By the end, you'll be comfortable managing containers with Podman. You'll also understand why podman run is a drop-in replacement for docker run.


✅ Prerequisites

  • Podman installed, rootless on SLES 16 (see Ep 1)
  • Shared storage configured (multi-user UID/GID setup)
  • 5 minutes to run your first workload

🔍 Finding Images

Podman uses container registries to pull images. On SLES, the default registry is registry.suse.com. It's SUSE's own registry with images built and maintained for SLES:

$ podman search nginx
NAME                                                                              DESCRIPTION
registry.suse.com/caasp/v4/nginx-ingress-controller                               
registry.suse.com/caasp/v4.5/ingress-nginx-controller                             
registry.suse.com/caasp/v5/ingress-nginx-controller                               
registry.suse.com/cap/nginx-buildpack                                             
registry.suse.com/cap/stratos-metrics-nginx                                       
registry.suse.com/cap/suse-nginx-buildpack                                        
registry.suse.com/rancher/library-nginx                                           
registry.suse.com/suse/nginx                                                      
Enter fullscreen mode Exit fullscreen mode

Start here. If the image you need is in the SUSE registry, use it. It's tested on SLES, receives security updates, and works seamlessly with your system.

But the SUSE registry doesn't have everything. If you can't find an image there, fall back to Docker Hub (docker.io) or Quay (quay.io), which is where most of the world's container images live. To search Docker Hub, prefix with the registry name:

$ podman search docker.io/library/nginx
NAME                                              DESCRIPTION
docker.io/library/nginx                           Official build of Nginx.
docker.io/nginx/nginx-ingress                     NGINX and NGINX Plus Ingress Controllers...
docker.io/nginx/nginx-prometheus-exporter         NGINX Prometheus Exporter for NGINX...
docker.io/nginx/unit                              This repository is retired, use the Docker...
docker.io/nginx/nginx-ingress-operator            NGINX Ingress Operator for NGINX and NGINX...
docker.io/bitnami/nginx                           Bitnami Secure Image for nginx
Enter fullscreen mode Exit fullscreen mode

Look for the official images (from docker.io/library/). They're maintained by the software's creators and receive regular security updates.


🐳 Running Your First Container

Let's run nginx from the SUSE registry:

$ podman run -d --rm --name dtnginx suse/nginx
Enter fullscreen mode Exit fullscreen mode

Let me break down each flag:

Flag What It Does
-d Detach: runs the container in the background so you get your terminal back
--rm Auto-remove: automatically deletes the container once it stops
--name dtnginx Name it dtnginx instead of a random ID
suse/nginx The image to run. Podman on SLES searches registry.suse.com by default, so the short name works

If this is the first time running this image, Podman downloads it:

Resolving "suse/nginx" using unqualified-search registries (/etc/containers/registries.conf)
Trying to pull registry.suse.com/suse/nginx:latest...
Getting image source signatures
Checking if image destination supports signatures
Copying blob 5a22de652f81 done   |
Copying blob 36e296237f0c done   |
Copying config 885ea61474 done   |
Writing manifest to image destination
Storing signatures
Enter fullscreen mode Exit fullscreen mode

📊 Checking Container Status

Verify it's running:

$ podman ps
CONTAINER ID  IMAGE                                COMMAND               CREATED        STATUS         PORTS       NAMES
431e72ff8902  registry.suse.com/suse/nginx:latest  nginx -g daemon o...  10 seconds ago Up 10 seconds  80/tcp      dtnginx
Enter fullscreen mode Exit fullscreen mode

Note: podman ps and docker ps produce identical output. If you've used Docker, the commands feel the same.

To see all containers (including stopped ones):

$ podman ps -a
CONTAINER ID  IMAGE                                COMMAND               CREATED         STATUS                     PORTS       NAMES
431e72ff8902  registry.suse.com/suse/nginx:latest  nginx -g daemon o...  2 minutes ago   Up 2 minutes               80/tcp      dtnginx
2ea01225897d  quay.io/podman/hello:latest          /usr/local/bin/po...  3 minutes ago   Exited (0) 3 minutes ago               hopeful_heyrovsky
Enter fullscreen mode Exit fullscreen mode

dtnginx is still running in the background. The hello container from Ep1 is sitting in "Exited" state. Because it was run without --rm, it stayed around after it finished.

💡 Tip: forgot to name your container? Podman assigns random names like hopeful_heyrovsky or agitated_villani. You can rename it anytime:

$ podman rename hopeful_heyrovsky dthello

Now podman ps -a shows dthello instead. Much easier to manage.

To clean up stopped containers, use podman rm:

$ podman rm dthello
dthello
$ podman ps -a
CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES
Enter fullscreen mode Exit fullscreen mode

💻 Accessing the Container Shell

Open a shell inside the running container:

$ podman exec -it dtnginx /bin/bash
Enter fullscreen mode Exit fullscreen mode
Flag What It Does
-i Keeps stdin open
-t Allocates a pseudo-terminal

You're now inside the container. Check the nginx default page:

bash-5.2# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the container with the nginx web server is 
successfully installed and working.</p>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Exit the shell:

bash-5.2# exit
Enter fullscreen mode Exit fullscreen mode

🛑 Stopping and Cleaning Up

Stop the container:

$ podman stop dtnginx
Enter fullscreen mode Exit fullscreen mode

Since we used --rm, it's automatically removed. Confirm:

$ podman ps -a
CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES
Enter fullscreen mode Exit fullscreen mode

No sign of dtnginx. The --rm flag took care of it.

If you forgot --rm, the container stays around in "Exited" state. Clean it up:

$ podman rm dtnginx
Enter fullscreen mode Exit fullscreen mode

Or remove all stopped containers at once:

$ podman container prune
Enter fullscreen mode Exit fullscreen mode

⚙️ Environment Variables

Many container images are configured through environment variables instead of editing config files. This is how you run databases, web apps, and services without ever touching a config file inside the container.

Use the -e flag to pass variables at runtime. Let's run MariaDB:

$ podman run -d --rm --name dtmariadb \
    -e MARIADB_ROOT_PASSWORD=podman \
    -e MARIADB_DATABASE=testdb \
    suse/mariadb
Enter fullscreen mode Exit fullscreen mode

This starts MariaDB with the root password set to podman and automatically creates a database called testdb. Without MARIADB_ROOT_PASSWORD, the container refuses to start.

You can verify the variables inside a running container:

$ podman exec dtmariadb env | grep MARIADB
MARIADB_ROOT_PASSWORD=podman
MARIADB_DATABASE=testdb
Enter fullscreen mode Exit fullscreen mode

To connect to the database from inside the container:

$ podman exec -it dtmariadb mariadb -u root -ppodman -e "SHOW DATABASES;"
Database
information_schema
mysql
performance_schema
testdb
Enter fullscreen mode Exit fullscreen mode

Each image documents its supported environment variables on its Docker Hub page. Scroll down to the "Environment Variables" section and you'll find everything you need. Things like POSTGRES_PASSWORD, MYSQL_ROOT_PASSWORD, REDIS_PASSWORD, and dozens more. That's always the first place I check before running a new database image.

Stop the container when done:

$ podman stop dtmariadb
Enter fullscreen mode Exit fullscreen mode

🔄 Key Differences: Podman vs Docker

You'll notice the commands are nearly identical. But here's what's different under the hood:

Feature Docker Podman
Daemon Required (dockerd) No daemon needed. Containers run as direct child processes
Rootless Requires extra setup Rootless by default, no extra setup needed
Systemd integration Manual Native support via podman generate systemd
Pod support Via Compose Native support via podman pod create
Fork/exec model Single daemon manages all Each container is independent

In practice: alias docker=podman works for 95% of daily commands.


🏋️ Exercise

Part 1: Run Redis and Store Data

Redis isn't in the SUSE registry (the available image is 8 years old), so we fall back to Docker Hub:

$ podman run -d --rm --name dtredis docker.io/library/redis
$ podman exec -it dtredis redis-cli
Enter fullscreen mode Exit fullscreen mode
127.0.0.1:6379> SET mykey "Hello from Podman!"
OK
127.0.0.1:6379> GET mykey
"Hello from Podman!"
127.0.0.1:6379> exit
Enter fullscreen mode Exit fullscreen mode

Part 2: Run PostgreSQL and Add Data

$ podman run -d --rm --name dtpg \
    -e POSTGRES_PASSWORD=podman \
    -e POSTGRES_DB=testdb \
    suse/postgres
Enter fullscreen mode Exit fullscreen mode

Wait ~10 seconds for PostgreSQL to initialize, then create a table and insert some data:

$ podman exec -it dtpg psql -U postgres -d testdb
Enter fullscreen mode Exit fullscreen mode
testdb=# CREATE TABLE users (name VARCHAR(50), email VARCHAR(50));
CREATE TABLE
testdb=# INSERT INTO users VALUES ('Alice', 'alice@example.com');
INSERT 0 1
testdb=# SELECT * FROM users;
 name  |       email        
-------+--------------------
 Alice | alice@example.com
(1 row)
testdb=# \q
Enter fullscreen mode Exit fullscreen mode

Alice is in the database. Everything looks good.

Part 3: Remove Both and Lose Everything

$ podman stop dtredis dtpg
$ podman ps -a
CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES
Enter fullscreen mode Exit fullscreen mode

Both are gone (thanks to --rm). Now start fresh containers:

$ podman run -d --rm --name dtredis docker.io/library/redis
$ podman exec -it dtredis redis-cli
Enter fullscreen mode Exit fullscreen mode
127.0.0.1:6379> GET mykey
(nil)
Enter fullscreen mode Exit fullscreen mode

Redis data is gone. Now check PostgreSQL:

$ podman run -d --rm --name dtpg \
    -e POSTGRES_PASSWORD=podman \
    -e POSTGRES_DB=testdb \
    suse/postgres
$ podman exec -it dtpg psql -U postgres -d testdb -c "SELECT * FROM users;"
ERROR:  relation "users" does not exist
Enter fullscreen mode Exit fullscreen mode

Alice is gone. The table is gone. The database is a fresh empty shell.

Containers are ephemeral by design. When they go, everything inside them goes with them.

Next chapter: we rescue Alice. Persistent storage that survives container death.


👉 Coming up: You've got nginx running and MariaDB configured. But here's a problem. Stop the container, remove it, start a new one, and your data is gone. The database you just created? Disappeared.

Next time: we fix that. Persistent storage that survives container death. Your data lives on even when containers come and go.


Found this helpful? 🙌

Top comments (0)