Chapter 14. Porting containers to systemd using Podman Podman (Pod Manager) is a simple daemonless tool fully featured container engine. Podman provides a Docker-CLI comparable command line that makes the transition from other container engines easier and enables the management of pods, containers, and images. Originally, Podman was not designed to provide an entire Linux system or manage services, such as start-up order, dependency checking, and failed service recovery. systemd was responsible for a complete system initialization. Due to Red Hat integrating containers with systemd , you can manage OCI and Docker-formatted containers built by Podman in the same way as other services and features are managed in a Linux system. You can use the systemd initialization service to work with pods and containers. With systemd unit files, you can: Set up a container or pod to start as a systemd service. Define the order in which the containerized service runs and check for dependencies (for example making sure another service is running, a file is available or a resource is mounted). Control the state of the systemd system using the systemctl command. You can generate portable descriptions of containers and pods by using systemd unit files. 14.1. Auto-generating a systemd unit file using Quadlets With Quadlet, you describe how to run a container in a format that is very similar to regular systemd unit files. The container descriptions focus on the relevant container details and hide technical details of running containers under systemd . Create the <CTRNAME> .container unit file in one of the following directories: For root users: /usr/share/containers/systemd/ or /etc/containers/systemd/ For rootless users: USDHOME/.config/containers/systemd/ , USDXDG_CONFIG_HOME/containers/systemd/, /etc/containers/systemd/users/USD(UID) , or /etc/containers/systemd/users/ Note Quadlet is available beginning with Podman v4.6. Prerequisites The container-tools meta-package is installed. Procedure Create the mysleep.container unit file: In the [Container] section you must specify: Image - container mage you want to tun Exec - the command you want to run inside the container This enables you to use all other fields specified in a systemd unit file. Create the mysleep.service based on the mysleep.container file: Optional: Check the status of the mysleep.service : Start the mysleep.service : Verification Check the status of the mysleep.service : List all containers: Note that the name of the created container consists of the following elements: a systemd- prefix a name of the systemd unit, that is systemd-mysleep This naming helps to distinguish common containers from containers running in systemd units. It also helps to determine which unit a container runs in. If you want to change the name of the container, use the ContainerName field in the [Container] section. Additional resources Make systemd better for Podman with Quadlet Quadlet upstream documentation 14.2. Enabling systemd services When enabling the service, you have different options. Procedure Enable the service: To enable a service at system start, no matter if user is logged in or not, enter: You have to copy the systemd unit files to the /etc/systemd/system directory. To start a service at user login and stop it at user logout, enter: You have to copy the systemd unit files to the USDHOME/.config/systemd/user directory. To enable users to start a service at system start and persist over logouts, enter: Additional resources systemctl and loginctl man pages on your system Enabling a system service to start at boot 14.3. Auto-starting containers using systemd You can control the state of the systemd system and service manager using the systemctl command. You can enable, start, stop the service as a non-root user. To install the service as a root user, omit the --user option. Prerequisites The container-tools meta-package is installed. Procedure Reload systemd manager configuration: Enable the service container.service and start it at boot time: Start the service immediately: Check the status of the service: You can check if the service is enabled using the systemctl is-enabled container.service command. Verification List containers that are running or have exited: Note To stop container.service , enter: Additional resources systemctl man page on your system Running containers with Podman and shareable systemd services Enabling a system service to start at boot 14.4. Advantages of using Quadlets over the podman generate systemd command You can use the Quadlets tool, which describes how to run a container in a format similar to regular systemd unit files. Note Quadlet is available beginning with Podman v4.6. Quadlets have many advantages over generating unit files using the podman generate systemd command, such as: Easy to maintain : The container descriptions focus on the relevant container details and hide technical details of running containers under systemd . Automatically updated : Quadlets do not require manually regenerating unit files after an update. If a newer version of Podman is released, your service is automatically updated when the systemclt daemon-reload command is executed, for example, at boot time. Simplified workflow : Thanks to the simplified syntax, you can create Quadlet files from scratch and deploy them anywhere. Support standard systemd options : Quadlet extends the existing systemd-unit syntax with new tables, for example, a table to configure a container. Note Quadlet supports a subset of Kubernetes YAML capabilities. For more information, see the support matrix of supported YAML fields . You can generate the YAML files by using one of the following tools: Podman: podman generate kube command OpenShift: oc generate command with the --dry-run option Kubernetes: kubectl create command with the --dry-run option Quadlet supports these unit file types: Container units : Used to manage containers by running the podman run command. File extension: .container Section name: [Container] Required fields: Image describing the container image the service runs Kube units : Used to manage containers defined in Kubernetes YAML files by running the podman kube play command. File extension: .kube Section name: [Kube] Required fields: Yaml defining the path to the Kubernetes YAML file Network units : Used to create Podman networks that may be referenced in .container or .kube files. File extension: .network Section name: [Network] Required fields: None Volume units : Used to create Podman volumes that may be referenced in .container files. File extension: .volume Section name: [Volume] Required fields: None Additional resources Quadlet upstream documentation 14.5. Generating a systemd unit file using Podman Podman allows systemd to control and manage container processes. You can generate a systemd unit file for the existing containers and pods using podman generate systemd command. It is recommended to use podman generate systemd because the generated units files change frequently (via updates to Podman) and the podman generate systemd ensures that you get the latest version of unit files. Note Starting with Podman v4.6, you can use the Quadlets that describe how to run a container in a format similar to regular systemd unit files and hides the complexity of running containers under systemd . Prerequisites The container-tools meta-package is installed. Procedure Create a container (for example myubi ): Use the container name or ID to generate the systemd unit file and direct it into the ~/.config/systemd/user/container-myubi.service file: Verification Display the content of generated systemd unit file: The Restart=on-failure line sets the restart policy and instructs systemd to restart when the service cannot be started or stopped cleanly, or when the process exits non-zero. The ExecStart line describes how we start the container. The ExecStop line describes how we stop and remove the container. Additional resources Running containers with Podman and shareable systemd services 14.6. Automatically generating a systemd unit file using Podman By default, Podman generates a unit file for existing containers or pods. You can generate more portable systemd unit files using the podman generate systemd --new . The --new flag instructs Podman to generate unit files that create, start and remove containers. Note Starting with Podman v4.6, you can use the Quadlets that describe how to run a container in a format similar to regular systemd unit files and hides the complexity of running containers under systemd . Prerequisites The container-tools meta-package is installed. Procedure Pull the image you want to use on your system. For example, to pull the httpd-24 image: Optional: List all images available on your system: Create the httpd container: Optional: Verify the container has been created: Generate a systemd unit file for the httpd container: Display the content of the generated container-httpd.service systemd unit file: Note Unit files generated using the --new option do not expect containers and pods to exist. Therefore, they perform the podman run command when starting the service (see the ExecStart line) instead of the podman start command. For example, see section Generating a systemd unit file using Podman . The podman run command uses the following command-line options: The --conmon-pidfile option points to a path to store the process ID for the conmon process running on the host. The conmon process terminates with the same exit status as the container, which allows systemd to report the correct service status and restart the container if needed. The --cidfile option points to the path that stores the container ID. The %t is the path to the run time directory root, for example /run/user/USDUserID . The %n is the full name of the service. Copy unit files to /etc/systemd/system for installing them as a root user: Enable and start the container-httpd.service : Verification Check the status of the container-httpd.service : Additional resources Improved Systemd Integration with Podman 2.0 Enabling a system service to start at boot 14.7. Automatically starting pods using systemd You can start multiple containers as systemd services. Note that the systemctl command should only be used on the pod and you should not start or stop containers individually via systemctl , as they are managed by the pod service along with the internal infra-container. Note Starting with Podman v4.6, you can use the Quadlets that describe how to run a container in a format similar to regular systemd unit files and hides the complexity of running containers under systemd . Prerequisites The container-tools meta-package is installed. Procedure Create an empty pod, for example named systemd-pod : Optional: List all pods: Create two containers in the empty pod. For example, to create container0 and container1 in systemd-pod : Optional: List all pods and containers associated with them: Generate the systemd unit file for the new pod: Note that three systemd unit files are generated, one for the systemd-pod pod and two for the containers container0 and container1 . Display pod-systemd-pod.service unit file: The Requires line in the [Unit] section defines dependencies on container-container0.service and container-container1.service unit files. Both unit files will be activated. The ExecStart and ExecStop lines in the [Service] section start and stop the infra-container, respectively. Display container-container0.service unit file: The BindsTo line line in the [Unit] section defines the dependency on the pod-systemd-pod.service unit file The ExecStart and ExecStop lines in the [Service] section start and stop the container0 respectively. Display container-container1.service unit file: Copy all the generated files to USDHOME/.config/systemd/user for installing as a non-root user: Enable the service and start at user login: Note that the service stops at user logout. Verification Check if the service is enabled: Additional resources podman-create , podman-generate-systemd , and systemctl man pages on your system Running containers with Podman and shareable systemd services Enabling a system service to start at boot 14.8. Automatically updating containers using Podman The podman auto-update command allows you to automatically update containers according to their auto-update policy. The podman auto-update command updates services when the container image is updated on the registry. To use auto-updates, containers must be created with the --label "io.containers.autoupdate=image" label and run in a systemd unit generated by podman generate systemd --new command. Podman searches for running containers with the "io.containers.autoupdate" label set to "image" and communicates to the container registry. If the image has changed, Podman restarts the corresponding systemd unit to stop the old container and create a new one with the new image. As a result, the container, its environment, and all dependencies, are restarted. Note Starting with Podman v4.6, you can use the Quadlets that describe how to run a container in a format similar to regular systemd unit files and hides the complexity of running containers under systemd . Prerequisites The container-tools meta-package is installed. Procedure Start a myubi container based on the registry.access.redhat.com/ubi9/ubi-init image: Optional: List containers that are running or have exited: Generate a systemd unit file for the myubi container: Copy unit files to /usr/lib/systemd/system for installing it as a root user: Reload systemd manager configuration: Start and check the status of a container: Auto-update the container: Additional resources Improved Systemd Integration with Podman 2.0 Running containers with Podman and shareable systemd services Enabling a system service to start at boot 14.9. Automatically updating containers using systemd As mentioned in section Automatically updating containers using Podman , you can update the container using the podman auto-update command. It integrates into custom scripts and can be invoked when needed. Another way to auto update the containers is to use the pre-installed podman-auto-update.timer and podman-auto-update.service systemd service. The podman-auto-update.timer can be configured to trigger auto updates at a specific date or time. The podman-auto-update.service can further be started by the systemctl command or be used as a dependency by other systemd services. As a result, auto updates based on time and events can be triggered in various ways to meet individual needs and use cases. Note Starting with Podman v4.6, you can use the Quadlets that describe how to run a container in a format similar to regular systemd unit files and hides the complexity of running containers under systemd . Prerequisites The container-tools meta-package is installed. Procedure Display the podman-auto-update.service unit file: Display the podman-auto-update.timer unit file: In this example, the podman auto-update command is launched daily at midnight. Enable the podman-auto-update.timer service at system start: Start the systemd service: Optional: List all timers: You can see that podman-auto-update.timer activates the podman-auto-update.service . Additional resources Improved Systemd Integration with Podman 2.0 Running containers with Podman and shareable systemd services Enabling a system service to start at boot

