Podman Reloaded
In an earlier post, I wrote about Podman. See also Podman. Now, I wanted
to migrate some applications to Podman and received a deprecation warning with the command:
podman generate systemd --new --files --name test
.
It is suggested to adapt to Quadlet, which provides a nicer workflow. So I did, but it took some reading to
figure it out, which is why I’m summarizing it here.
This change offers a clean and elegant solution, seamlessly integrating Podman with systemd. While it took me some time as a user to get everything running smoothly again, the effort was absolutely worth it.
This is another blog I found helpful: https://mo8it.com/blog/quadlet/.
Quadlet
Quadlet is integrated into Podman and allows users to create systemd services in a declarative way. You
can find more details here:
https://www.redhat.com/en/blog/quadlet-podman.
I placed the quadlet files in .config/containers/systemd/
. And a simple app can look like that:
# some-app.container
[Container]
AutoUpdate=registry
ContainerName=some-app
Environment=TZ=Europe/Zurich
Image=lscr.io/linuxserver/some-app:latest
Pod=some-app-stack.pod
PodmanArgs=--tty
Volume=some-app_data:/config
[Service]
Restart=always
[Install]
WantedBy=default.target
With following command one can verify how the generated files look like:
/usr/libexec/podman/quadlet -dryrun -user
Output:
quadlet-generator[4645]: Loading source unit file /home/toob/.config/containers/systemd/some-app.container
---some-app.service---
# some-app.container
[X-Container]
AutoUpdate=registry
ContainerName=some-app
Environment=TZ=Europe/Zurich
Image=lscr.io/linuxserver/some-app:latest
Pod=some-app-stack.pod
PodmanArgs=--tty
Volume=some-app_data:/config
[Service]
Restart=always
Environment=PODMAN_SYSTEMD_UNIT=%n
KillMode=mixed
ExecStop=/usr/bin/podman rm -v -f -i --cidfile=%t/%N.cid
ExecStopPost=-/usr/bin/podman rm -v -f -i --cidfile=%t/%N.cid
Delegate=yes
Type=notify
NotifyAccess=all
SyslogIdentifier=%N
ExecStart=/usr/bin/podman run --name some-app --cidfile=%t/%N.cid --replace --rm --cgroups=split --sdnotify=conmon -d -v some-app_data:/config --label io.containers.autoupdate=registry --env TZ=Europe/Zurich --pod-id-file %t/some-app-stack-pod.pod-id --tty lscr.io/linuxserver/some-app:latest
[Install]
WantedBy=default.target
[Unit]
Wants=podman-user-wait-network-online.service
After=podman-user-wait-network-online.service
SourcePath=/home/toob/.config/containers/systemd/some-app.container
RequiresMountsFor=%t/containers
BindsTo=some-app-stack-pod.service
After=some-app-stack-pod.service
Podlet
Podlet helps to generate such files. One can find it here on github; https://github.com/containers/podlet?tab=readme-ov-file.
It supports many different modes, including generating from already running resources, which is the closest replacement for the old podman generate command. However, it also supports interesting features like generating from Docker Compose files.
Here’s an example of how I used it to generate a Quadlet file from an existing pod:
podlet generate pod some-app-stack
I think the functionality of the generate option hasn’t received much attention. It only supports a small subset of creation options and may fail. In my case, I had to recreate almost everything manually.
Troubleshooting
Initially, I encountered problems with the AutoUpdate=registry setting for my Grafana instance. Since I want it to auto-update for easier maintenance, I included this argument in my quadlet file. However, with this setting, Grafana failed to start. When I removed the argument, it started without any issues.
Upon checking the service logs, I noticed a warning about the image reference, indicating that it should be a fully qualified domain name (FQDN).
To resolve this, I updated my image reference from Image=grafana/grafana:latest to Image=docker.io/grafana/grafana:latest. After this change, everything worked as expected. In hindsight, this makes sense because Podman does not assume Docker Hub as the default registry. Still, it was a bit of a headache to figure out.
Auto-Updates and Rollbacks
The auto-updates and rollbacks continue to function as before. You can refer to my previous post for more details.