Featured image of post Podman Quadlets

Podman Quadlets

Erstellung und Nutzung von Podman Quadlets, rootfull und rootless.

Hinweis
Für die Nutzung von Quadlets ist mindestens die Podman Version 4.4 erforderlich. Die Version kann mit dem Befehl podman version geprüft werden.

Einleitung

In dem vorangegangenen Beitrag Einführung in Podman haben wir Podman installiert und grundlegend eingerichtet. Bitte stellt sicher, dass du alle dort genannten Schritte auf deinem System ausgeführt habt, da dies die Grundlage für diesen Beitrag ist.

Mit der Grundinstallation ist es jetzt schon möglich, über einfache podman run-Befehle Container zu erstellen und zu steuern. Doch wie geht man vor, wenn man sich nicht die langen Befehle mit all den Einstellungen für den Container merken möchte? Bei Docker nutzt man in diesem Fall docker-compose.yml-Dateien, die alle Informationen zu Container, Volume und Netzwerk beinhalten.

Für Podman sind dafür Quadlets vorgesehen. Bei Quadlets handelt es sich um systemd Unit Dateien. Andere bekannte Units wären zum Beispiel

  • .service
  • .timer
  • .target

Quadlets bringen jetzt unter anderen zusätzlich

  • .container
  • .volume
  • .network

Systemd generiert aus den Quadlets passende Services, sodass diese dann wie ganz normale Dienste und Programme über systemctl gesteuert werden können.

