Run rootless Podman containers as  systemd services

Power Up

Defining a First Container

After all this preparation, you can now define your first systemd unit file for a container. As an example, set up FreshRSS [7], a self-hosted RSS feed aggregator (Figure 2). To have this service start automatically in a Podman container, define the systemd unit shown in Listing 1 in the file ~/.config/containers/systemd/freshrss.container.

Figure 2: FreshRSS is a self-hosted RSS and Atom feed aggregator, which runs perfectly in a rootless Podman container.

Listing 1

freshrss.container

01 [Unit]
02 Description=FreshRSS feed aggregator
03
04 [Container]
05 Image=docker.io/freshrss/freshrss:1.25.0
06 ContainerName=freshrss
07 HostName=freshrss
08 Volume=%h/containers/freshrss/data:/var/www/FreshRSS/data:Z
09 Volume=%h/containers/freshrss/extensions:/var/www/FreshRSS/extensions:Z
10 Environment=TZ=Europe/Brussels
11 Environment=CRON_MIN=1,31
12 PublishPort=80:80
13
14 [Service]
15 Restart=always
16
17 [Install]
18 WantedBy=default.target

If you are familiar with systemd unit files for services, you'll notice a new section: [Container]. The file name also uses the .container extension instead of .service to indicate that it's a container unit.

The [Container] section has various options for your container, documented extensively in the Podman Quadlet [4] man page. In this example, I define the container image, name, hostname, volumes, environment variables, and ports you want to publish.

The Volume statement in line 8 indicates that the directory containers/freshrss/data in the host's home directory (%h) of the user is mounted at /var/www/FreshRSS/data within the container. On an SELinux-enabled system, the Z option specifies that this directory is used only by this container, ensuring it receives the proper labeling. If the directory is shared with other containers, use the lowercase z option instead, and use ro for a read-only mount within the container.

Under the user's home directory, create these directories on your host system:

$ mkdir -p ~/containers/freshrss/{data,extensions}

I typically create a ~/containers directory within the user's home directory with a subdirectory for each rootless container. If you prefer a different setup, adjust the volumes in the container unit file accordingly.

Next, the [Container] section of the unit file has a line for each environment variable and then a line to publish the container's port (line 12). In this case, container port 80 (defined after the colon) from the container is exposed to port 80 on the host (defined before the colon).

The [Service] and [Install] sections of the unit file are familiar from service unit files. The [Install] section in particular is important: The WantedBy=default.target option ensures the container starts on boot.

Starting the Service

After saving the container file in Listing 1 and creating the directories for the container's volumes, you need to inform systemd of the new unit file for the user:

$ systemctl --user daemon-reload

This command generates a service for the container in the background, with the same name as your .container unit file but with the .service extension. You can view its content with:

$ systemctl --user cat freshrss.service

You'll see, for instance, that the service unit file contains an extensive [Service] section with the ExecStart option consisting of a podman run command that starts the container with various options like volumes, environment variables, and so on.

You can now also start the container by starting this generated service:

$ systemctl --user start freshrss.service

The startup might take some time if the container image needs to be downloaded first.

If all goes well, the FreshRSS web interface is available on port 80 of your container host. If not, consult the logfiles with journalctl or take a look at the output of:

systemctl --user status freshrss.service

Always remember to use the --user flag in your systemctl commands; because you're working with rootless containers, the corresponding systemd services are running with user privileges.

Creating a Podman Network

You can similarly define unit files for volumes, networks, pods, and more. As an example, I'll define a Podman network in a systemd unit file. Instead of letting all your containers publish their ports directly on the host, connect them all to a Podman network and then run a container with a reverse proxy to access all those containers externally.

Define a .config/containers/systemd/reverse-proxy.network file in your home directory with the content:

[Unit]
Description=Reverse proxy network
[Network]
NetworkName=reverse-proxy

Additional options are documented in the aforementioned Podman Quadlet man page. Now change the unit file of your FreshRSS container to include the following line in the [Container] section to use this network:

Network=reverse-proxy.network

Remove the PublishPort line because the container's port shouldn't be exposed on the host anymore: That will be the reverse proxy's task.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus