Managing Containers with Podman Quadlet
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.