Kleiner Aha-Moment aus dem Homelab: beim Testen der Automatisierung aus dem letzten podman-Artikel ist mir aufgefallen, dass ein Container plötzlich mit einem neueren Image lief – obwohl ich gar kein auto-update ausgelöst hatte. Weder von Hand noch per Timer. Wie kann das sein? Schauen wir uns das mal an, denn dahinter steckt kein Bug, sondern ein podman kube play-Verhalten, das man kennen sollte.
Container-Neustart ist nicht gleich Service-Neustart
Der Schlüssel liegt darin, was da eigentlich neu startet. Zwei Fälle, zwei völlig unterschiedliche Ergebnisse:
Fall 1: der Container startet neu. Also ein podman restart, ein Absturz mit anschließender restartPolicy, ein gestorbener Prozess im Container. Hier passiert – nichts. Der Container existiert bereits und hängt fest an seiner Image-ID. podman startet schlicht denselben Container wieder an, die Registry wird nicht einmal angefasst.
Fall 2: der systemd-Service startet neu. Und damit auch: der Host bootet. Läuft der pod wie im letzten Artikel als Quadlet-Unit, ruft ein systemctl --user restart mypod.service unter der Haube ein frisches podman kube play auf. Der pod wird also nicht einfach wieder angestartet, sondern neu erstellt – und dabei wertet podman die Pull-Policy aus.
:latest heißt bei kube play: nachschauen und ziehen
Und genau da war mein „Geister-Update“ zu Hause. Die podman-Doku zu kube play sagt es ganz trocken: wird der :latest-Tag verwendet, versucht podman, das Image aus der Registry zu ziehen (einzige Ausnahme: lokal gebaute Images mit localhost-Domain). podman folgt hier der Kubernetes-Logik: ohne explizit gesetzte imagePullPolicy gilt bei :latest automatisch Always, bei jedem anderen Tag dagegen IfNotPresent.
Always klingt dramatischer als es ist: podman fragt bei der Registry nach, löst den Tag zum Digest auf und lädt nur, was lokal fehlt. Ist das Image aktuell, passiert nichts weiter. Gibt es aber ein neueres – zack, wird es gezogen und der pod startet damit. In meinem Fall fiel der Service-Neustart zufällig mit einem frischen Image in der Registry zusammen, und schon lief der Container aktualisiert. Ganz ohne auto-update.
Kurz gesagt: das Update kam nicht vom auto-update-Timer, sondern vom kube play selbst. Jeder Service-Neustart mit :latest ist potenziell auch ein Update.
Neustart-Updates abschalten: IfNotPresent
Wer dieses Verhalten nicht möchte – etwa weil Updates kontrolliert nur über podman auto-update laufen sollen, mit Rollback und zu planbarer Zeit – setzt die Pull-Policy in der yaml einfach explizit:
spec:
containers:
- name: libretranslate
image: docker.io/libretranslate/libretranslate:latest
imagePullPolicy: IfNotPresent
Mit IfNotPresent zieht kube play nur noch, wenn das Image lokal gar nicht vorhanden ist. Ein Service-Neustart oder Reboot startet dann verlässlich mit dem Image, das schon da ist – und das Aktualisieren bleibt allein Sache des auto-update-Timers. So gibt es genau einen Weg, auf dem neue Images ins System kommen, statt zwei, von denen einer zufällig zuschlägt.
Übrigens der Vollständigkeit halber: bei einem fest gepinnten Tag wie :1.5.2 stellt sich die Frage gar nicht erst – da gilt ohnehin IfNotPresent, und ein Neustart zieht nie. Dafür greift dann aber auch das auto-update nur, wenn sich hinter genau diesem Tag etwas ändert.
Schnell nachprüfen
Ob der eigene Service beim Neustart zieht, verrät ein Blick ins Journal direkt nach einem Restart:
systemctl --user restart mypod.service
journalctl --user -u mypod.service -n 30
Taucht dort ein „Trying to pull …“ auf, ist der Fall klar. Unterm Strich: :latest plus Service-Neustart ist ein verstecktes Update – wer es kontrolliert mag, setzt imagePullPolicy: IfNotPresent und überlässt das Ziehen dem auto-update. Dann gibt es auch keine Geister-Updates mehr.