Quadlet¶
Tool · prereq 03 (Containers/Podman), 09 (RHEL) · ~half a day–1 day
A container you launched by hand in module 03 (Containers) doesn't survive a
reboot and isn't managed like every other service on the box. Quadlet closes that gap: you write a
declarative .container/.volume/.network file, and systemd — the service manager from
module 09, Linux (RHEL) — generates and owns the real unit from it, so the
container starts at boot, restarts on failure, and is inspected with the same systemctl/journalctl
tools as any other service. This module is about that generate-from-source loop, and the one habit that
trips people up: editing the source file alone does nothing until you tell systemd to regenerate.
TL;DR — in 30 seconds:
- Editing a
.container/.volume/.networkfile does nothing on its own — you mustsystemctl daemon-reloadbefore the generator re-reads it and rebuilds the real unit. - Quadlet replaces
podman generate systemd: you edit a declarative source file and reload, instead of regenerating a static shell-script-like unit by hand every time the container config changes. - Never hand-edit the generated
.servicefile — it's rebuilt from the source Quadlet file on every reload, so direct edits to it are effectively thrown away.
Learning objectives¶
By the end, the junior can:
- Write a
.containerQuadlet unit and run a container as a systemd service. - Explain why
daemon-reloadis needed and how Quadlet replacespodman generate systemd. - Attach a
.volume/.networkto a Quadlet.
Pair, Do and Prove run in Claude Code, with the onboarding-tutor skill. Click a button to copy the exact prompt, then paste it into Claude Code in this repo.
1. Learn · acquire the concept¶
Read: the quadlet course — focus §4 (
.container), §5 (.volume), §6 (.network), §12 (operations — the daily loop). Skip for now: §8 (.kube), §9 (.build/.image) — later. Glossary (beat 5): the module’s Anki deck
Check yourself — you edit a key in myapp.container and run systemctl restart myapp.service, but the container still runs with the old configuration. What step did you skip, and why?
systemctl daemon-reload — a plain restart just reruns the existing generated unit. Quadlet's
generator only re-reads the source .container file and rebuilds the service on daemon-reload (or at
boot), so a restart without a reload first just restarts the stale, unchanged unit.
Check yourself — why is Quadlet preferred over the older podman generate systemd approach?
Quadlet units are declarative source files that get regenerated automatically on daemon-reload — you
edit the .container/.volume/.network file and reload. podman generate systemd instead produced a
static, one-off unit file that had to be manually regenerated and rewritten by hand every time the
container's configuration changed.
2. Pair · passive → active¶
Drive the onboarding-tutor skill:
- "Explain what Quadlet generates and where the real systemd unit ends up."
- "3-line mental model of the
.container→systemctl daemon-reload→systemctl startloop." - "Quiz me: why does my edit not take effect until I do X?"
Common gotchas
- Hand-editing the generated
.servicefile instead of the source Quadlet file. Fix: always edit the source.container/.volume/.networkfile anddaemon-reload— the generated unit is rebuilt from source on every reload, so direct edits to it don't survive. - Forgetting
daemon-reloadafter adding or editing a Quadlet file. Fix: systemd only reruns the Quadlet generator ondaemon-reload(or boot) — without it, the edit is silently not picked up at all, even though nothing looks obviously wrong. - Dropping a rootless quadlet file in the root path (
/etc/containers/systemd/), or vice versa. Fix: rootless quadlets live under~/.config/containers/systemd/; root quadlets live under/etc/containers/systemd/— the wrong directory means the wrong systemd instance never sees the file. - Assuming
systemctl --user enable --nowalone survives a logout. Fix: a rootless service also needsloginctl enable-linger <user>— without it, the user systemd instance (and everything in it) stops the moment the last session ends.
Done when: you can explain the daemon-reload step before you forget it, unprompted.
3. Do · produce an artifact¶
Exercise — promote your module 03 (Containers) container to a systemd service:
- Use a systemd Linux host (course §3) — Quadlet is systemd-native: a RHEL/Linux VM (module 09, Linux (RHEL)), not macOS. Needs Podman + systemd.
- Take the image you built in module 03 (Containers) and write a
.containerQuadlet unit for it, with a.volumefor its state. - Drop the files in the right dir,
systemctl daemon-reload, thensystemctl --user enable --now(rootless) the generated service. - Verify with
systemctl status+journalctl. Reboot or restart the service and confirm state persists (the volume).
Done when: the container runs as a managed systemd service and survives a restart with its data.
4. Prove · understanding gate¶
Mandatory. Pass bar in the Socratic gate.
- Walkthrough: Explain each key in your
.containerfile and which systemd unit it generated. - Alternative: Quadlet vs the old
podman generate systemd— why is Quadlet preferred now? - Failure & debug: You edited the
.containerfile but nothing changed — why? And when systemd says the unit doesn't exist, what are the two usual causes? - Provenance: Which keys did the agent add? How did you verify the generated unit matches your intent (
systemctl cat)?
Pass bar: you can defend the Quadlet→systemd generation and the daily loop. Forgetting why daemon-reload matters = back to Pair.
5. Retain · fight forgetting¶
Study the module deck SE Onboarding::10 Quadlet — its 11 theme subdecks let you drill one area at a time. It syncs to your Anki automatically on pull (anki-sync).
Done when: you can recall — from the deck — .container/.volume/.network, daemon-reload, and the rootless quadlet dirs.
Key takeaways¶
- Quadlet is declarative: you edit a source
.container/.volume/.networkfile and the generator rebuilds the real systemd unit from it — you never author or hand-maintain the unit itself. systemctl daemon-reloadis the step that makes an edit take effect — the generator only re-reads Quadlet source files on reload (or at boot); skip it and the change is silently not picked up.- Never hand-edit the generated
.servicefile — it's rebuilt from the source Quadlet file on every reload, so direct edits to it don't survive. - Rootless quadlets live under
~/.config/containers/systemd/; root quadlets live under/etc/containers/systemd/— the wrong directory means the wrong systemd instance never sees the file. - A rootless service also needs
loginctl enable-linger <user>to survive logout —systemctl --user enable --nowalone stops the service the moment the last session ends. - Quadlet replaces
podman generate systemd: instead of manually regenerating a static unit file by hand every time the container config changes, you edit a declarative source file and reload.
Go deeper — curated resources¶
Hand-picked external material to take this topic further — the best books, courses, talks, and writing. Cost is tagged Free, Free online (full text/course free on the web), or Paid.
- Docs · Quadlet — podman-systemd.unit(5) — Podman project. The reference for Quadlet unit files: every key for
.container/.volume/.networkand how it maps topodman. Free. - Blog · Make systemd better for Podman with Quadlet — Dan Walsh (Red Hat). A practical, hands-on intro to running containers under systemd with Quadlet, from Podman's lead. Free.
- Docs · systemd.service man page — freedesktop.org. What a unit file can actually express underneath — service types,
ExecStart,Restart=, dependencies. Free.
Gate log (mentor fills on pass)¶
- Date passed: / Passed by: / checked by: / Weak spots: