“RunRoot is pointing to a path (/run/user/1000/containers) which is not writable. Most likely podman will fail.”
Manchmal ist es zum Mäusemelken, Informatiker zu sein.
Ich arbeite gerade an etwas.
Server basteln, Dienste hochziehen.
Und ich kann es nicht nur nicht leiden, sondern halte es für mangelnde Qualität, so etwas von Hand zusammenzufummeln. Deshalb mache ich so etwas grundsätzlich per Puppet oder Ansible. Das ist zwar zunächst deutlich mehr Aufwand, die Installation nicht manuell zu machen, sondern als eine Art Programm oder Regelsatz zu schreiben, aber es hat einfach so enorm große Vorteile, dass sich jede Diskussion erübrigt:
- Es ist reproduzierbar – man kann es jederzeit wiederholen.
- Es ist skalierbar – man kann es auf beliebig vielen Maschinen identisch wiederholen.
- Es ist versionierbar – man kann den Code in ein Repository einchecken (GIT eben) und damit alle Änderungen nachvollziehen oder zu alten Versionen zurückkehren.
- Es ist sicherer – man kann im Zweifel den Server einfach löschen und sofort neu und automatisiert hochziehen.
- Es ist verfügbarer – wenn der Server, wie und warum auch immer, abbrennt, kann man ihn ruckzuck neu erzeugen.
- Es ist fehlerärmer – man verwendet Variablen für alle Werte, und wen man sie ändert, ändern sie sich überall.
- Es ist dokumentieriger – selbst dann, wenn man es nicht kommentiert, hat man über den Code zumindest formal niedergeschrieben, was man da eigentlich getrieben hat.
- Es ist entwickliger – man kann den Code zumindest auf einer Entwicklungsmaschine entwickeln und auf Testmaschinen testen, bevor man produktiv geht.
- Es ist sauberer – man springt beim Installieren erfahrungsgemäß zwischen verschiedenen Teilen der Installation hin- und her. Schreibt man es aber als Code, ist das sauber organisiert und getrennt.
- Es ist merkiger – Ich wüsste nach einer Woche nicht mehr vollständig und fehlerfrei reproduzierbar, welche Details ich da alle eingebaut habe. Eigentlich könnte ich schon heute nicht mehr wirklich fehlerfrei und vollständig aufzählen, was ich gestern alles getrieben habe und auf welches Syntax- und Funktionsdetails ich speziell abgehoben habe, welche Optionen und Einzelheiten ich aus den Man-Seiten herausgefummelt habe.
Kurz gesagt: Es ist einfach viel, viel besser und Stand der Technik und des Könnens, das in irgendeinem der Installations- und Provisionierungstools zu schreiben (es gibt auch noch Chef und Salt, aber die kenne ich nicht näher.)
Also habe ich gestern und vorgestern – und schon mal vor über einem Monat – an einem Server gebaut, und finde das auch wunderbar, wenn man die Schritte alle sauber aufschreibt und immer dann, wenn man einen Schritt getan hat, der sauber funktioniert, zwischendurch „einzuchecken“, damit das nicht mehr verloren geht. Und gerade dann, wenn man seine Arbeit zwischendurch mal einen Monat unterbricht, und man da gedanklich wieder raus war, kann man da einfach nachlesen, was man schon gemacht hat, und was als letztes. Und was man als TODO und als FIXME reingeschrieben hat.
Also habe ich gestern abend wieder viel dran gemacht, kam gut voran, und so bis vier Uhr morgens habe ich einiges gut hinbekommen, läuft alles sauber und zuverlässig, aber noch nicht ganz fertig. Läuft. Grün. Eingecheckt. Zufrieden. Ins Bett gelegt.
Aber, ach.
Heute wollte ich dran weiter schreiben.
Geht nicht mehr.
In einer der beiden tasklist, an denen ich vergangene Nacht geschrieben habe, und die bis heute morgen um vier einwandfrei funktionierten, funktionierten nur noch die ersten drei, gewöhnlichen Tasks, und dann kommt es zu einer Fehlermeldung. Ein Task geht nicht mehr, aber die Fehlermeldung gibt nichts her.
Warum, zum Henker, ging das gestern, und heute nicht mehr?
Seht Ihr, auch das ist ein Grund, zu versionieren, einzuchecken. Es kann einem immer mal passieren, dass man versehentlich irgendwo durch einen Schreibfehler oder weil man an eine Taste kommt, unabsichtlich irgendwas ändert. Dafür gibt es das Versionierungstool, und ein einfacher Befehl wie git diff zeigt einem sofort, welche Dateien man geändert hat, und worin die Änderungen bestehen. Ruckzuck ist der Fehler gefunden.
Dumm daran: git diff zeigt, dass ich gar nichts geändert habe. Der Code ist derselbe. Warum tat das gestern und heute nicht mehr?
Also debuggen, gucken, suchen, eingrenzen.
Es geht darum, einen Docker-Container laufen zu lassen. Mit Podman. Und Quadlets. Und so. Eigentlich zwar nicht ganz, aber weitgehend einfach, zumal Ansible eigene Module zum Betüddeln von Podman hat, weshalb ich da gestern auch recht gut durchkam. Hat ja auch funktioniert.
Aus Sicherheitsgründen wird ja dringend empfohlen, Dienste, die nicht unbedingt root-Rechte brauchen, unter Podman als rootless laufen zu lassen, als ein anderer Benutzer. Und weil der Hauptbenutzer, der sich einloggt, auch auf die Dateien zugreifen können muss, haben ich einfach diesen, UID 1000, als den Benutzer auserkoren, der den Container laufen lassen soll, und das bei der Gelegenheit auch gleich per systemd socket activation, damit der nur läuft, wenn man ihn auch braucht.
Dazu hatte ich in die jeweiligen Ansible-Tasks, die als Benutzer laufen müssen, become_user: ... und become: true reingeschrieben. Das hat gestern noch einwandfrei funktioniert. Und damit verschiedene Podman-Befehle ausgeführt:
- pull image
- build image
- tag image
- prune images
- quadlets anlegen
- socket unit anlegen
Natürlich alles im user-scope, nicht im system-scope.
Hat gestern einwandfrei funktioniert.
Heute bricht es mit unklarer Fehlermeldung ab. Ansible könnte sich nicht mehr per ssh einloggen. Quatsch, kann es.
Kurioserweise funktioniert Ansible, wenn ich denselben Task manuell und einzeln per ansible statt ansible-playbook ausführe.
Das hat mich jetzt einige Zeit gekostet, das zu debuggen. Erstaunlicherweise hat es nicht einmal mehr funktioniert, wenn ich den Code durch
- command:
chdir: /home/{{ benutzer }}
cmd: /usr/bin/podman pull {{ image }}
ersetzt habe, obwohl der Befehl manuell tadellos funktionierte, dort und auf anderen Rechnern. Aber das hat mich dann auf die richtige Lösung gebracht. Und wenn ich das ganz weg lasse, dann scheitert der nächste Podman-Befehl, der das Image baut, genauso. Gestern ging es noch.
Man findet aber sowohl da, auch in straces, die Fehlermeldung, die schlussendlich Erkenntnis verschafft:
“RunRoot is pointing to a path (/run/user/1000/containers) which is not writable. Most likely podman will fail.”
Das ist nämlich der springende Punkt.
Wenn man podman als root ausführt, macht podman einige Dinge in /run/. Macht man es aber rootless, als anderer Benutzer, treibt er es in /run/user/UID/containers. Und dieses Verzeichnis existiert nur, wenn der Benutzer aus Sicht von systemd gerade eingeloggt ist, weil systemd dann feierlich eine session eröffnet und /run/user/UID anlegt. Und wieder abreißt, wenn er sich ausloggt.
Vergangene Nacht nun hatte ich verschiedene Sitzungen auf der Maschine offen. Als root. Und als jener Benutzer mit UID 1000. Also existierte /run/user/UID/containers, und podman funktionierte einwandfrei.
Heute dagegen wollte ich erst einmal nur eine Kleinigkeit am Ansible-Code ändern und ihn laufen lassen, war aber nicht als der Benutzer eingeloggt. Deshalb hatte der systemd keine Sitzung für diesen Benutzer angelegt und /run/user/1000 nicht erzeugt.
Als ich nun ansible laufen ließ, hat sich ansible, weil von mir so geschrieben, als root eingeloggt, eine session für root angelegt, und sich dann nur für einzelne Tasks per su bzw. setuid in den Benutzer verwandelt, ohne aber beim systemd eine Sitzung anlegen zu lassen. Und dann funktioniert podman (zumindest diese Version) eben nicht.
Kaum hatte ich mich als Benutzer wieder eingeloggt, ging auch die Installation mit Ansible wieder – genau wie vergangene Nacht gegen vier Uhr.
Und tatsächlich: Auch vergangene Nacht hatte es einmal nicht funktioniert, als ich mich mal kurz ausgeloggt hatte, aber den Zusammenhang hatte ich nicht bemerkt. Ich dachte, das docker repo wäre aus Netzwerkproblem mal kurz nicht erreichbar gewesen, weil es gleich darauf ja auch wieder ging – ich war wieder eingeloggt.
Und dieser Scheiß hat mich gerade – allerdings mit Unterbrechungen und zwischendurch Abendessen, was man abziehen müsste – über drei Stunden gekostet, bis das eingekreist und verstanden war. Auch weil in der ursprünglichen Konfiguration diese Fehlermeldung nicht zu sehen war.
Und mit so etwas verbrät man dann seine Arbeits-, Frei- und Lebenszeit.
Aber wenigstens ist man hinterher schlauer als vorher.