Warum Docker-Images so groß werden - und was dagegen hilft

Warum Docker-Images so groß werden - und was dagegen hilft

Ein 2-GB-Image für eine Node.js-App ist kein Ausnahmefall — es ist das Ergebnis von mehreren kleinen Entscheidungen, die sich addieren. Die häufigsten Ursachen und ihre Lösungen.

Ursache 1: Falsches Basis-Image

# 1.1 GB Basis — kaum jemand braucht das alles
FROM node:20

# 200 MB — deutlich besser
FROM node:20-slim

# 50 MB — für einfache Anwendungen ausreichend
FROM node:20-alpine

Das richtige Basis-Image zu wählen ist der einfachste einzelne Hebel.

Ursache 2: Paket-Cache nicht bereinigt

Nach apt-get install bleiben Paketlisten und Cache auf der Festplatte. In Docker muss das im selben RUN-Befehl passieren — sonst landet der Cache trotzdem in einem früheren Layer.

# Schlecht: Cache bleibt in Layer 2, Layer 3 löscht nur den Container-Layer
RUN apt-get update && apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# Richtig: alles in einer RUN-Instruktion
RUN apt-get update \
    && apt-get install -y --no-install-recommends curl ca-certificates \
    && rm -rf /var/lib/apt/lists/*

--no-install-recommends verhindert, dass apt empfohlene Pakete mitinstalliert.

Ursache 3: Dev-Dependencies in Produktion

# node_modules mit devDependencies: 400 MB
RUN npm install

# Nur Production-Dependencies: 80 MB
RUN npm ci --omit=dev

Oder noch besser: Multi-Stage Build (Build-Stage mit allen Dependencies, Runtime-Stage nur mit Production-Dependencies).

Ursache 4: Viele unnötige Dateien im Build-Kontext

Ohne .dockerignore landet alles im Image: .git-Verzeichnis, node_modules vom Host, Logs, temporäre Dateien.

# .dockerignore
.git
node_modules
*.log
.env
coverage
dist

Ursache 5: Zu viele RUN-Layer

Jede RUN-Instruktion, die Dateien anlegt und eine spätere sie wieder löscht, addiert trotzdem Größe — die Löschung ist im Union Filesystem ein neuer Eintrag, nicht eine echte Entfernung aus dem vorherigen Layer.

# Beide Layer bleiben — Nettogröße: groß
RUN curl -O https://example.com/bigfile.tar.gz && tar -xf bigfile.tar.gz
RUN rm bigfile.tar.gz

# Richtig: in einer Instruktion
RUN curl -O https://example.com/bigfile.tar.gz \
    && tar -xf bigfile.tar.gz \
    && rm bigfile.tar.gz

Image-Größe analysieren

# Layers und ihre Größe anzeigen
docker history myimage:latest

# Detaillierte Layer-Analyse mit dive (Tool)
dive myimage:latest

dive zeigt interaktiv, welche Dateien pro Layer existieren und wie viel Speicher belegt wird — sehr hilfreich, um den dicksten Layer zu finden.

Fazit

Die typische Reihenfolge der Maßnahmen: richtiges Basis-Image → .dockerignore → Paket-Cache in einer RUN-Instruktion bereinigen → Multi-Stage Build. Damit lässt sich die Image-Größe in den meisten Projekten um 60–90% reduzieren.