Declarative Podman Setup? Just use Quadlets

Nicola Sella and Jan Rodák

Nicola Sella

Senior Software Engineer

Jan Rodák

Software Engineer

Plan for today

  • Intro
  • Quick theory of Systemd and Quadlets
  • Minimal examples of a quadlet
  • Connecting Quadlets together
  • How to migrate compose files
  • Integrating with Quadlets
  • Future in Podman6

Before we begin

Podman

  • Container Engine
    • Not just Podman, there's also Skopeo, Buildah...
  • Part of CNCF since January 2025
  • Check it on podman.io

What is a Quadlet?

  • File with a specific extension that lives in ~/.config/containers/systemd
  • Systemd unit file generator
  • Declarative Container Specification

Basic quadlet commands

  • podman quadlet install
  • podman quadlet list
  • podman quadlet print
  • podman quadlet rm

Basics of systemd: .service files

  • Configuration files that give instructions to systemd on how to start, stop, restart
  • Processes and daemons can be managed by unit files

Basic Systemd commands

  • systemctl --user status
  • systemctl --user start
  • systemctl --user restart
  • systemctl --user stop
  • systemctl --user enable --now
  • systemctl --user disable --now
  • systemctl --user cat

Anatomy of a Quadlet

Source: your .container quadlet


# ~/.config/containers/systemd/minimal.container
[Container]
Image=quay.io/demo_quadlets/alpine:latest
                        

Generated: systemd unit (do not edit by hand)


# /run/user/1000/systemd/generator/minimal.service
# Automatically generated by /usr/lib/systemd/user-generators/podman-user-generator
#
[X-Container]
Image=quay.io/demo_quadlets/alpine:latest

[Unit]
Wants=podman-user-wait-network-online.service
After=podman-user-wait-network-online.service
SourcePath=/home/nsella/.config/containers/systemd/minimal.container
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
KillMode=mixed
ExecStop=/usr/bin/podman rm -v -f -i systemd-%N
ExecStopPost=-/usr/bin/podman rm -v -f -i systemd-%N
Delegate=yes
Type=notify
NotifyAccess=all
SyslogIdentifier=%N
ExecStart=/usr/bin/podman run --name systemd-%N --replace --rm --cgroups=split --sdnotify=conmon -d quay.io/demo_quadlets/alpine:latest
                        

What systemd actually runs (ExecStart from the generated service)

/usr/bin/podman run \
    --name systemd-%N \
    --replace --rm \
    --cgroups=split \
    --sdnotify=conmon \
    -d quay.io/demo_quadlets/alpine:latest

Quadlet file types

Container unit file

Defines a single long-running container; maps to podman run.

podman run alpine:latest

[Container]
Image=alpine:latest
                        
mycontainer.container → mycontainer.service

Pod unit file

Creates a pod (shared network/IPC); containers join it with Pod=….

podman pod create

[Pod]
                        
mypod.pod → mypod.service

Kube unit file

Applies a Kubernetes manifest (Pod, Deployment, etc.) in one shot instead of many .container files.

podman kube play myawesomekubefile.yaml

[Kube]
Yaml=myawesomekubefile.yaml
                        
mykube.kube → mykube.service

Network unit file

Provisions a named network; containers reference it with Network=….

podman network create mynetwork

[Network]
                        
mynetwork.network → mynetwork-network.service

Volume unit file

Declares persistent disk; mount in containers with Volume=myvolume.volume:/path.

podman volume create myvolume

[Volume]
                        
myvolume.volume → myvolume-volume.service

Build unit file

Builds an image from a Containerfile next to the unit; other units can then run that tag.

podman build --tag localhost/imagename .

[Build]
ImageTag=localhost/imagename
SetWorkingDirectory=unit
                        
myimage.build → myimage-build.service

Image unit file

Pull-only service; containers use Image=myimage.image so start does not wait on the registry.

podman pull quay.io/centos/centos:latest

[Image]
Image=quay.io/centos/centos:latest
                        
myimage.image → myimage-image.service

Artifact unit file

Fetches OCI artifacts (models, bundles) for use with newer Podman features—not a runnable image by itself.

podman artifact pull quay.io/foobar/artifact:special

[Artifact]
Artifact=quay.io/foobar/artifact:special
                        
myartifact.artifact → myartifact-artifact.service

Demos

00_minimal
  1. Run a mininal example and understand the basics of quadlets
01_wordpress
  1. Run two containers
  2. Add persistence with .volume files
  3. Add a pod to manage container network
  4. Better environment file management
  5. Handle image pull separately
  6. Manage auto updates
02_compose
  1. Break down a compose file
  2. Implement quadlets in a single file solution
03_kube
  1. Convert compose to Kubernetes YAML
  2. Run the stack with a .kube quadlet
  3. Check out podlet
04_python
  1. Manage your quadlet from Python
  2. Note the variable XDG_RUNTIME_DIR
05_curl
  1. Quadlets from the RESTful API

Our team

Code github.com/containers/podman
Chat (dev) #podman-dev:matrix.org
Chat (general) #podman:fedoraproject.org
Calendar zoom-lfx.platform.linuxfoundation.org
Office Hours Mon 16:00–16:30 CET  |  Thu 17:00–17:30 CET
Community 1st Tue/Even month (Feb, Apr, June,...) 17:00–18:00 CET

References