Container-Images patchen: der Rückstand steckt im frischen Pull

08.08.2026

Thema: alle Beiträge zu Docker

Ein frisch gezogenes nginx-Image bringt 33 veraltete Pakete mit, 15 davon mit Sicherheitsaktualisierung. Wie du den Rückstand in einem Kommando misst und was das Nachpatchen wirklich kostet.

Inhaltsverzeichnis

Auf LinkedIn lief dieser Tage eine Liste von Fragen an ein Betriebssystem, die ich sofort unterschreibe: Können wir vorhersagbar patchen? Können wir sauber automatisieren? Können wir beobachten, was passiert? Können wir ohne Heldentaten wiederherstellen? Können wir das Risiko gegenüber Auditoren und Kunden erklären? Genau deshalb ist Linux dort Standard, wo Ausfälle teuer sind, und nicht, weil es Geschmackssache wäre.

Die erste dieser Fragen wird interessant, sobald die Anwendung im Container läuft. Denn dort verschwindet der Mechanismus, der sie auf einer VM beantwortet.

Die Antwort vorweg: Im Container ist Patchen keine Laufzeiteigenschaft mehr, sondern eine Eigenschaft des Images und damit deiner Bau-Kadenz. Ein frisch gezogenes Image kann am Tag des Pulls bereits Dutzende veraltete Pakete mitbringen, und du kannst diese Zahl in einem Kommando bestimmen, ohne Scanner und ohne CVE-Datenbank.

Warum die Frage im Container anders steht

Auf einer VM läuft unattended-upgrades nachts, holt die Sicherheitsaktualisierungen aus dem Repository der Distribution und tauscht die Pakete im laufenden System. Vorhersagbares Patchen ist dort ein Dienst, der tickt.

In einem Container läuft dieser Dienst nicht, und das ist kein Versäumnis, sondern Absicht. Ein Container ist nur ein Prozess, sein Dateisystem soll sich nicht selbst verändern, und ein Neustart wirft jede Änderung weg. Was im Image liegt, bleibt liegen, bis jemand ein neues Image baut und ausrollt.

Damit wandert die Frage von der Laufzeit in die Lieferkette. Sie verschwindet nicht, sie hat nur eine andere Adresse: Wie alt sind die Pakete in dem Image, das gerade produktiv läuft?

Die Messung

Ein einziges Kommando, ausgeführt im Image selbst. Die Paketverwaltung vergleicht die installierten Versionen mit dem, was die Distribution aktuell ausliefert:

docker run --rm nginx:1.29 sh -c \
  'apt-get update -qq >/dev/null 2>&1; apt list --upgradable'

Was hier gemessen wird, ist ausdrücklich kein Schwachstellen-Scan. Es gibt keine CVE-Datenbank, keine Bewertung, keine Severity. Die Frage ist schlicht: Gibt es für ein installiertes Paket bereits eine neuere Version im Repository der Distribution?

Das Ergebnis

Alle Images am 3. August 2026 frisch gezogen, jeweils linux/amd64:

Image gebaut am Pakete davon veraltet
debian:13-slim 2026-07-13 78 0
python:3.13-slim 2026-07-14 87 0
postgres:17 2026-07-16 142 0
node:22-slim 2026-07-29 88 0
alpine:3.22 2026-06-22 16 0
ubuntu:26.04 2026-07-13 87 10
ubuntu:24.04 2026-06-22 92 14
eclipse-temurin:21-jre 2026-07-16 140 20
nginx:1.29 2026-05-08 151 33

Die gute Nachricht steht oben: Der Normalfall ist sauber. Die offiziellen Debian-Images und die darauf aufsetzenden Sprach- und Datenbank-Images werden häufig genug neu gebaut, dass beim Pull nichts fehlt. Alpine ebenso, bei ausgesprochen kleiner Angriffsfläche von 16 Paketen.

Die interessante Zeile ist nginx:1.29. Ein Image, das in sehr vielen Clustern läuft, bringt beim Pull 33 veraltete Pakete mit. Davon stammen 15 aus der Security-Suite, es liegen also ausdrücklich Sicherheitsaktualisierungen bereit. Die Namen sind nicht die Randlage:

openssl  libssl3t64  libgnutls30t64  libc6  libc-bin  bash  sed
libxml2  libcurl4t64  libnghttp2-14  libssh2-1t64  libexpat1  liblzma5
libgcrypt20  libkrb5-3  libtiff6  libpng16-16t64  libsystemd0  tzdata …

Das Alter des Images erklärt es nicht

Der naheliegende Schluss wäre, dass alte Images einen Rückstand haben und neue nicht. Zwei Zeilen der Tabelle widerlegen ihn: postgres:17 und eclipse-temurin:21-jre sind beide am 16. Juli 2026 gebaut. Das eine hat null veraltete Pakete, das andere zwanzig.

