Ansichten eines Informatikers

podman-Container rootless aus systemd heraus starten

Hadmut
17.11.2025 2:23

Mal wieder etwas aus der Linux-Welt, womit ich die letzten zwei Tage wieder etliche Stunden verbraten habe. So als Hinweis, damit es anderen nicht genauso geht.

Es geht darum, einen podman-Container auf einem Ubuntu 24.04 server system automatisiert aus systemd heraus zu starten.

Eigentlich ist das ziemlich leicht, denn dafür die systemd-Units zu schreiben oder, noch einfacher, Quadlets zu verwenden ist eigentlich eine ziemlich einfache Sache und kaum der Rede wert.

Aber, ach.

Der Teufel steckt im Detail.

Nun ist es ja so, dass nicht nur der Vorteil von podman gegenüber docker ist (bzw. war, docker hat da inzwischen auch was), dass podman-Container im Gegensatz zu docker rootless laufen können und damit ein geringeres Sicherheitsrisiko darstellen. Weshalb ja auch dringend empfohlen wird, container rootless laufen zu lassen, wenn nicht zwingende Gründe dafür sprechen, sie unter root laufen zu lassen.

Und ein weitere Unterschied ist, dass bei docker die Container von einem eigenen daemon verwaltet und gestartet werden, der sich um alles kümmert (aber selbst wieder ein Sicherheitsrisiko darstellt), während es bei podman (im Allgemeinen) keinen daemon gibt, und podman stattdessen in den systemd eingehängt wird und jeder Container, jedes Volume usw. eine eigene Unit braucht – oder als kubelet geschrieben werden muss.

Grundsätzlich ist das ja eine leichte Angelegenheit, denn es gibt systemd-units für root, und das ganze system nochmal für Benutzer. Wenn man Zeugs als Root ausführen will, schreibt man seine systemd units an die üblichen Orte wie /etc/systemd/system/.. , und wenn man sie als Benutzer ausführen will, dann entweder unter $XDG_CONFIG_DIRS/systemd/user/

Und wenn man es sich eben einfach machen will, dann schreibt man keine Units, sondern Quadlets und legt sie unter /etc/containers/systemd/ für root oder unter
/etc/containers/systemd/users/ , /etc/containers/systemd/users/$(UID) oder $XDG_CONFIG_HOME/containers/systemd/ (i.d.R = ~/.config/containers/systemd/ ) und lässt sich die Units vom Generator erstellen.

Eigentlich alles recht einfach und komfortabel.

Man sollte dazu aber auch wissen, dass Benutzer-Units normalerweise nicht immer laufen, sondern nur dann, wenn der Benutzer eingeloggt ist. Systemd verhält sich da quasi so, als würde man für den Benutzer ein persönliches Unter-Linux mit seinem eigenen systemd beim Einloggen hoch- und beim Ausloggen wieder runterfahren. Das ist oft von vorteil, aber oft eben auch von Nachteil. Deshalb kann man das mit loginctl enable-linger für einzelne oder alle Benutzer einschalten, dass die Units gleich ab boot dauernd laufen und der Benutzer nicht eingeloggt sein muss.

Jetzt wollte ich aber keinen normalen Benutzer, sondern einen Systembenutzer (uid <1000 ) dafür haben. Ich dachte, das macht keinen Unterschied, das läuft da alles genauso.

Dachte ich. Das System sagte „Denkste“.

Ich konnte nämlich als der System-Benutzer systemctl nicht aufrufen. Gab immer eine Fehlermeldung

Failed to connect to bus: No medium found

weil bei einem normalen Benutzer der benutzereigene systemd, der das alles rauf und runterfährt, beim Einlog-Vorgang (PAM) gestartet wird und sich dann um alles kümmert. Wo aber kommt der user-systemd her, wenn es beim System-user keinen einlog-Vorgang gibt? Ich dachte bis dahin, dass loginctl enable-linger dafür sorgt, dass dieser systemd ab boot läuft, war aber nicht so.

Also dachte ich, auch nach Studium der man-pages, dass das mit dem enable-linger bei system-Usern nicht läuft, weil man da gar nicht erst in den systemd am dbus kommt, um den ganzen Kram zu starten.

Das Problem ist leicht lösbar, dachte ich, dann starte ich die Unit bzw. das Quadlet eben als root und schreibe rein

User=BENUTZERNAME

mit dem system-Benutzer. Das hätte auch genau so funktioniert, wie ich mir das vorgestellt hatte, wenn mir nicht ein kleines, fieses detail zwischen gekommen wäre. Ich wollte ja unbedingt die Units per Quadlets erzeugen. Und der podman generator erzeugt daraus eine Service-Unit, die mehrmals als pid-File --cidfile=%t/%N.cid verwendet.

Und das geht schief. Denn wenn man die Unit als root startet, verwendet systemd für %t immer /run/, und kümmert sich dabei auch nicht darum, dass man mit User= einen anderen Benutzer angegeben hat, und als Environment ein anderes XDG_RUNTIME_DIR, weil der Wert für %t festgelegt wird, bevor die Unit eingelesen wird, und die den dann nicht mehr ändern kann. Braucht man ja auch, falls man einen Exec per ! oder + privileged ausführen will. Nur: podman, dass dann nicht als root läuft, hat dann keine Rechte, um nach –cidfile=%t/%N.cid , also /run/…. zu schreiben und bricht ab.

Was also tun?

Wie bekommt man das Ding geradeaus zum Laufen unter Verwendung von Quadlets, und ohne alle units selbst zu schreiben?

Bug reports aufgemacht. Weil ich annahm, dass in einem von beidem ein Denkfehler liegen muss.

Bei systemd bekam ich die produktüblichen Beschimpfungen.

Von den podman-Leuten dagegen bekam ich den entscheidenden Hinweis.

Es geht nämlich schon exakt so, wie ich mir das ursprünglich vorgestellt hatte, nur ein winziges Detail ist anders:

Ursprünglich nämlich habe ich zwar alles richtig konfiguriert, dann aber versucht, daemon-reload und start und sowas alles aus dem system-user-account mit systemctl –user … zu machen. Und das ging ja nicht, weil auf dem dbus kein systemd lief.

Der richtige Befehl lautet von root aus systemctl --machine BENUTZERNAME@ --user daemon-reload statt eben su - BENUTZERNAME systemctl --user daemon-reload, weil das Ding im linger-modus eben erst gar keinen systemd für den Benutzer startet und das anders macht, nämlich über den Haupt-systemd, und das für mich aus der man-page zu systemctl überhaupt nicht ersichtlich war, was diese Option –machine genau macht, dass man die dafür braucht und das im linger-modus anders läuft.

Jetzt ist das Problem zwar gelöst, und bis auf dieses winzige Detail habe ich ja auch von vornherein alles richtig gemacht, aber viele Stunden Arbeits- und Lebenszeit verbraten.

Dafür mal wieder die alte 80:20-Regel bewiesen. 80% der Aufgaben löst man in 20% seiner Zeit, und für die letzten 20% der Aufgaben verbrät man 80% seiner Zeit.