Podman ist bekannt für seine nahtlose Integration in moderne Linux-Systeme, und die Unterstützung von systemd ist ein Eckpfeiler dieser Bemühungen. Linux verwendet üblicherweise das Systemd-Init-System, um lokale Dienste wie Webserver, Container-Engines, Netzwerk-Daemons und alle ihre gegenseitigen Abhängigkeiten zu verwalten. Die Erweiterung dieser traditionelleren Linux-Systemverwaltungspraktiken mit der modernen Welt der Container ist eine natürliche Entwicklung.
Es gibt zwei gängige Anwendungsfälle für die Kombination von systemd und Containern:
- Systemd in einem Container ausführen
- Systemd verwenden, um containerisierte Anwendungen auszuführen
Das erste Szenario ist das Ausführen von systemd innerhalb eines Containers. Wie Dan Walsh erklärt, ist das Ausführen von systemd in einem Container so einfach wie möglich, wenn Podman verwendet wird. Podman richtet automatisch mehrere Mounts im Container ein und systemd ist startklar. Obwohl es sich um ein vergleichsweise kleines Podman-Feature handelt, war es bei seiner Einführung ein großer Sprung für die Ausführung containerisierter Workloads.
In der Vergangenheit haben andere Container-Tools systemd nicht unterstützt. Benutzer standen vor der Herausforderung, benutzerdefinierte Init-Skripte zu schreiben, die fehleranfällig sind und eine Supportbelastung für Softwareanbieter darstellen. Mit Podman verschwinden all diese Probleme. Benutzer können systemd verwenden, um ihre Anwendungen in Containern zu installieren und auszuführen, genau wie anderswo, und Softwareanbieter werden nicht mit den Herausforderungen konfrontiert, mit benutzerdefinierten Init-Skripten umzugehen, die von ihren Benutzern geschrieben wurden.
Das zweite Szenario verwendet systemd zum Ausführen und Verwalten von containerisierten Anwendungen. Das bedeutet, dass systemd eine containerisierte Anwendung startet und ihren gesamten Lebenszyklus verwaltet. Podman vereinfacht dies mit dem podman generate systemd
Befehl, der eine systemd-Unit-Datei für einen bestimmten Container oder Pod generiert. Podman v1.7 und höher unterstützen das Generieren solcher Einheiten. Im Laufe der Zeit hat unser Team diese Funktion verbessert und systemd-Unit-Dateien generiert, die auf anderen Computern ausgeführt werden können, ähnlich wie bei der Verwendung einer Kubernetes-YAML- oder einer Compose-Datei. Darüber hinaus legte die enge Integration mit systemd den Grundstein für automatische Updates und einfache Rollbacks, die seit Podman v3.4 unterstützt werden.
Während es viele frühere Blogs und Artikel zum Generieren von systemd-Einheiten für Container gibt, gibt es keine zum Generieren dieser Einheiten für Pods. Aber bevor ich auf diese Details eingehe, möchte ich noch einmal kurz erläutern, was ein Pod ist.
[ Erste Schritte mit Containern? Schauen Sie sich diesen kostenlosen Kurs an. Containerisierte Anwendungen bereitstellen:Eine technische Übersicht. ]
Was ist ein Pod?
Es gibt mehrere verschiedene Teile in einem Pod, und ich denke, Brent Baude erklärt es am besten mit der großartigen Abbildung unten:
Als Erstes fällt auf, dass ein Pod aus einem oder mehreren Containern besteht. Die Gruppe teilt sich Kontrollgruppen (cgroups) und bestimmte Namespaces wie den PID-, Netzwerk- und IPC-Namespace. Die gemeinsam genutzten Cgroups stellen sicher, dass alle Container die gleichen Ressourcenbeschränkungen haben. Die gemeinsam genutzten Namensräume ermöglichen es den Containern, einfacher miteinander zu kommunizieren (z. B. über localhost oder Kommunikation zwischen Prozessen).
Sie können auch einen speziellen Infra-Container sehen. Sein Hauptzweck besteht darin, bestimmte mit dem Pod verbundene Ressourcen wie Ports, Namespaces oder cgroups offen zu halten. Der Infra-Container ist der Top-Level-Container des Pods und wird vor anderen Containern erstellt und zuletzt zerstört. Sie verwenden den Infra-Container beim Generieren von systemd-Einheiten für einen Pod. Denken Sie also daran, dass dieser Container für die gesamte Lebensdauer des Pods ausgeführt wird. Es impliziert auch, dass Sie keine systemd-Einheiten für Pods ohne Infra-Container generieren können (z. B. --infra=false
).
Zu guter Letzt sehen Sie mehrere conmon
laufende Prozesse, einer pro Container. „Common“ ist die Abkürzung für Container Monitor, was seine Hauptfunktionalität zusammenfasst. Es kümmert sich auch um die Weiterleitung von Protokollen und die Durchführung von Bereinigungsaktionen, sobald der Container beendet wurde. Der conmon
Der Prozess beginnt vor dem Container und weist die zugrunde liegende Containerlaufzeit an (z. B. runc
oder crun
), um den Container zu erstellen und zu starten. Es wird auch mit dem Exit-Code des Containers beendet, der es ermöglicht, ihn als Hauptprozess eines systemd-Dienstes zu verwenden.
Generieren von systemd-Einheiten für einen Pod
Podman erzeugt für einen Container genau eine Systemeinheit. Verwenden Sie nach der Installation systemctl
um den Dienst zu starten, zu stoppen und zu überprüfen. Die Haupt-PID jeder Einheit ist der gemeinsame Prozess des Containers. Auf diese Weise kann systemd den Exit-Code des Containers lesen und gemäß der konfigurierten Neustartrichtlinie handeln. Weitere Einzelheiten zu den Einheiten finden Sie unter Container mit Podman und gemeinsam nutzbaren systemd-Diensten ausführen und verbesserter systemd-Podman mit Podman 2.0.
Das Generieren von Einheiten für einen Pod ist dem Starten eines Containers sehr ähnlich. Jeder Container im Pod hat eine dedizierte systemd-Einheit, und jede Einheit hängt von der Haupt-systemd-Einheit des Pods ab. Auf diese Weise können Sie systemctl
weiterhin verwenden um den Hauptdienst des Pods zu starten, zu stoppen und zu inspizieren; systemd kümmert sich um das (Neu-)Starten und Stoppen der Dienste der Container zusammen mit dem Hauptdienst.
Dieses Beispiel erstellt einen Pod mit zwei Containern, generiert Unit-Dateien für den Pod und installiert dann die Dateien für den aktuellen Benutzer:
$ podman pod create --name=my-pod
635bcc5bb5aa0a45af4c2f5a508ebd6a02b93e69324197a06d02a12873b6d1f7
$ podman create --pod=my-pod --name=container-a -t centos top
c04be9c4ac1c93473499571f3c2ad74deb3e0c14f4f00e89c7be3643368daf0e
$ podman create --pod=my-pod --name=container-b -t centos top
b42314b2deff99f5877e76058ac315b97cfb8dc40ed02f9b1b87f21a0cf2fbff
$ cd $HOME/.config/systemd/user
$ podman generate systemd --new --files --name my-pod
/home/vrothberg/.config/systemd/user/pod-my-pod.service
/home/vrothberg/.config/systemd/user/container-container-b.service
/home/vrothberg/.config/systemd/user/container-container-a.service
Wie erwartet hat Podman drei .service
generiert Dateien, eine für jeden Container plus die oberste Ebene für den Pod. Den gesamten Inhalt der Unit-Dateien finden Sie im Anhang am Ende des Artikels. Die für die beiden Container generierten Units sehen aus wie Standard-Container-Units plus die folgenden systemd-Abhängigkeiten:
BindsTo=pod-my-pod.service
:Die Containereinheit ist an die Einheit des Pods "gebunden". Wenn die Einheit des Pods gestoppt wird, wird diese Einheit ebenfalls gestoppt.After=pod-my-pod.service
:Die Containereinheit beginnt nach der Einheit des Pods.
Die Abhängigkeiten des Hauptdienstes des Pods stellen außerdem sicher, dass die Haupteinheit des Haupt-Pods ebenfalls fehlschlägt, wenn eine Containereinheit nicht erfolgreich gestartet wird.
Das ist alles, was Sie über das Generieren von systemd-Einheiten für Pods mit Podman wissen müssen. Sobald Sie systemd über systemctl --user daemon-reload
neu geladen haben , starten und stoppen Sie den pod.service
nach Belieben. Schau mal:
# Reload the daemon
$ systemctl --user daemon-reload
# Start the pod service and make sure the service is running
$ systemctl --user start pod-my-pod.service
$ systemctl --user is-active pod-my-pod.service
active
# Make sure the pod and its containers are running
$ podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
6dd1090d4ca6 my-pod Running 2 minutes ago 85f760a5cfe5 3
user $ podman container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85f760a5cfe5 localhost/podman-pause:4.0.2-1646319369 5 minutes ago Up 5 minutes ago 6dd1090d4ca6-infra
44a7e60b9563 quay.io/centos/centos:latest top 5 minutes ago Up 5 minutes ago container-b
31f24bdff747 quay.io/centos/centos:latest top 5 minutes ago Up 5 minutes ago container-a
Super, alles funktioniert wie erwartet. Sie können systemctl
verwenden um die Dienste zu starten, und Podman listet die Pods und ihre Container korrekt auf. Sehen Sie sich der Einheitlichkeit halber abschließend an, wie Sie den Pod-Dienst stoppen können.
# Stop the pod service
$ systemctl --user stop pod-my-pod.service
# Make sure the pod and its containers are removed
$ podman pod ps -q
$ podman container ps -q
# Make sure the services are inactive
$ systemctl --user is-active pod-my-pod.service container-container-a.service container-container-b.service
inactive
inactive
inactive
Die Take-Home-Message lautet, dass Podman systemd-Einheiten für Pods genauso generiert wie für Container. Die Abhängigkeiten zwischen diesen Units sind so eingestellt, dass Sie nur mit der Haupt-Unit des Pods interagieren müssen, und systemd kümmert sich um das Starten und Stoppen der Container-Units.
Anhang
Podman generiert die folgenden Unit-Dateien für einen Pod und die beiden zugehörigen Container.
pod-my-pod.service
Description=Podman pod-my-pod.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=
Requires=container-container-a.service container-container-b.service
Before=container-container-a.service container-container-b.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/pod-my-pod.pid %t/pod-my-pod.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-my-pod.pid --pod-id-file %t/pod-my-pod.pod-id --name=my-pod --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-my-pod.pod-id
ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-my-pod.pod-id -t 10
ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-my-pod.pod-id
PIDFile=%t/pod-my-pod.pid
Type=forking
[Install]
WantedBy=default.target
container-container-a.service
[Unit]
Description=Podman container-container-a.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers
BindsTo=pod-my-pod.service
After=pod-my-pod.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --pod-id-file %t/pod-my-pod.pod-id --sdnotify=conmon -d --replace --name=container-a -t centos top
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all
[Install]
WantedBy=default.target
container-container-b.service
[Unit]
Description=Podman container-container-b.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers
BindsTo=pod-my-pod.service
After=pod-my-pod.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --pod-id-file %t/pod-my-pod.pod-id --sdnotify=conmon -d --replace --name=container-b -t centos top
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all
[Install]
WantedBy=default.target