Chapter 21: Containers with Podman
Containers as services with Quadlet
A container you started by hand is gone after a reboot. To run it as a real service, describe it in a Quadlet file. Podman turns that file into a systemd service, so everything you learned in chapter 9 (start, status, restart, journal) applies to your container too.
- Write a
.containerfile and run it as a user service. - Check the generated unit, restart behaviour and logs.
- Make the service start at boot with lingering, and open its port.
From a file to a service
From a file to a service: Step through Quadlet.
A Quadlet file: Select a section or setting.
Put the file in the directory below. Start from the page and image of the earlier lessons (the page is in ~/web):
[student@servera ~]$ mkdir -p ~/.config/containers/systemd
[student@servera ~]$ cat > ~/.config/containers/systemd/web.container <<'EOT'
[Unit]
Description=Demo web container
[Container]
Image=registry.access.redhat.com/ubi9/httpd-24:latest
PublishPort=8080:8080
Volume=%h/web:/var/www/html:ro,Z
[Service]
Restart=always
[Install]
WantedBy=default.target
EOT
[student@servera ~]$ systemctl --user daemon-reload
[student@servera ~]$ systemctl --user start web.service
[student@servera ~]$ systemctl --user is-active web.service
active
[student@servera ~]$ curl -s localhost:8080
hello from a container
[student@servera ~]$ podman ps --format "{{.Names}} {{.Status}}"
systemd-web Up 3 secondsThe container is named systemd-web (the prefix systemd- plus the file name). systemctl --user cat web.service shows the generated unit, which begins with the comment "Automatically generated by …podman-user-generator". Edit the .container file, never the generated one, and run daemon-reload after every change.
Restart behaviour
[student@servera ~]$ systemctl --user is-enabled web.service
generated
[student@servera ~]$ podman kill systemd-web
systemd-web
[student@servera ~]$ systemctl --user is-active web.service
active
[student@servera ~]$ systemctl --user show web.service -p NRestarts
NRestarts=1You do not run enable: a generated unit shows generated, and the [Install] section of your file does the work. Restart=always restarted the killed container; systemctl --user status web.service shows the application's own log lines as well.
Surviving a reboot
By default a user's services run only while that user is logged in. Lingering keeps the user's systemd alive from boot:
[student@servera ~]$ loginctl show-user student -p Linger
Linger=no
[student@servera ~]$ sudo loginctl enable-linger student
[student@servera ~]$ loginctl show-user student -p Linger
Linger=yes
[student@servera ~]$ sudo firewall-cmd --permanent --add-port=8080/tcp; sudo firewall-cmd --reload
success
successWith lingering on, a reboot is followed by a running container, without anyone logging in; a client on serverb gets the page. Without it, the same client gets "Connection refused" until student logs in for the first time. Lingering is a deliberate policy: it lets a user run programs without a session, so enable it only for service accounts that need it.
When it does not work
| Symptom | Check |
|---|---|
Failed to connect to bus | You are not in a real login; ssh in as the user |
| Service fails at once | systemctl --user status web.service, journalctl _SYSTEMD_USER_UNIT=web.service and podman logs systemd-web |
| Start times out | Pull the image first; a slow registry is the usual cause |
| Page gives 403 | The volume needs :Z |
| Address already in use | Another container or program uses the host port (ss -tlnp) |
| Works locally only | Allow the port in the firewall |
| Does not start after reboot | Lingering is off |
A wrong image name shows up in the journal as Error: unable to copy from source docker://…/httpd-99:latest, and systemctl --user is-active keeps saying activating while Restart=always retries.
The earlier podman generate systemd command is deprecated in favour of Quadlet. Use .container files for new work.
Try it
Check your understanding
- Where do you put the definition of a rootless Quadlet container?
- Which command makes systemd read a new or changed .container file?
- What does loginctl enable-linger student do?
- Restart=always is in the file. The container is killed. What happens?
- Why pull the image before starting the service?
- A rootless service works on the host but other machines cannot reach it. Which step is often missing?