Chapter 8. Porting containers to systemd using Podman

Podman (Pod Manager) is a fully featured container engine that is a simple daemonless tool. Podman provides a Docker-CLI comparable command line that eases the transition from other container engines and allows the management of pods, containers and images. It was not originally designed to bring up an entire Linux system or manage services for such things as start-up order, dependency checking, and failed service recovery. That is the job of a full-blown initialization system like systemd. Red Hat has become a leader in integrating containers with systemd, so that OCI and Docker-formatted containers built by Podman can be managed in the same way that other services and features are managed in a Linux system. You can use the systemd initialization service to work with pods and containers. You can use the podman generate systemd command to generate a systemd unit file for containers and pods.

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.

This chapter provides you with information on how to generate portable descriptions of containers and pods using systemd unit files.

8.1. 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:

      # systemctl enable <service>

      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:

      $ systemctl --user enable <service>

      You have to copy the systemd unit files to the $HOME/.config/systemd/user directory.

    • To enable users to start a service at system start and persist over logouts, enter:

      # loginctl enable-linger <username>

Additional resources

  • For more information on the systemctl and loginctl commands, enter man systemctl or man loginctl, respectively.
  • To learn more about configuring services with systemd, refer to the Configuring basic system settings guide chapter called Managing services with systemd.

8.2. 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.

Procedure

  1. Create a container (for example myubi):

    $ podman create -d --name myubi registry.access.redhat.com/ubi8:latest top
    0280afe98bb75a5c5e713b28de4b7c5cb49f156f1cce4a208f13fee2f75cb453
  2. Use the container name or ID to generate the systemd unit file and direct it into the ~/.config/systemd/user/container-myubi.service file:

    $ podman generate systemd --name myubi > ~/.config/systemd/user/container-myubi.service

Verification steps

  • To display the content of generated systemd unit file, enter:

    $ cat ~/.config/systemd/user/container-myubi.service
    # container-myubi.service
    # autogenerated by Podman 2.0.0
    # Tue Aug 11 10:51:04 CEST 2020
    
    [Unit]
    Description=Podman container-myubi.service
    Documentation=man:podman-generate-systemd(1)
    Wants=network.target
    After=network-online.target
    
    [Service]
    Environment=PODMAN_SYSTEMD_UNIT=%n
    Restart=on-failure
    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/0280afe98bb75a5c5e713b28de4b7c5cb49f156f1cce4a208f13fee2f75cb453/userdata/conmon.pid
    KillMode=none
    Type=forking
    
    [Install]
    WantedBy=multi-user.target default.target
    • 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

8.3. Auto-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.

Procedure

  1. Pull the image you want to use on your system. For example, to pull the busybox image:

    # podman pull busybox:latest
  2. List all images available on your system:

    # podman images
    REPOSITORY                 TAG     IMAGE ID      CREATED      SIZE
    docker.io/library/busybox  latest  c7c37e472d31  3 weeks ago  1.45 MB
  3. Create the busybox container:

    # podman create --name busybox busybox:latest
    1e12cf95e305435c0001fa7d4a14cf1d52f737c1118328937028c0bd2fdec5ca
  4. To verify the container has been created, list all containers:

    # podman ps -a
    CONTAINER ID  IMAGE                             COMMAND  CREATED        STATUS   PORTS   NAMES
    1e12cf95e305  docker.io/library/busybox:latest  sh       7 seconds ago  Created          busybox
  5. Generate a systemd unit file for the busybox container:

    # podman generate systemd --new --files --name busybox
    /root/container-busybox.service
  6. Display the content of the generated container-busybox.service systemd unit file:

    # vim container-busybox.services
    
    # container-busybox.service
    # autogenerated by Podman 2.0.0-rc7
    # Mon Jul 27 11:06:32 CEST 2020
    
    [Unit]
    Description=Podman container-busybox.service
    Documentation=man:podman-generate-systemd(1)
    Wants=network.target
    After=network-online.target
    
    [Service]
    Environment=PODMAN_SYSTEMD_UNIT=%n
    Restart=on-failure
    ExecStartPre=/usr/bin/rm -f %t/container-busybox.pid %t/container-busybox.ctr-id
    ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-busybox.pid --cidfile %t/container-busybox.ctr-id --cgroups=no-conmon -d --replace --name busybox busybox:latest
    ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-busybox.ctr-id -t 10
    ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-busybox.ctr-id
    PIDFile=%t/container-busybox.pid
    KillMode=none
    Type=forking
    
    [Install]
    WantedBy=multi-user.target default.target

    Note that 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 7.2. 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/$UserID.
      • The %n is the full name of the service.
  7. Copy unit files to /usr/lib/systemd/system for installing them as a root user:

    # cp -Z container-busybox.service  /usr/lib/systemd/system
    Created symlink /etc/systemd/system/multi-user.target.wants/container-busybox.service /usr/lib/systemd/system/container-busybox.service.
    Created symlink /etc/systemd/system/default.target.wants/container-busybox.service → /usr/lib/systemd/system/container-busybox.service.

Additional resources

8.4. Auto-starting containers using systemd

You can control the state of the systemd system and service manager using the systemctl command. This section shows the general procedure on how to enable, start, stop the service as a non-root user. To install the service as a root user, omit the --user option.

