Docker-Images automatisch updaten
Inhalt
Wozu automatische Updates?#
Software altert bzw. die Zeit streicht an ihr vorbei, sodass sie gewartet und auf Stand gehalten werden muss.
“Software ist kein Vermögenswert, sondern eine Verbindlichkeit.” - Cory Doctorow, Jan-2026
In meinem Blog habe ich schon mehrfach von Problemen wie kritischen Schwachstellen in Gitea oder in PHP berichtet, Systemabstürze beseitigt und unabsichtlich veröffentlichten Seiten wieder eingefangen, deren Ursachen allesamt durch Updates oder Rekonfiguration behoben werden konnten.
Das Betriebssystem meines Servers und die wichtigsten darauf laufenden Programme erhalten bereits automatische Updates wie in meinem server-auto-upgrade Artikel beschrieben.
Trotzdem bin ich mit dem Thema noch nicht ganz fertig.
Docker image update mit Watchtower#

- Es wird nicht mehr aktiv gewartet und befindet sich im Archivzustand. Allerdings gibt es Forks, die weitergeführt werden.
- Um zu funktionieren, benötigt es Zugriff auf den Docker Daemon per
docker.sock. Dies ist gleichbedeutend mit Root-Zugriff des Containers auf mein System. Das will ich in Zukunft unbedingt vermeiden.
1:1-Ersatz für Watchtower benötigt? Linuxhandbook hat hier ein paar Lösungen aufgelistet. Allen gemein ist allerdings, dass sie entweder nur über vorhandene Updates informieren und sie nicht ausrollen, oder dass sie selbst ebenfalls den docker.sock als Volume benötigen.
Lösung per Skript#
Auf der Suche nach einem Weg ohne das Sicherheitsrisiko docker.sock komme ich schnell zur Idee, täglich ein Skript per cron ausführen zu lassen. Dies geschieht mit root-Rechten und kann daher direkt Docker-Befehle ausführen.
Kompliziert: docker pull, Abgleich mit vorhandenen Images, bei Bedarf einspielen#
Mein erstes Skript hat 164loc (Zeilen) und tut folgendes:
- Prüfen, ob benötigte Werkzeuge
curl, docker, docker compose, docker-comppose.ymlinstalliert sind und funktionieren - Die aktuellen image digests der in der
docker-compose.ymldefinierten Services herausfinden - Die Registry für jeden Service per
docker compose pullaktualisieren - Per
docker image inspectdie “neuen” mit den “alten” image digests vergleichen - Die neuen Images per
docker compose upstarten, Logs wegspeichern - Bericht per ntfy an mich, falls Updates erfolgt sind.
Doch dieser Weg ist viel zu kompliziert gedacht. Das von mir verwendete Werkzeug docker compose bringt die benötigte Option direkt mit: docker compose up --pull always.
Einfach: Alles in einem Kommando per Option mitgeben#
Der Kern meines neuen Skriptes (61loc) sieht wie folgt aus:
compose=(docker compose --progress plain -f "$COMPOSE_FILE")
before=$("${compose[@]}" ps --all --quiet | sort)
if output=$("${compose[@]}" up -d --pull always --quiet-pull --wait \
--wait-timeout "$WAIT_TIMEOUT" 2>&1); then
status=0
else
status=$?
fi
printf '[%s] docker compose up (exit %s)\n%s\n\n' \
"$(date -Is)" "$status" "$output" >> "$CHANGELOG"
if (( status != 0 )); then
report_failure "WARNING: Docker update failed" "warning" "$output"
exit "$status"
fi
after=$("${compose[@]}" ps --all --quiet | sort)
if [[ "$before" != "$after" ]]; then
notify "INFO: Docker containers updated" "white_check_mark" "$output"
fi
Im Skript erhebe ich einen Status vor dem Update, indem alle in der Compose-Datei spezifizierten Services aufliste und in einer Variable zwischenparke. Anschließend führe ich wie üblich docker compose up -d durch, allerdings nicht ohne die Flags --pull always sowie --wait wait-timeout <time[s]> zu setzen.
Mit der Pull-Option prüft Docker die Registry auf neue Images, welche gegebenenfalls heruntergeladen und gestartet werden. Der Timeout gibt dem Befehl eine bestimmte Zeit zur Ausführung bevor es mit einer Fehlermeldung abbricht, damit sich das Skript nicht aufhängen kann.
Was folgt ist nur noch Dokumentation und Monitoring: Die Ausgabe des Befehls wird in das Changelog geschrieben, im Falle eines Fehlschlags bekomme ich eine Information per Notify wie in meinem Server-Logging Post beschrieben. Hier wird der before-Status wichtig: Ich eine Benachrichtigung nur bei Fehler oder Update.
Anschließend muss ich das Skript nur noch ausführbar machen chmod + x docker-image-update.sh und an root übergeben: chown root root docker-image-update.sh.
Eintrag für cron#
Nach einem manuellen Test des Skripts ./docker-image-update.sh, Prüfung seiner Ausgabe, des Changelogs und den neuen Containerversionen, lasse ich das Skript täglich durch den Cron-Daemon aufrufen:
schallbert@machine: crontab -e
[...]
0 2 * * * /path/to/docker-image-update.sh
Welche Version wurde installiert?#
Statt mit Versionsbezeichnungen der Services arbeitet Docker mit Image digests. Dieser sha256-hash ist für jedes Image einzigartig, aber nicht besonders leserfreundlich:
sha256:94a00394bc5a8ef503fb59db0a7d0ae9e1110866e8aee8ba40cd864cea69ea1a # example Image digest

Gitea v28.2.1 werden in den Image-Metadaten nicht standardmäßig unterstützt. Daher habe ich erstmal noch keine Lösung für die Ausgabe einer Version. Die Digests lasse ich in der Ausgabe weg.
Meldung bei Update#
Die Meldung ist verbesserungsfähig: Ich benötige eigentlich nur die Namen der Container Updates und die Bestätigung, dass alle Images danach wieder “healthy” sind. Zusätzlich erhalte ich aber die Zustände der Container, aus denen ich die benötigten Informationen erst extrahieren muss. Der Mehrwert einer Filterung erscheint mir aber derzeit zu gering, als dass ich meine Zeit in die Erweiterung des Skriptes stecken würde. Schließlich zeigt mir Recreate bereits an, welcher Container auf Stand gebracht wurde.
Ich bin zufrieden. Ich konnte vom Host aus mit wenigen Zeilen Code, aus Bordmitteln, und nur mit cron als zusätzlicher Abhängigkeit mein Updateproblem für die per Docker Compose verwalteten Container lösen.