Der Unterschied liegt in der Linie, auf der sie aufsetzen. Ein Blick in beide Images:

docker run --rm postgres:17 sh -c '. /etc/os-release; echo $PRETTY_NAME'
# Debian GNU/Linux 13 (trixie)

docker run --rm eclipse-temurin:21-jre sh -c '. /etc/os-release; echo $PRETTY_NAME'
# Ubuntu 26.04 LTS

Das Muster in der Tabelle folgt genau dieser Trennung: Die Debian-Linien stehen auf null, die Ubuntu-Linien nicht. ubuntu:26.04 bringt selbst schon 10 veraltete Pakete mit, und eclipse-temurin:21-jre setzt darauf auf und liegt bei 20. Der Rückstand der Basis ist damit eine Eigenschaft, die du mit FROM übernimmst, ohne sie zu sehen und ohne sie zu kontrollieren.

Bei nginx:1.29 kommt der eigene Takt dazu. Die Basis ist hier Debian, also sauber, aber das Image wird gebaut, wenn nginx eine Version veröffentlicht, und nicht, wenn Debian ein Sicherheitspaket nachschiebt. Drei Monate ohne nginx-Release sind drei Monate ohne Paketstand.

Nebenbei ist das ein Argument gegen die verbreitete Sortierung „Alpine ist sicherer als Debian”. Beide Distributionen liefern hier sauber ab. Was den Unterschied macht, ist nicht die Distribution, sondern wie oft das konkrete Image neu gebaut wird.

Warum das kein Scanner-Thema ist

Diese Zahl ist etwas anderes als ein CVE-Bericht, und beide beantworten verschiedene Fragen.

Ein Scanner beantwortet: Welche bekannten Schwachstellen stecken in diesen Paketversionen? Diese Antwort hängt an der gewählten Datenbank, weshalb dasselbe Image je nach Werkzeug 236 oder 474 CVEs hat und je nach Quelle die EUVD gar nicht vorkommt.

Die Messung hier beantwortet: Welche Korrekturen liegen bereit und sind noch nicht bei mir angekommen? Dafür braucht es keine Bewertung durch Dritte. Es zählt, was die Distribution selbst als aktuellen Stand ausliefert, inklusive der stillen Korrekturen ohne CVE-Nummer.

Für ein Audit ist die zweite Zahl oft die unangenehmere, weil sie sich nicht wegdiskutieren lässt. Ein Fix war verfügbar, er wurde nicht eingebaut, und der Nachweis ist ein Einzeiler.

Der Reflex und sein Preis

Wer den Rückstand entdeckt, hängt typischerweise eine Zeile ins Dockerfile:

FROM nginx:1.29
RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*

Das funktioniert, die Messung im Ergebnis meldet null veraltete Pakete. Es kostet aber mehr, als es aussieht:

nginx:1.29        62,9 MB
nginx-gepatcht    79,8 MB   (+27 %)

Der Zuwachs ist kein Zufall. Ein Image-Layer löscht nichts, er verdeckt nur. Beim Auspacken des gebauten Images liegt dieselbe Bibliothek zweimal darin:

Layer 1: usr/lib/x86_64-linux-gnu/libssl.so.3   sha256 85ed1546d2848ca2
Layer 8: usr/lib/x86_64-linux-gnu/libssl.so.3   sha256 caac96cbdee92283

Zwei verschiedene Prüfsummen, zwei verschiedene Paketstände:

nginx:1.29        libssl3t64  3.5.5-1~deb13u2
nginx-gepatcht    libssl3t64  3.5.6-1~deb13u2

Der Prozess im Container benutzt die neue Fassung, das ist richtig. Die alte wird trotzdem bei jedem Pull mit übertragen und liegt auf jedem Knoten im Cluster auf der Platte. Ein Scanner, der das fertige Dateisystem betrachtet, meldet sie nicht mehr. Weg ist sie nicht.

Als Notpflaster ist das in Ordnung, wenn morgen ein Fix nötig ist und die Basis noch nicht neu gebaut wurde. Als Dauerlösung ist es der teure Weg: Das Image wächst mit jedem Zyklus weiter, und die Historie der ersetzten Binärdateien wandert mit.

Der langweilige Weg, der trägt

