Skip to content

Running containers from systemd

When you embed a container in an operating system (OS) image, you can start the container manually in the booted system with the podman run command. However, the container does not start automatically at boot time. To configure a container to start at boot time, you must create a systemd service that starts the container at the right time, in the right way.

Quadlet is a tool that optimally runs Podman containers under systemd. Rather than creating the systemd service manually, use Quadlet to automatically generate the corresponding systemd service unit file at boot time. Quadlet simplifies container management by allowing you to create declarative configurations in .container files instead of lengthy, complex systemd unit files.

Quadlet unit files configure containers in both the root and QM partitions. In the AutoSD OS filesystem, store your .container files in /etc/containers/systemd.

At a minimum, include the following sections and options in a .container file:

[Unit]
Description=<A human-readable title>

[Container]
Image=<The container image>
Exec=<The command that runs in the container>

[Install]
WantedBy=multi-user.target default.target

Include additional sections and options to meet your container requirements. Any section or option permitted in a systemd.unit file is also permitted in a Quadlet unit file.

Containers within containers

The QM partition is a container within the root partition of an AutoSD OS image. The QM partition houses containers that run non-critical application workloads.

To add containers to the QM partition, you create Quadlet unit files and add them to the add_files section of your Automotive Image Builder manifest, for example:

Quadlet unit file added to an Automotive Image Builder manifest
            - sshd.service
            # Enable UDS socket for server-client communication
    ...
            tag: latest
            name: "localhost/ipc_client"
            containers-transport: containers-storage

The example shows an ipc_client.container unit file added to the add_files section of the qm partition. The path section is the location for all container files, /etc/containers/systemd.

You can also create Quadlet unit files directly in the manifest, for example:

Quadlet unit file created in the Automotive Image Builder manifest
    qm:
    ...
      content:
    ...
        add_files:
          - path: /etc/containers/systemd/nginx.container
            text: |
              [Container]
              Image=localhost/nginx
              PublishPort=8080:80

              [Install]
              WantedBy=multi-user.target

The example shows an nginx container image created directly from the manifest. The text section contains the contents of the .container file.

Configuring communication between QM containers demonstrates additional Quadlet unit file use cases.

Creating Quadlet files for sample applications

In this example, create Quadlet files for the sample applications that are available in the AutoSD sample-apps repository. If you want to use your own containerized software, see the Podman documentation for more information about creating your own Quadlet configuration files.

Prerequisites

Procedure

  1. Create a systemd socket unit and Quadlet unit files for the radio-service and engine-service services in your sample application auto-apps:

    engine.container file
    [Unit]
    Description=Demo engine service container
    # routingmanagerd.socket is not included in vsomeip3 3.5.11, so let's use routingmanagerd.service for now
    Requires=routingmanagerd.service
    After=routingmanagerd.service
    
    [Container]
    Image=localhost/auto-apps
    Exec=/usr/bin/engine-service
    Volume=/run/vsomeip:/run/vsomeip
    Volume=/run/root-ipc-demo:/run/root-ipc-demo
    
    [Service]
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    
    radio.socket file
    [Unit]
    Description=example systemd unix socket
    
    [Socket]
    ListenStream=%t/root-ipc-demo/root_ipc.socket
    RuntimeDirectory=root-ipc-demo
    
    [Install]
    WantedBy=sockets.target
    
    radio.container file
    [Unit]
    Description=Demo radio service container
    # routingmanagerd.socket is not included in vsomeip3 3.5.11, so let's use routingmanagerd.service for now
    Requires=routingmanagerd.service
    After=routingmanagerd.service
    Requires=radio.socket
    After=radio.socket
    Wants=engine.service
    
    [Container]
    Image=localhost/auto-apps
    Exec=/usr/bin/radio-service
    Volume=/run/vsomeip:/run/vsomeip
    Volume=/run/root-ipc-demo:/run/root-ipc-demo
    
    [Service]
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    

Note

Requires=radio.socket is a hard dependency that prevents the radio service from starting until the socket unit is active. After=radio.socket is an ordering dependency: the radio service starts only after the socket unit has started. Requires=routingmanagerd.service is a hard dependency that prevents the radio service from starting until the routing manager service is active. Wants=engine.service is a soft dependency. Ideally, the engine service activates the radio service, but if the engine service is not activated, systemd still permits the radio service to start.

  1. Create an Automotive Image Builder manifest named root-root.aib.yml that contains the following code, which copies the Quadlet unit files to the /etc/containers/systemd/ directory during the OS image build process:

    Manifest configuration to copy Quadlet unit files
    # root-root IPC communications demo
    
    name: root-root-IPC-communications
    
    content:
      repos:
        - id: epel
          metalink: https://mirrors.fedoraproject.org/metalink?repo=epel-10&arch=$arch
    
      rpms:
        - podman
        - netavark
        - aardvark-dns
        - vsomeip3-routingmanager
        - dlt-daemon
        # For testing the image only:
        - openssh-server
        - openssh-clients
    
      container_images:
        # Get the auto-apps container image from gitlab
        - source: registry.gitlab.com/centos/automotive/sample-images/demo/auto-apps
          tag: latest
          name: localhost/auto-apps
    
      add_files:
        - path: /etc/containers/systemd/radio.container
          source_path: ./radio.container
        - path: /etc/containers/systemd/engine.container
          source_path: ./engine.container
        - path: /etc/systemd/system/radio.socket
          source_path: ./radio.socket
    
      # Required for testing the image only:
      systemd:
        enabled_services:
          # Enable ssh daemon
          - sshd.service
          # Enable the dlt daemon
          - dlt
          # Enable the IPC socket
          - radio.socket
    
    auth:
      # "password"
      root_password: $6$xoLqEUz0cGGJRx01$H3H/bFm0myJPULNMtbSsOFd/2BnHqHkMD92Sfxd.EKM9hXTWSmELG8cf205l6dktomuTcgKGGtGDgtvHVXSWU.
      # Required for testing the image only:
      sshd_config:
        PasswordAuthentication: true
        PermitRootLogin: true
    

    Note

    The source_path: option resolves a relative path. In this example, the Quadlet unit files are in the same directory as the manifest.

  2. Run aib-dev build to build a disk image:

    $ aib-dev \
        --include=/var/lib/containers/storage/ \
        build \
        --distro autosd10 \
        --target qemu \
        --build-dir=_build \
        root-root.aib.yml \
        root-root.$arch.qcow2
    
  3. Verify that the script has created an AutoSD image file named root-root.<arch>.qcow2 in your present working directory.

  4. Assuming that you have installed QEMU, boot the AutoSD image in a virtual machine, substituting the name of your .qcow2 image file (if necessary):

    $ air --nographics root-root.x86_64.qcow2
    
  5. After the image boots in QEMU, log in with the user name root and the password password.

Additional resources


© Red Hat