Kleinere Images gegen verlorenes Layer-Caching abwaegen
Der --squash Build-Flag fasst alle Layer eines Images zu einem einzigen zusammen und schafft damit kleinere, aufgeraeumte Images, kostet dabei aber das Layer-Caching zwischen Builds, das viele CI-Pipelines beschleunigt.
Inhaltsverzeichnis
- 1. Warum Dockerfiles mit vielen Layern entstehen
- 2. Was --squash technisch macht
- 3. Squash mit BuildKit und buildx aktivieren
- 4. Vorteil: Kleinere Images durch entfernte Zwischenstaende
- 5. Vorteil: Keine Layer-History mit sensiblen Zwischenstaenden
- 6. Nachteil: Kein Layer-Caching mehr zwischen Builds
- 7. Multi-Stage-Builds als bessere Alternative in vielen Faellen
- 8. Wann Squashing tatsaechlich die richtige Wahl ist
- 9. Entscheidungsleitfaden fuer die Praxis
- 10. Zusammenfassung
- 11. FAQ
1. Warum Dockerfiles mit vielen Layern entstehen
Jede Anweisung in einem Dockerfile, die den Dateisystemzustand veraendert (RUN, COPY, ADD), erzeugt einen eigenen Layer, der dauerhaft im Image gespeichert bleibt. Bei gewachsenen Dockerfiles mit vielen einzelnen RUN-Befehlen fuer Paketinstallation, Konfiguration und Aufraeumarbeiten summiert sich das schnell auf 20 oder mehr Layer, von denen jeder einzelne seinen eigenen Diff im Union-Filesystem hinterlaesst.
Problematisch wird das vor allem, wenn in einem fruehen Layer eine grosse Datei angelegt und in einem spaeteren Layer wieder geloescht wird, etwa ein heruntergeladenes Archiv nach dem Entpacken. Das Loeschen entfernt die Datei zwar aus der sichtbaren Dateisystemansicht, der urspruengliche Layer mit der Datei bleibt aber im Image erhalten und traegt weiterhin zur Gesamtgroesse bei, was beim reinen Betrachten der finalen Image-Groesse leicht uebersehen wird.
2. Was --squash technisch macht
Der --squash Flag weist den Docker-Daemon an, nach einem regulaeren, layer-basierten Build alle neu erzeugten Layer des Builds zu einem einzigen Layer zusammenzufassen. Technisch werden dabei alle Dateisystem-Diffs der einzelnen Build-Schritte zu einem finalen Diff gegen das Basis-Image verrechnet, sodass am Ende exakt ein neuer Layer oberhalb des Base-Image-Layers entsteht.
Wichtig dabei: Nur die Layer, die waehrend dieses Builds neu entstanden sind, werden zusammengefasst, der Base-Image-Layer selbst bleibt als eigener Layer erhalten und wird nicht mit hineingerechnet. Dateien, die in einem fruehen Build-Schritt angelegt und in einem spaeteren wieder geloescht wurden, tauchen im finalen gesquashten Layer gar nicht mehr auf, weil nur der Endzustand des Dateisystems relevant ist.
3. Squash mit BuildKit und buildx aktivieren
Historisch war --squash ein experimentelles Feature des klassischen Docker-Builders und musste per experimental: true in der daemon.json freigeschaltet werden. Mit dem heute standardmaessig aktiven BuildKit-Builder ist die Situation etwas anders: Ueber docker buildx build steht --squash ebenfalls zur Verfuegung, teils weiterhin als experimentelle Option je nach Docker-Version, sodass ein Blick in die aktuelle Dokumentation der eigenen Docker-Version sinnvoll ist.
In der Praxis reicht meist ein einfacher Aufruf, der sich problemlos in bestehende Build-Skripte oder CI-Jobs einbauen laesst, ohne dass sich am restlichen Dockerfile etwas aendern muss. Der Build selbst dauert dabei laenger als ein normaler Build, weil zusaetzlich zum eigentlichen Bauen der Layer noch der Squash-Schritt als Nachbearbeitung erfolgt.
# Build mit Squash ueber den klassischen Builder
docker build --squash -t myapp:squashed .
# Build mit Squash ueber buildx (BuildKit)
docker buildx build --squash -t myapp:squashed --load .
# Layer-Anzahl vor und nach dem Squash vergleichen
docker history myapp:latest | wc -l
docker history myapp:squashed | wc -l
4. Vorteil: Kleinere Images durch entfernte Zwischenstaende
Der offensichtlichste Vorteil zeigt sich bei Dockerfiles, die grosse temporaere Dateien anlegen und wieder loeschen, ohne dass dies in einem einzigen RUN-Befehl mit anschliessendem rm im selben Layer geschieht. Ein Beispiel ist ein Build-Schritt, der Quellcode kompiliert und Build-Artefakte von mehreren hundert Megabyte hinterlaesst, die in einem spaeteren Schritt entfernt werden, weil nur die kompilierten Binaries im finalen Image gebraucht werden.
In solchen Faellen kann Squashing die Image-Groesse um mehrere hundert Megabyte bis in den Gigabyte-Bereich reduzieren, je nachdem wie gross die zwischenzeitlich angelegten und wieder geloeschten Dateien waren. Bei sauber geschriebenen Dockerfiles, die solche Zwischenstaende bereits ueber Multi-Stage-Builds vermeiden, faellt der Effekt dagegen deutlich geringer aus, weil es kaum noch etwas zum Zusammenfassen gibt.
5. Vorteil: Keine Layer-History mit sensiblen Zwischenstaenden
Ueber docker history oder durch Extrahieren einzelner Layer mit docker save laesst sich bei einem nicht gesquashten Image jeder Zwischenschritt nachvollziehen, einschliesslich Dateien, die in einem spaeteren Layer wieder entfernt wurden. Wird versehentlich in einem fruehen RUN-Befehl eine Zugangsdatei oder ein API-Key angelegt und erst in einem spaeteren Schritt geloescht, bleibt dieser Wert im urspruenglichen Layer fuer jeden mit Zugriff auf das Image extrahierbar.
Ein gesquashtes Image reduziert dieses Risiko, weil nur der finale Dateisystemzustand als einzelner Layer erhalten bleibt und Zwischenschritte nicht mehr rekonstruierbar sind. Das ist aber kein Ersatz fuer korrekte Secret-Handhabung ueber BuildKit-Secrets oder Multi-Stage-Builds, sondern bestenfalls eine zusaetzliche Absicherung gegen versehentliche Fehler in der Build-Logik, keine grundsaetzliche Loesung fuer den Umgang mit Geheimnissen im Build.
6. Nachteil: Kein Layer-Caching mehr zwischen Builds
Der zentrale Nachteil von --squash ist der Verlust des inkrementellen Layer-Caches zwischen aufeinanderfolgenden Builds. Normalerweise erkennt Docker anhand unveraenderter Dockerfile-Anweisungen und Build-Kontexte, welche Layer aus dem lokalen Cache oder aus der Registry wiederverwendet werden koennen, was Builds mit nur kleinen Codeaenderungen von Minuten auf Sekunden verkuerzt.
Da ein gesquashtes Image aus Docker-Sicht nur noch einen einzigen Layer oberhalb des Base-Image besitzt, gibt es fuer nachfolgende Builds nichts mehr, worauf granular aufgesetzt werden koennte. Jede noch so kleine Codeaenderung fuehrt effektiv dazu, dass der komplette Build-Prozess von vorne durchlaeuft, was insbesondere in CI-Pipelines mit haeufigen Commits die Build-Zeiten spuerbar verlaengert.
7. Multi-Stage-Builds als bessere Alternative in vielen Faellen
Fuer die meisten Anwendungsfaelle, in denen Squashing wegen grosser Zwischenartefakte in Erwaegung gezogen wird, ist ein Multi-Stage-Build die sauberere Loesung. Build-Abhaengigkeiten, Compiler und temporaere Artefakte landen in einer separaten Build-Stage, aus der am Ende nur die tatsaechlich benoetigten Dateien in eine schlanke Runtime-Stage kopiert werden, ohne dass Zwischenschritte jemals im finalen Image landen.
Der entscheidende Unterschied zu --squash ist, dass Multi-Stage-Builds das Layer-Caching innerhalb jeder einzelnen Stage vollstaendig erhalten. Aendert sich nur der Anwendungscode, nicht aber die Build-Abhaengigkeiten, greift der Cache fuer die Installationsschritte weiterhin, waehrend gleichzeitig ein ebenso schlankes finales Image entsteht wie mit Squashing, nur eben ohne dessen Cache-Nachteil.
# Dockerfile mit Multi-Stage-Build statt Squash
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]
8. Wann Squashing tatsaechlich die richtige Wahl ist
Squashing bleibt sinnvoll bei finalen Release-Images, die nur noch einmal gebaut und danach unveraendert in vielen Umgebungen verteilt werden, etwa fertige Basis-Images fuer interne Teams oder Distributions-Images, bei denen die Registry-Groesse und Pull-Zeit wichtiger sind als schnelle Wiederholungs-Builds. Auch bei Images, die aus Legacy-Dockerfiles entstehen, die nicht ohne weiteres auf Multi-Stage umgeschrieben werden koennen, ist Squashing eine pragmatische Zwischenloesung.
Nicht sinnvoll ist Squashing dagegen in aktiven Entwicklungs- oder CI-Pipelines mit haeufigen Rebuilds, wo der Verlust des Layer-Caches die Build-Zeiten spuerbar erhoeht und den eigentlichen Zweck schneller Feedback-Zyklen untergraebt. Hier ueberwiegt der Nachteil des fehlenden Caches fast immer den Vorteil der kleineren Image-Groesse.
9. Entscheidungsleitfaden fuer die Praxis
Die Faustregel lautet: Erst pruefen, ob ein Multi-Stage-Build das eigentliche Problem loest, das Zwischenstaende im finalen Image landen. In den allermeisten Faellen ist das moeglich und die deutlich bessere Wahl, weil Caching und kleine Images kein Widerspruch sind. Squashing bleibt danach als gezieltes Werkzeug fuer die verbleibenden Randfaelle wie einmalige Release-Builds oder Legacy-Dockerfiles, die sich kurzfristig nicht umstrukturieren lassen.
Wer beide Ansaetze kombinieren will, kann auch einen Multi-Stage-Build zusaetzlich mit --squash fahren, verliert dann aber trotzdem das Caching fuer den finalen Build-Lauf. In der Praxis lohnt sich diese Kombination selten, weil ein sauberer Multi-Stage-Build meist bereits die gewuenschte Image-Groesse ohne Squashing erreicht.
| Ansatz | Layer-Caching | Image-Groesse | Typischer Einsatz |
|---|---|---|---|
| Normaler Build | Vollstaendig erhalten | Groesser bei vielen Zwischenstaenden | Aktive Entwicklung, haeufige Rebuilds |
| --squash | Verloren fuer nachfolgende Builds | Deutlich kleiner bei grossen Zwischenstaenden | Finale Release-Images, Legacy-Dockerfiles |
| Multi-Stage-Build | Vollstaendig erhalten pro Stage | Klein durch selektives Kopieren | Empfohlener Standardansatz |
| Multi-Stage + --squash | Verloren fuer finalen Lauf | Minimal | Seltene Spezialfaelle |
Mironsoft
Container-Infrastruktur, CI-Pipelines und Deployment-Automatisierung
Docker-Setups, die im Team und in Produktion tragfähig bleiben?
Wir prüfen bestehende Dockerfiles und Compose-Stacks auf Sicherheitslücken, aufgeblähte Images und fragile Build-Pipelines und bauen daraus eine Container-Infrastruktur, die schnell baut, sicher läuft und im Team nachvollziehbar bleibt.
Dockerfile-Review
Multi-Stage-Builds, Layer-Caching und Image-Größe systematisch optimieren.
Security-Audit
Container-Isolation, Secrets-Handling und Image-Scanning gegen echte Angriffsflächen absichern.
CI/CD-Integration
Build-Pipelines, Registries und Deployment-Strategien für reproduzierbare Releases aufbauen.
10. Zusammenfassung
Layer Squash: Das Wichtigste auf einen Blick
Funktionsweise
--squash fasst alle neu erzeugten Build-Layer zu einem einzigen Layer zusammen.
Vorteil
Kleinere Images, keine rekonstruierbare Historie geloeschter Zwischenstaende.
Nachteil
Layer-Caching zwischen Builds geht fuer den Squash-Layer verloren.
Empfehlung
Multi-Stage-Builds meist vorziehen, Squash gezielt fuer Release-Images.