Layer-Cache gezielt nutzen - Docker-Builds beschleunigen

Layer-Cache gezielt nutzen - Docker-Builds beschleunigen

Der Layer-Cache ist einer der größten Vorteile von Docker-Builds. Wer das Dockerfile falsch strukturiert, verliert ihn bei jeder Änderung — und wartet unnötig.

Wie der Cache funktioniert

Docker prüft beim Build jeden Layer: Hat sich die Instruktion oder ihr Input seit dem letzten Build verändert? Wenn nein, wird der gecachte Layer wiederverwendet. Wenn ja, wird der Layer neu gebaut — und alle folgenden Layer ebenfalls, egal ob sie sich geändert haben oder nicht.

Layer 1: FROM node:20-slim         → Cache HIT
Layer 2: COPY package*.json .      → Cache HIT (package.json unverändert)
Layer 3: RUN npm ci                → Cache HIT (Dependencies unverändert)
Layer 4: COPY . .                  → Cache MISS (Quellcode geändert)
Layer 5: RUN npm run build         → neu gebaut (wegen Layer 4)

Das wichtigste Prinzip: stabile Dinge zuerst

Alles, was sich selten ändert, gehört früh ins Dockerfile. Alles, was sich häufig ändert (Quellcode), kommt ans Ende.

# Schlecht: Quellcode wird zuerst kopiert
FROM node:20-slim
WORKDIR /app
COPY . .                    # Quellcode-Änderung invalidiert alles danach
RUN npm ci                  # npm install läuft bei JEDER Code-Änderung neu
RUN npm run build

# Richtig: Dependencies zuerst, Quellcode zuletzt
FROM node:20-slim
WORKDIR /app
COPY package.json package-lock.json ./   # nur wenn package.json sich ändert
RUN npm ci                               # gecacht solange package.json gleich bleibt
COPY . .                                 # Code-Änderungen hier — npm ci bleibt cached
RUN npm run build

Mit der richtigen Reihenfolge dauert ein Build nach einer Code-Änderung Sekunden statt Minuten.

Der package.json-Trick für Python

Dasselbe Muster gilt für Python:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .       # nur wenn requirements.txt sich ändert
RUN pip install -r requirements.txt   # gecacht
COPY . .                      # Code-Änderungen invalidieren ab hier

Systemabhängigkeiten vor App-Code

FROM python:3.12-slim
# System-Pakete: ändert sich selten → früh rein
RUN apt-get update \
    && apt-get install -y --no-install-recommends libpq-dev \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install -r requirements.txt

# Quellcode: ändert sich oft → ganz am Ende
COPY . .

Cache deaktivieren

Manchmal will man einen frischen Build ohne Cache — z. B. wenn man sicherstellen muss, dass apt-get update die aktuellen Paketlisten holt:

docker build --no-cache -t myapp .

Cache für Remote-Builds teilen

Bei CI/CD-Pipelines (GitHub Actions, GitLab CI) gibt es keinen lokalen Layer-Cache zwischen Runs. Lösung: Registry als Cache nutzen:

docker buildx build \
  --cache-from type=registry,ref=myregistry/myapp:cache \
  --cache-to type=registry,ref=myregistry/myapp:cache,mode=max \
  -t myregistry/myapp:latest .