Commands:
cat USDHOME/.config/containers/systemd/mysleep.container [Unit] Description=The sleep container After=local-fs.target [Container] Image=registry.access.redhat.com/ubi9-minimal:latest Exec=sleep 1000 Start by default on boot WantedBy=multi-user.target default.target
systemctl --user daemon-reload
systemctl --user status mysleep.service ○ mysleep.service - The sleep container Loaded: loaded (/home/ username /.config/containers/systemd/mysleep.container; generated) Active: inactive (dead)
systemctl --user start mysleep.service
systemctl --user status mysleep.service ● mysleep.service - The sleep container Loaded: loaded (/home/ username /.config/containers/systemd/mysleep.container; generated) Active: active (running) since Thu 2023-02-09 18:07:23 EST; 2s ago Main PID: 265651 (conmon) Tasks: 3 (limit: 76815) Memory: 1.6M CPU: 94ms CGroup:
podman ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 421c8293fc1b registry.access.redhat.com/ubi9-minimal:latest sleep 1000 30 seconds ago Up 10 seconds ago systemd-mysleep
systemctl enable <service>
systemctl --user enable <service>
loginctl enable-linger <username>
systemctl --user daemon-reload
systemctl --user enable container.service
systemctl --user start container.service
systemctl --user status container.service ● container.service - Podman container.service Loaded: loaded (/home/user/.config/systemd/user/container.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-09-16 11:56:57 CEST; 8s ago Docs: man:podman-generate-systemd(1) Process: 80602 ExecStart=/usr/bin/podman run --conmon-pidfile //run/user/1000/container.service-pid --cidfile //run/user/1000/container.service-cid -d ubi9-minimal:> Process: 80601 ExecStartPre=/usr/bin/rm -f //run/user/1000/container.service-pid //run/user/1000/container.service-cid (code=exited, status=0/SUCCESS) Main PID: 80617 (conmon) CGroup: /user.slice/user-1000.slice/user@1000.service/container.service ├─ 2870 /usr/bin/podman ├─80612 /usr/bin/slirp4netns --disable-host-loopback --mtu 65520 --enable-sandbox --enable-seccomp -c -e 3 -r 4 --netns-type=path /run/user/1000/netns/cni-> ├─80614 /usr/bin/fuse-overlayfs -o lowerdir=/home/user/.local/share/containers/storage/overlay/l/YJSPGXM2OCDZPLMLXJOW3NRF6Q:/home/user/.local/share/contain> ├─80617 /usr/bin/conmon --api-version 1 -c cbc75d6031508dfd3d78a74a03e4ace1732b51223e72a2ce4aa3bfe10a78e4fa -u cbc75d6031508dfd3d78a74a03e4ace1732b51223e72> └─cbc75d6031508dfd3d78a74a03e4ace1732b51223e72a2ce4aa3bfe10a78e4fa └─80626 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1d
podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f20988d59920 registry.access.redhat.com/ubi9-minimal:latest top 12 seconds ago Up 11 seconds ago funny_zhukovsky
systemctl --user stop container.service
podman create --name myubi registry.access.redhat.com/ubi9:latest sleep infinity 0280afe98bb75a5c5e713b28de4b7c5cb49f156f1cce4a208f13fee2f75cb453
podman generate systemd --name myubi > ~/.config/systemd/user/container-myubi.service
cat ~/.config/systemd/user/container-myubi.service container-myubi.service autogenerated by Podman 3.3.1 Wed Sep 8 20:34:46 CEST 2021 [Unit] Description=Podman container-myubi.service Documentation=man:podman-generate-systemd(1) Wants=network-online.target After=network-online.target RequiresMountsFor=/run/user/1000/containers [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure TimeoutStopSec=70 ExecStart=/usr/bin/podman start myubi ExecStop=/usr/bin/podman stop -t 10 myubi ExecStopPost=/usr/bin/podman stop -t 10 myubi PIDFile=/run/user/1000/containers/overlay-containers/9683103f58a32192c84801f0be93446cb33c1ee7d9cdda225b78049d7c5deea4/userdata/conmon.pid Type=forking [Install] WantedBy=multi-user.target default.target
podman pull registry.access.redhat.com/ubi9/httpd-24
podman images REPOSITORY TAG IMAGE ID CREATED SIZE registry.access.redhat.com/ubi9/httpd-24 latest 8594be0a0b57 2 weeks ago 462 MB
podman create --name httpd -p 8080:8080 registry.access.redhat.com/ubi9/httpd-24 cdb9f981cf143021b1679599d860026b13a77187f75e46cc0eac85293710a4b1
podman ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cdb9f981cf14 registry.access.redhat.com/ubi9/httpd-24:latest /usr/bin/run-http... 5 minutes ago Created 0.0.0.0:8080->8080/tcp httpd
podman generate systemd --new --files --name httpd /root/container-httpd.service
cat /root/container-httpd.service container-httpd.service autogenerated by Podman 3.3.1 Wed Sep 8 20:41:44 CEST 2021 [Unit] Description=Podman container-httpd.service Documentation=man:podman-generate-systemd(1) Wants=network-online.target After=network-online.target RequiresMountsFor=%t/containers [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/%n.ctr-id ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --sdnotify=conmon --cgroups=no-conmon --rm -d --replace --name httpd -p 8080:8080 registry.access.redhat.com/ubi9/httpd-24 ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id Type=notify NotifyAccess=all [Install] WantedBy=multi-user.target default.target
cp -Z container-httpd.service /etc/systemd/system
systemctl daemon-reload systemctl enable --now container-httpd.service Created symlink /etc/systemd/system/multi-user.target.wants/container-httpd.service /etc/systemd/system/container-httpd.service. Created symlink /etc/systemd/system/default.target.wants/container-httpd.service /etc/systemd/system/container-httpd.service.
systemctl status container-httpd.service ● container-httpd.service - Podman container-httpd.service Loaded: loaded (/etc/systemd/system/container-httpd.service; enabled; vendor preset: disabled) Active: active (running) since Tue 2021-08-24 09:53:40 EDT; 1min 5s ago Docs: man:podman-generate-systemd(1) Process: 493317 ExecStart=/usr/bin/podman run --conmon-pidfile /run/container-httpd.pid --cidfile /run/container-httpd.ctr-id --cgroups=no-conmon -d --repla> Process: 493315 ExecStartPre=/bin/rm -f /run/container-httpd.pid /run/container-httpd.ctr-id (code=exited, status=0/SUCCESS) Main PID: 493435 (conmon)
podman pod create --name systemd-pod 11d4646ba41b1fffa51c108cbdf97cfab3213f7bd9b3e1ca52fe81b90fed5577
podman pod ps POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID 11d4646ba41b systemd-pod Created 40 seconds ago 1 8a428b257111 11d4646ba41b1fffa51c108cbdf97cfab3213f7bd9b3e1ca52fe81b90fed5577
podman create --pod systemd-pod --name container0 registry.access.redhat.com/ubi 9 top podman create --pod systemd-pod --name container1 registry.access.redhat.com/ubi 9 top
podman ps -a --pod CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME 24666f47d9b2 registry.access.redhat.com/ubi9:latest top 3 minutes ago Created container0 3130f724e229 systemd-pod 56eb1bf0cdfe k8s.gcr.io/pause:3.2 4 minutes ago Created 3130f724e229-infra 3130f724e229 systemd-pod 62118d170e43 registry.access.redhat.com/ubi9:latest top 3 seconds ago Created container1 3130f724e229 systemd-pod
podman generate systemd --files --name systemd-pod /home/user1/pod-systemd-pod.service /home/user1/container-container0.service /home/user1/container-container1.service
cat pod-systemd-pod.service pod-systemd-pod.service autogenerated by Podman 3.3.1 Wed Sep 8 20:49:17 CEST 2021 [Unit] Description=Podman pod-systemd-pod.service Documentation=man:podman-generate-systemd(1) Wants=network-online.target After=network-online.target RequiresMountsFor= Requires=container-container0.service container-container1.service Before=container-container0.service container-container1.service [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure TimeoutStopSec=70 ExecStart=/usr/bin/podman start bcb128965b8e-infra ExecStop=/usr/bin/podman stop -t 10 bcb128965b8e-infra ExecStopPost=/usr/bin/podman stop -t 10 bcb128965b8e-infra PIDFile=/run/user/1000/containers/overlay-containers/1dfdcf20e35043939ea3f80f002c65c00d560e47223685dbc3230e26fe001b29/userdata/conmon.pid Type=forking [Install] WantedBy=multi-user.target default.target
cat container-container0.service container-container0.service autogenerated by Podman 3.3.1 Wed Sep 8 20:49:17 CEST 2021 [Unit] Description=Podman container-container0.service Documentation=man:podman-generate-systemd(1) Wants=network-online.target After=network-online.target RequiresMountsFor=/run/user/1000/containers BindsTo=pod-systemd-pod.service After=pod-systemd-pod.service [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure TimeoutStopSec=70 ExecStart=/usr/bin/podman start container0 ExecStop=/usr/bin/podman stop -t 10 container0 ExecStopPost=/usr/bin/podman stop -t 10 container0 PIDFile=/run/user/1000/containers/overlay-containers/4bccd7c8616ae5909b05317df4066fa90a64a067375af5996fdef9152f6d51f5/userdata/conmon.pid Type=forking [Install] WantedBy=multi-user.target default.target
cat container-container1.service
cp pod-systemd-pod.service container-container0.service container-container1.service USDHOME/.config/systemd/user
systemctl enable --user pod-systemd-pod.service Created symlink /home/user1/.config/systemd/user/multi-user.target.wants/pod-systemd-pod.service /home/user1/.config/systemd/user/pod-systemd-pod.service. Created symlink /home/user1/.config/systemd/user/default.target.wants/pod-systemd-pod.service /home/user1/.config/systemd/user/pod-systemd-pod.service.
systemctl is-enabled pod-systemd-pod.service enabled
podman run --label "io.containers.autoupdate=image" --name myubi -dt registry.access.redhat.com/ubi9/ubi-init top bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d
podman ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 76465a5e2933 registry.access.redhat.com/9/ubi-init:latest top 24 seconds ago Up 23 seconds ago myubi
podman generate systemd --new --files --name myubi /root/container-myubi.service
cp -Z ~/container-myubi.service /usr/lib/systemd/system
systemctl daemon-reload
systemctl start container-myubi.service systemctl status container-myubi.service
podman auto-update
cat /usr/lib/systemd/system/podman-auto-update.service [Unit] Description=Podman auto-update service Documentation=man:podman-auto-update(1) Wants=network.target After=network-online.target [Service] Type=oneshot ExecStart=/usr/bin/podman auto-update [Install] WantedBy=multi-user.target default.target
cat /usr/lib/systemd/system/podman-auto-update.timer [Unit] Description=Podman auto-update timer [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target
systemctl enable podman-auto-update.timer
systemctl start podman-auto-update.timer
systemctl list-timers --all NEXT LEFT LAST PASSED UNIT ACTIVATES Wed 2020-12-09 00:00:00 CET 9h left n/a n/a podman-auto-update.timer podman-auto-update.service