Wie man Quadlets erstellt und einsetzt, wird in diesem Beitrag anhand des Flame Dashboard (https://github.com/pawelmalak/flame) beschrieben.

Rootful oder rootless?

Da es bei Podman im Gegensatz zu Docker keinen zentralen Prozess (Daemon) gibt, hängt es vom ausführenden Benutzer ab, ob ein Container rootful oder rootless ist. Von einem rootful Container spricht man, wenn dieser vom Benutzer root erstellt und gestartet wurde. Der Container kann somit alle Privilegien erhalten, die auch root hat. Ein rootless Container dagegen wird von einem normalen Benutzer erstellt und gestartet.

Die meisten Container sollten problemlos rootless ausgeführt werden können und das sollte aus Sicherheitsgründen auch immer die bevorzugte Variante sein. Es kann jedoch Spezialfälle geben, bei denen der Container Berechtigungen benötigt, die nur von root erteilt werden können.

Beispiel: Normale Benutzer können keine Ports öffnen, die kleiner als 1024 sind, dafür ist root notwendig. Wenn es sich bei dem Container um einen Reverse Proxy handelt, benötigt man aber die Ports 80 (http) und 443 (https). In so einem Fall gibt es zwei Möglichkeiten, welche man besser findet muss man abwägen:

  1. root für den Container nutzen, also rootful. Im Quadlet kann weiterhin ein anderer Benutzer anegegeben werden, sodass der Prozess im Container mit einem unprivilegierten Benutzer läuft.
  2. Den Container dennoch rootless starten, statt 80/443 höhere Ports nutzen (z.B. 10080/10443) und in der Firewall die Ports 80/443 auf diese höheren Ports umleiten (forward).

In diesem Beitrag werden wir einen rootless Container nutzen.

Wo werden die Dateien abgelegt?

Es gibt vordefinierte Pfade, in denen systemd nach Quadlets sucht. Diese werden nachfolgend einmal für rootful und für rootless aufgelistet, zusätzlich befindet sich in der Übersicht auch noch der Pfad zu den Volumes. Die werden von Podman selbst angelegt, wenn man sie in den Quadlets definiert.

Für rootful:

  • Quadlets: /etc/containers/systemd
  • Volumes: /var/lib/containers/storage/volumes

Für rootless:

  • Quadlets: ~/.config/containers/systemd
  • Volumes: ~/.local/share/containers/storage/volumes

Die Daten für rootless liegen also komplett im Home-Verzeichnis des ausführenden Benutzers. Für die Quadlets können auch zusätzliche Unterordner, zum Beispiel je Anwendung, angelegt werden, um die Übersicht zu erhöhen.

Verzeichnisse anlegen

Zunächst müssen wir in den Benutzer wechseln, der den Container erstellen und ausführen soll. Wenn das der gleiche Benutzer sein soll, mit dem du dich per SSH eingeloggt hast, kann es direkt los gehen und du kannst den nächsten Befehl überspringen.

Wenn es ein anderer Benutzer sein soll, wechseln wir jetzt in diesen Benutzer:

1
sudo machinectl shell --uid NAME_DES_BENUTZERS
Hinweis
Der Benutzerwechsel sollte mit machinectl erfolgen und nicht mit sudo su, weil dies zu Problemen bei der Nutzung von systemctl --user führen kann. Wenn der Befehl machinectl fehlt, muss “systemd-container” nachinstalliert werden.

Die Verzeichnisse, in denen später Quadlets und Volumes liegen, existieren noch nicht und müssen angelegt werden. Nachfolgend legen wir die Ordner an und erstellen symbolische Links direkt in die Hauptebene des Home-Verzeichnis, damit wir die Unterordner einfacher erreichen können:

1
2
3
4
mkdir -p ~/.config/containers/systemd
mkdir -p ~/.local/share/containers/storage/volumes
ln -s ~/.config/containers/systemd ~/containers
ln -s ~/.local/share/containers/storage/volumes ~/volumes

Im Home-Verzeichnis befinden sich jetzt die beiden Links containers und volumes, über die wir mit cd schnell in die jeweiligen Zielverzeichnisse springen können.

Podman Secrets

Für das Flame Dashboard müssen wir ein Passwort definieren, mit dem wir uns dann später in den Adminbereich einloggen können. Damit dieses nicht im Klartext in eine Konfigurationsdatei eingetragen werden muss, bietet Podman eine Funktion an, um diese Art von Daten zu sichern, die Podman Secrets. Mit dieser Funktion erstellen wir ein Secret und geben diesem einen Namen und den dazugehörigen Wert, also das Passwort. Später im Quadlet definieren wir dann, dass dieses Secret abgerufen werden und in dem Container als Umgebungsvariable zur Verfügung gestellt werden soll.

Erstellung des Secrets per Datei

Der Befehl zur Erstellung eines Secrets erwartet eine Datei als Eingabe:

1
nano passwordfile

Dort trägst du einfach nur das gewünschte Passwort ein, dann speichern und schließen mit STRG+O -> ENTER STRG+X (Mac: control statt STRG).

Anschließend erstellen wir ein Secret, als Wert wird der Inhalt der eben erstellten Datei zugewiesen:

1
podman secret create flame_password passwordfile

Der Inhalt der Datei befindet sich nun im Secrets Speicher von Podman, die Datei kann also entfernt werden:

1
rm passwordfile

Mit podman secret ls wir eine Übersicht aller verfügbaren Secrets angezeigt. Es werde nur die Namen der Secrets angezeigt, der Inhalt kann nicht ausgegeben werden.

Erstellung des Secrets ohne Datei

Alternativ kann mit folgendem Befehl das Passwort direkt gespeichert werden ohne den Umweg mit der Dateierstellung:

1
printf "VERY_SECRET_PASSWORD" | podman secret create flame_password -

Der Nachteil ist, dass das Passwort jetzt in der Befehlshistorie der Shell zu sehen ist, wenn du mit Pfeil nach oben die vorangegangnen Befehle durchgehst. Hier sollte dann ggf. einmal history -c ausgeführt werden, um die komplette Historie zu löschen.

Quadlets erstellen

Jetzt kann es endlich an die Quadlets selbst gehen. Dazu wechseln wir über unseren Symlink in das Verzeichnis, in das die Quadlets abgelegt werden müssen:

1
cd containers

und legen erstmal einen Unterordner für unsere Anwendung flame an und wechseln dann auch in diesen Ordner:

1
2
mkdir flame
cd flame

Flame Container

Zunächst erstellen wir das Quadlet für den Container an sich:

1
nano flame.container

Inhalt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[Unit]
Description=Flame Dashboard Podman Container
After=network-online.target

[Container]
AutoUpdate=registry

Image=docker.io/pawelmalak/flame:latest
ContainerName=flame
HostName=flame

PublishPort=8080:5005/tcp

Volume=flame-data.volume:/app/data

Environment=TZ=Europe/Berlin

Secret=flame_password,type=env,target=PASSWORD

[Service]
Restart=always

[Install]
WantedBy=default.target

Speichern und Schließen mit STRG+O -> ENTER STRG+X (Mac: control statt STRG)

Detaillierte Beschreibung der einzelnen Angaben:

SchlüsselwortBeschreibung
[Unit]Keine Besonderheit von Quadlets, gibt es generell in Service Units.
Description=Name / Beschreibung des Service
After=Abhängigkeiten zu anderen Diensten. Die Eintragung network-online.target bedeutet, dass der Service erst starten soll, wenn eine Netzwerkverbindung besteht.
[Container]Spezifische Beschreibung des Containers (Quadlet-Funktionalität)
AutoUpdate=Definiert, dass dieser Container vom automatischen Update berücksichtigt werden soll (podman-auto-update). Der Wert “registry” sagt aus, dass in der angegebenen Registry (z.B. Docker Hub) nach Updates gesucht wird.
Image=Das zu verwendende Image. Die Registry muss immer mit angegeben werden, hier “docker.io/”
ContainerName=Der Name, den der Container haben soll.
HostName=Der Hostname, der innerhalb des Containers genutzt werden soll.
PublishPort=Port-Mapping. Die erste Angabe ist der zu verwendende Port auf dem Host-System, die zweite Angabe der im Container. 8080:5005/tcp = TCP-Port, Host: 8080, Container: 5005
Volume=Speicherbereich, in dem die Daten das Löschen des Containers überleben. Vor dem Doppelpunkt steht der Pfad auf dem Host, nach dem Doppelpunkt der Pfad im Container. Es kann direkt ein Pfad angegeben werden oder wie hier der Verweis auf das Quadlet “flame-data.volume”, das später noch erstellt wird.
Environment=Angabe von Environment-Variablen im Container im Format: Environment=NAME_DER_VARIABLE=WERT_DER_VARIABLE
Secret=Ein in den Podman Secrets eingetragenes Secret in den Container geben. In diesem Fall wird der Inhalt vom Secret “flame_password” im Container in die Environment-Variable PASSWORD geschrieben.
[Service]Keine Besonderheit von Quadlets, gibt es generell in Service Units.
Restart=Was soll passieren, wenn der Container abstürzt. Bei “always” wird er in diesem Fall immer neu gestartet. Sollte er zu schnell hintereinander abstürzen, bricht systemd dies nach 5 Versuchen ab und der Container bleibt gestoppt.
[Install] WantedBy=Die von systemd aus Quadlets erstellten Service-Units sind “transient”. Das bedeutet, dass man sie nicht wie von anderen Services gewohnt für den Autostart aktivieren (systemctl enable) kann. WantedBy=default.target in der Install-Section bedeutet, dass der Service automatisch mit dem System startet. Wenn das nicht so sein soll, kann die komplette [Install]-Section weggelassen werden.

Flame Volume

In vorangegangenen Quadlet flame.container haben wir als einzubindendes Volume flame-data.volume angegeben. Diese Datei muss nun ebenfalls angelegt werden. Darin beschreiben wir Einzelheiten des Volumes, in unserem Fall muss außer dem Namen, den das Volume haben soll, nichts weiter definiert werden.

1
nano flame-data.volume

Inhalt:

1
2
3
4
5
[Unit]
Description=Flame Dashboard Data Volume

[Volume]
VolumeName=flame-data

Services erstellen und starten

Damit systemd jetzt funktionierende Service-Units aus den Quadlets erstellt, reicht folgender Befehl:

1
systemctl --user daemon-reload

Dadurch wurde jetzt im System flame.service erstellt und wir können unseren Container einfach über systemctl starten:

1
systemctl --user start flame.service

Mit nachfolgendem Befehl können wir uns auch den aktuellen Status ansehen.

1
systemctl --user status flame.service

Ebenso ist der Container jetzt unter Podman sichtbar mit:

1
podman ps

Das Log des Containers lässt sich ebenfalls direkt aufrufen:

1
podman logs -f flame

WICHTIG: Bei jeder Anpassung an den Quadlets ist danach immer der Befehl systemctl --user daemon-reload notwendig, damit die dazugehörigen Service-Dateien von systemd aktualisiert werden.

Container unter systemd-Verwaltung

Wenn der Container gestoppt werden soll, muss dies jetzt über systemd, also systemctl --user stop flame.service geschehen. Beim Stoppen wird der Container auch jedes Mal gelöscht und beim Start neu erstellt. Nach dem Stoppen sieht man den Container also mit podman ps nicht mehr, da er nicht mehr existiert. Alle Daten, die in Volumes sind, gehen dabei nicht verloren.

Da es sich um einen systemd-Service handelt wird dieser nun genauso wie alle anderen Dienste und Programme überwacht. Stürzt der Container ab, wird er von systemd automatisch neu gestartet. Stoppt ihr den Container mit einem direkten Podman-Befehl, wird er ebenfalls wieder von systemd automatisch gestartet. Für Start/Stop sollte also ausschließlich systemctl genutzt werden.

Dashboard aufrufen

Gemäß unserer Konfiguration ist das Flame Dashboard jetzt über den Port 8080 erreichbar. Davor müsst ihr aber wahrscheinlich erst noch den Port in der Firewall öffnen, da Podman dies bei unprivilegierten Containern nicht von selbst macht. Wenn du unserer Alma Linux Anleitung gefolgt bist, hast du firewalld im Einsatz und kannst den Port folgendermaßen freigeben:

1
2
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --reload

Jetzt kannst du im Browser das Dashboard unter http://SERVER_IP:8080 erreichen.

Abschluss

Damit hast du deinen ersten Container mit Quadlets beschrieben und in Einsatz genommen. Quadlets bieten noch eine riesige Menge an weiteren Optionen, da hilft häufig ein Blick in die sehr gute Podman Dokumentation. Unten rechts hat man hier auch die Möglichkeit die Version auszuwählen, die man gerade im Einsatz hat. Damit sieht man dann auch wirklich nur die Optionen und Befehle, die in der jeweiligen Version verfügbar sind.

Zuletzt aktualisiert am 12.02.2025, 16:29 +0100
Erstellt mit Hugo
Theme Stack gestaltet von Jimmy