Managing Containers with Podman Quadlet

SystemD Podman — Published on .

If you’ve read my blog posts before, you may know that I personally don’t like systemd all that much. In my experience, it breaks many things that used to work just fine from a user perspective, while adding not much new. Recently however, I looked into managing containers with it. I found out about Podman Quadlet, and it feels like a first neat way to use systemd to solve a problem.

As far as I’m aware, this is something that only works with Podman, not with Docker. This shouldn’t be an issue for most, since you should be using Podman over Docker anyway.

What does it solve

Sometimes, you just want to run a container for a service. Many projects even offer a docker-compose.yml in their repositories to get you started with a containerized setup. Such a setup doesn’t survive through reboots without some trickery. Quadlet lets you interact with running containers as if they were systemd services, which means they can have dependencies and get restarted automatically on errors or reboots. To me personally, it also feels a lot cleaner than a big docker-compose.yml file.

Since systemd has a --user mode as well, you can use this to run rootless containers as your own user, which start automatically as you log in. As I’m trying out Silverbullet, this has come in handy to always have an instance of it running.

How to use it

If you have an up-to-date Podman, you need to write some special systemd unit-like files. For system-wide setups, you’ll want to place them in /etc/containers/systemd/, whereas for user-specific containers you want to place them in $XDG_CONFIG_HOME/containers/systemd. You can read the full spec for the unit files in the podman-systemd.unit manual page. I will include only a simple unit file into this blog post to give you a real-world example.

[Unit]
Description=An open source personal productivity platform

[Container]
Image=ghcr.io/silverbulletmd/silverbullet:v2
Volume=%h/documents/space:/space
PublishPort=3000:3000

[Service]
Restart=always

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

As you can see, it is very similar to a regular systemd service unit, but it comes with an additional [Container] heading. All the command-line options for podman-run seem to be available, giving you a lot of customization access when needed, but for most images it could be as simple as this. An Image to denote the container to run, a Volume to give it access to some data, and a PublishPort to make it accessible.

If this is saved as silverbullet.container in the correct path for your user, you’ll have to reload systemd’s user instance for it to become usable.

systemctl --user daemon-reload

After this, silverbullet will be available as a service unit, and can be started as a systemd service.

systemctl --user start silverbullet

Note that you do not need to enable this service. If the container was running when you logged out, it will be restarted when you next log in.

In addition to .container units, you can also define networks, volumes, container builds, and more in this manner. For these, I highly recommend to read the manual page and see what you can do if such a setup interests you. It could be a much simpler way of managing a server which runs a few containers, so you won’t need a full container orchestration platform, such as k3s, to manage it.