SLE BCI Documentation
GitHubToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage
Edit page

Launch Containers with Podman and Systemd

Local Container Orchestration

A container runtime makes it easy to launch an application distributed as a single container. But things get more complicated when you need to run applications consisting of multiple containers, or when it’s necessary to start the applications automatically on system boot and restart them after they crash. While container orchestration tools like Kubernetes are designed for that exact purpose, they are intended to be used for highly distributed and scalable systems with hundreds of nodes, and not for a single machine. systemd and Podman are much better suited for the single-machine scenario, as they do not add another layer complexity to your existing setup.


Starting with version 1.3.0, Podman supports creating systemd unit files with the podman generate systemd subcommand. The subcommand creates a systemd unit file, making it possible to control a container or pod via systemd. Using the unit file you can launch a container or pod on boot, automatically restart it if a failure occurs, and keep its logs in journald.

Creating a new Systemd Unit File

The following example uses a simple NGINX container:

❯ podman run -d --name web -p 8080:80

Generating a systemd unit for the container can be done as follows:

❯ podman generate systemd --name --new web
# container-web.service
# autogenerated by Podman 4.2.0
# Tue Sep 13 10:58:54 CEST 2022

Description=Podman container-web.service

ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run \
        --cidfile=%t/%n.ctr-id \
        --cgroups=no-conmon \
        --rm \
        --sdnotify=conmon \
        --replace \
        -d \
        --name web \
        -p 8080:80
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id


Podman outputs a unit file to the console that can be put either into the user unit systemd directories (~/.config/systemd/user/ or /etc/systemd/user/) or into the system unit systemd directory (/etc/systemd/systtem) and control the container via systemd. The --new flag instructs Podman to recreate the container on a restart. This ensures that the systemd unit is self-contained, and it does not depend on external state. The --name flag allows you to assign a user-friendly name to the container: without it Podman uses container IDs instead of their names.

To control the container as a user unit, proceed as follows:

❯ podman generate systemd --name --new --files web
❯ mv container-web.service ~/.config/systemd/user/
❯ systemctl --user daemon-reload

Now the container can be started via systemctl --user start container-web:

❯ systemctl --user start container-web
❯ systemctl --user is-active container-web.service

Run the podman ps command to see the list of all running containers :

❯ podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED         STATUS             PORTS                 NAMES
af92743971d2  nginx -g daemon o...  15 minutes ago  Up 15 minutes ago>80/tcp  web

One of the benefits of managing the container via systemd is the ability to automatically restart the container if it crashes. You can simulate a crash by sending SIGKILL to the main process in the container:

❯ podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED             STATUS                 PORTS                 NAMES
4c89582fa9cb  nginx -g daemon o...  About a minute ago  Up About a minute ago>80/tcp  web

❯ kill -9 $(podman inspect --format "{{.State.Pid}}" web)

❯ podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS                 NAMES
0b5be4493251  nginx -g daemon o...  4 seconds ago  Up 4 seconds ago>80/tcp  web

Note that the container is not restarted when it is stopped gracefully, e.g. via podman stop web. To always restart it, add the flag --restart-policy=always to podman generate systemd.

Updating container images

Using the described approach means that the container image is never updated. You can solve the problem by adding the --pull=always flag to the ExecStart= entry in the unit file. But be aware that this increases the startup time of the container and updates the image on every restart. The latter also means that a container image update can make the container unavailable outside of a scheduled maintenance window due to a newly introduced bug.

The auto-update subcommand in Podman provides a possible solution. Add the label io.containers.autoupdate=registry to a container to make Podman pull a new version of the container image from the registry when running podman auto-update. This makes it possible to update all container images with a single command at a desired time, and without increasing the startup time of the systemd units.

The auto update feature can be enabled by adding the line --label "io.containers.autoupdate=registry" \ to the ExecStart= entry of the container’s systemd unit file. for the NGINX example, modify ~/.config/systemd/user/container-web.service as follows:

ExecStart=/usr/bin/podman run \
        --cidfile=%t/%n.ctr-id \
        --cgroups=no-conmon \
        --rm \
        --sdnotify=conmon \
        --replace \
        -d \
        --name web \
        --label "io.containers.autoupdate=registry" \
        -p 8080:80

After reloading the daemons and restarting the container, perform a dry run of the update (it will most likely not report any updates):

❯ podman auto-update --dry-run
UNIT                   CONTAINER           IMAGE            POLICY      UPDATED
container-web.service  87d263489307 (web)  registry    false

It is good practice to have external testing in place to make sure that image updates are generally safe to be deployed. If you are confident in the quality of our container image, you can let Podman automatically apply image updates periodically by enabling the podman-auto-update.timer:

# just for the current user
❯ systemctl --user enable podman-auto-update.timer
Created symlink /home/user/.config/systemd/user/ → /usr/lib/systemd/user/podman-auto-update.timer.
# or as root
❯ sudo systemctl enable podman-auto-update.timer
Created symlink /etc/systemd/system/ → /usr/lib/systemd/system/podman-auto-update.timer.

Managing multiple containers

Certain applications rely on more than one container to function, for example a web frontend, a backend server and a database. Docker compose is popular tool for deploying multi-container applications on a single machine. While Podman does not support the compose command natively, in most cases compose files can be ported to a Podman pod and multiple containers.

The following example deploys a Drupal and PostgreSQL container in a single pod and manages these via systemd units. First, create a new pod that exposes the Drupal web interface:

❯ podman pod create -p 8080:80 --name drupal

Once the pod has been created, launch the Drupal frontend and the PostgreSQL database inside it:

❯ podman run -d --name drupal-frontend --pod drupal

❯ podman run -d --name drupal-pg --pod drupal \
      -e POSTGRES_DB=drupal \
      -e POSTGRES_USER=user \
      -e POSTGRES_PASSWORD=pass \

This results in three running containers: the Drupal web interface, the PostgreSQL database and the pod’s infrastructure container.

❯ podman ps
CONTAINER ID  IMAGE                                    COMMAND               CREATED             STATUS                 PORTS                 NAMES
2948fa1476c6  localhost/podman-pause:4.2.0-1660228937                        2 minutes ago       Up About a minute ago>80/tcp  736cab072c49-infra
ffd2fbd6d445          apache2-foregroun...  About a minute ago  Up About a minute ago>80/tcp  drupal-frontend
a4dc31b24000            postgres              40 seconds ago      Up 41 seconds ago>80/tcp  drupal-pg

Creating a systemd unit for the pod is done similar to a single container:

❯ podman generate systemd --name --new --files drupal
❯ mv *service ~/.config/systemd/user/
❯ systemctl daemon-reload --user

Since Podman is aware of which containers belong to the drupal pod and how their systemd units are called, it can correctly add the dependencies to the pod’s unit file. This means that when you start or stop the pod, systemd ensures that all containers inside the pod are started or stopped automatically.

To check systemd’s dependency handling, first stop the drupal pod and verify that no containers are currently running on the host:

❯ podman pod stop drupal
❯ podman pod rm drupal
❯ podman ps -a

Start the drupal pod via systemctl start --user pod-drupal.service, and systemd launches the containers inside the pod:

❯ systemctl start --user pod-drupal.service
❯ podman ps
CONTAINER ID  IMAGE                                    COMMAND               CREATED        STATUS            PORTS                 NAMES
d1589d3ac68b  localhost/podman-pause:4.2.0-1660228937                        5 seconds ago  Up 5 seconds ago>80/tcp  ca41b505bd13-infra
a49bea53c20c            postgres              4 seconds ago  Up 5 seconds ago>80/tcp  drupal-pg
dc9dca018dad          apache2-foregroun...  4 seconds ago  Up 5 seconds ago>80/tcp  drupal-frontend