Der richtige Umgang ist keine Erfindung, sondern Kadenz:

  1. Regelmäßig neu bauen, auch ohne Codeänderung. Ein wöchentlicher Rebuild auf frischer Basis erledigt den Rückstand ohne zusätzliche Layer, weil die Pakete gar nicht erst in der alten Fassung ins Image kommen.
  2. Basis per Digest festnageln und den Digest automatisiert nachziehen. Das Pinning macht den Bau reproduzierbar, aber es friert eben auch den Rückstand ein. Erst ein Bot, der den Digest aktualisiert, macht daraus eine bewusste Entscheidung mit Datum statt eines Zufalls.
  3. Den Rückstand in der CI messen. Ein Lauf von apt list --upgradable gegen das gebaute Image kostet Sekunden und liefert eine Zahl, die man in einen Schwellenwert gießen kann. Sicherheitsaktualisierungen aus der Security-Suite eignen sich als harte Grenze.
  4. Die eigene Basis kennen. Wer auf einer Linie aufsetzt, die selten neu gebaut wird, erbt deren Takt. Das ist ein legitimes Kriterium bei der Wahl des Basis-Images, und es steht in keinem Vergleichsartikel.

Der Sonderfall ohne Paketverwaltung

Bei einem distroless-Image endet die Messung, bevor sie beginnt:

docker run --rm gcr.io/distroless/base-debian12 sh -c 'echo hi'
exec: "sh": executable file not found in $PATH

Kein apt, keine dpkg-Datenbank, keine Shell. Das ist als Härtung gewollt und wirksam, es nimmt dir aber genau die Eigenschaft, die der LinkedIn-Beitrag an Linux lobt: die saubere Paketverwaltung, aus der sich Zustand und Rückstand ablesen lassen. Was bleibt, ist die SBOM, die beim Bau erzeugt wurde. Sie ist damit kein Papierkram für den Cyber Resilience Act, sondern der einzige verbliebene Weg, die Frage überhaupt zu beantworten.

Man tauscht also nicht Sicherheit gegen Bequemlichkeit, sondern eine Eigenschaft gegen eine andere: weniger Angriffsfläche gegen weniger Auskunftsfähigkeit zur Laufzeit. Beides ist vertretbar, aber es sollte eine Entscheidung sein.

Warum diese Messung überhaupt geht

Der Einzeiler funktioniert nur, weil Debian und Ubuntu ihre Paketdatenbank offen veröffentlichen, mit Versionen, Suiten und Signaturen, abrufbar ohne Konto und ohne Vertrag. Der Vergleich zwischen „das habe ich” und „das gibt es” ist deshalb dein Vergleich und nicht der eines Anbieters.

Bei einem Basis-Image ohne offene Paketquelle bleibt an dieser Stelle die Zusage des Herstellers, dass gepatcht wurde. Das kann stimmen. Nachrechnen kannst du es nicht.

Damit hängt die erste Frage aus dem LinkedIn-Beitrag, ob vorhersagbar gepatcht werden kann, tatsächlich an beiden Säulen: am Verständnis dafür, wo im Container das Patchen stattfindet, und an offenen Werkzeugen, die dir die Gegenprobe erlauben.

Fazit

  1. Im Container ist Patchen keine Laufzeiteigenschaft. Es gibt keinen Dienst, der nachts aktualisiert, der Rückstand ist eine Eigenschaft des Images.
  2. Er ist ohne Scanner messbar: apt list --upgradable im Image, für Alpine apk list --upgradable.
  3. Gemessen am 3. August 2026 bringt ein frisch gezogenes nginx:1.29 33 veraltete Pakete mit, 15 davon mit Sicherheitsaktualisierung, darunter openssl, glibc und bash.
  4. Das Alter erklärt es nicht. postgres:17 und eclipse-temurin:21-jre sind am selben Tag gebaut und liegen bei 0 gegen 20. Entscheidend ist die Rebuild-Kadenz der Linie, die du mit FROM erbst.
  5. Ein nachgeschobenes apt-get upgrade schließt die Lücke, kostet hier aber 27 Prozent Größe und liefert die alte Bibliothek in einem tieferen Layer weiter mit.
  6. Der tragfähige Weg ist Kadenz: regelmäßig auf frischer Basis neu bauen, Digest per Bot nachziehen, Rückstand in der CI messen.

Die Frage aus dem LinkedIn-Beitrag bleibt damit vollständig gültig, sie hat im Container nur eine andere Adresse. Sie richtet sich nicht mehr an das Betriebssystem im laufenden Betrieb, sondern an deine Pipeline. Und dort lässt sie sich beantworten, mit einer Zahl statt mit einer Haltung.

© 2026 Trutz Software Consulting GmbH. CC BY 4.0: Dieser Text darf mit Namensnennung weiterverwendet und bearbeitet werden, auch kommerziell. Code-Beispiele darin stehen unter Apache 2.0. Ausgenommen sind Marke und Logo sowie gekennzeichnete Zitate Dritter. Was das genau heißt.

Newsletter

Erhalte praxisnahe Tutorials, Best Practices und echte Lösungen für die häufigsten DevOps-Probleme direkt in Dein Postfach.

Datenschutz: Deine E-Mail-Adresse wird DSGVO-konform in Deutschland gespeichert. Keine Spam, nur relevante Inhalte. Eine E-Mail alle 1 bis 2 Wochen.