Procedure

  1. Reload systemd manager configuration:

    # systemctl --user daemon-reload
  2. Enable the service container.service and start it at boot time:

    # systemctl --user enable container.service
  3. To start the service immediately:

    # systemctl --user start container.service
  4. Check the status of the 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 ubi8-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

    You can check if the service is enabled using the systemctl is-enabled container.service command.

Verification steps

  • List containers that are running or have exited:

    # podman ps
    CONTAINER ID  IMAGE                            COMMAND  CREATED         STATUS             PORTS  NAMES
    f20988d59920  registry.access.redhat.com/ubi8-minimal:latest  top      12 seconds ago  Up 11 seconds ago         funny_zhukovsky
Note

To stop container.service, enter:

# systemctl --user stop container.service

Additional resources

8.5. Auto-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.

Procedure

  1. Create an empty pod, for example named systemd-pod:

    $ podman pod create --name systemd-pod
    11d4646ba41b1fffa51c108cbdf97cfab3213f7bd9b3e1ca52fe81b90fed5577
  2. List all pods:

    $ podman pod ps
    POD ID        NAME         STATUS   CREATED         # OF CONTAINERS  INFRA ID
    11d4646ba41b  systemd-pod  Created  40 seconds ago  1                8a428b257111
    11d4646ba41b1fffa51c108cbdf97cfab3213f7bd9b3e1ca52fe81b90fed5577
  3. Create two containers in the empty pod. For example, to create container0 and container1 in systemd-pod:

    $ podman create --pod systemd-pod --name container0 registry.access.redhat.com/ubi8 top
    $ podman create --pod systemd-pod --name container1 registry.access.redhat.com/ubi8 top
  4. List all pods and containers associated with them:

    $ podman ps -a --pod
    CONTAINER ID  IMAGE                                   COMMAND  CREATED        STATUS         PORTS   NAMES               POD ID        PODNAME
    24666f47d9b2  registry.access.redhat.com/ubi8: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/ubi8:latest  top      3 seconds ago  Created                container1          3130f724e229  systemd-pod
  5. Generate the systemd unit file for the new pod:

    $ podman generate systemd --files --name systemd-pod
    /home/user1/pod-systemd-pod.service
    /home/user1/container-container0.service
    /home/user1/container-container1.service

    Note that three systemd unit files are generated, one for the systemd-pod pod and two for the containers container0 and container1.

  6. Display pod-systemd-pod.service unit file:

    $ cat pod-systemd-pod.service
    # pod-systemd-pod.service
    # autogenerated by Podman 2.0.3
    # Tue Jul 28 14:00:46 EDT 2020
    
    
    [Unit]
    Description=Podman pod-systemd-pod.service
    Documentation=man:podman-generate-systemd(1)
    Wants=network.target
    After=network-online.target
    Requires=container-container0.service container-container1.service
    Before=container-container0.service container-container1.service
    
    [Service]
    Environment=PODMAN_SYSTEMD_UNIT=%n
    Restart=on-failure
    ExecStart=/usr/bin/podman start c852fbaba568-infra
    ExecStop=/usr/bin/podman stop -t 10 c852fbaba568-infra
    ExecStopPost=/usr/bin/podman stop -t 10 c852fbaba568-infra
    PIDFile=/run/user/1000/containers/overlay-containers/a7ff86382608add27a03ac2166d5d0164199f01eadf80b68b06a406c195105fc/userdata/conmon.pid
    KillMode=none
    Type=forking
    
    [Install]
    WantedBy=multi-user.target default.target
    • 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.
  7. Display container-container0.service unit file:

    $ cat container-container0.service
    # container-container0.service
    # autogenerated by Podman 2.0.3
    # Tue Jul 28 14:00:46 EDT 2020
    
    [Unit]
    Description=Podman container-container0.service
    Documentation=man:podman-generate-systemd(1)
    Wants=network.target
    After=network-online.target
    BindsTo=pod-systemd-pod.service
    After=pod-systemd-pod.service
    
    [Service]
    Environment=PODMAN_SYSTEMD_UNIT=%n
    Restart=on-failure
    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/12e85378f2854b8283f791974494a02aa6c92630d76d1050237839b61508a008/userdata/conmon.pid
    KillMode=none
    Type=forking
    
    [Install]
    WantedBy=multi-user.target default.target
    • 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.
  8. Display container-container1.service unit file:

    $ cat container-container1.service
  9. Copy all the generated files to $HOME/.config/systemd/user for installing as a non-root user:

    $ cp pod-systemd-pod.service container-container0.service container-container1.service $HOME/.config/systemd/user
  10. Enable the service and start at user login:

    $ 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.

    Note that the service stops at user logout.

Verification steps

  • Check if the service is enabled:

    $ systemctl is-enabled pod-systemd-pod.service
    enabled

Additional resources

  • For more information on the podman create command, type man podman-create.
  • For more information on the podman generate systemd command, type man podman-generate-systemd.
  • For more information on the systemctl command, type man systemctl.
  • For more information, see the Running containers with Podman and shareable systemd services article by Valentin Rothberg.
  • To learn more about configuring services with systemd, refer to the Configuring basic system settings guide chapter called Managing services with systemd.