Docker-Multi-Stage-Builds Verkleinern Sie Ihr Image ohne die Bereitstellung zu stören
Ein praktischer Überblick zu mehrstufigen Docker-Builds — echte Vor- und Nachbildgrößen, funktionierende Dockerfile-Beispiele für Node.js und Python, und die Fehlerquellen, die jedes Team mindestens einmal trifft.
Ihre Node.js-Image beträgt 1,1 GB. Sie haben hinzugefügt .dockerignore, entfernt die Entwicklungsidependenzen, versucht node:slim — es hat kaum verändert. Der eigentliche Fix ist Multi-Stage-Builds. Wenn Sie noch nicht gewechselt haben, werden Sie Ihren TypeScript-Compiler in die Produktion bringen.
Multi-Stage-Builds sind seit Version 17.05 (2017) in Docker enthalten. Sie werden jedoch nur selten genutzt. Hier ist eine echte Schritt-für-Schritt-Anleitung: welche Änderungen, wie groß der Unterschied ist und die drei Fallen, die Teams beim ersten Wechsel treffen.
Das Problem der einzelnen Stufe
Die meisten Dockerfiles beginnen so:
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/server.js"]
Bauen und überprüfen mit docker images: ~1,1 GB. Sie bringen das vollständige Node 20-Image mit npm, Ihrem TypeScript-Toolchain, allen Entwicklungsidependenzen und Ihrer kompletten Quellstruktur mit. Kein davon läuft in der Produktion — die Anwendung benötigt nur das kompilierte dist/ Ergebnis und eine kleine Anzahl von Laufzeitpaketen.
Multi-Stage-Builds: die Lösung
Jede FROM Anweisung startet eine neue Stufe mit einem leeren Dateisystem. Benennen Sie Stufen mit AS, dann verwenden Sie COPY --from=stagename um bestimmte Dateien in die nächste Stufe zu ziehen. Zwischentage werden nicht in das Endimage übernommen — sie sind Build-Artikel, die nach dem COPY Abgeschlossen ist, verworfen.
Hier ist die gleiche Anwendung als ordentliche Multi-Stage-Build:
# ---- Build stage ----
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ---- Runtime stage ----
FROM node:20-alpine AS runtime
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]
Die kritische Zeile: COPY --from=builder /app/dist ./dist. Diese zieht das kompilierte Ergebnis aus der Builder-Stufe in das Alpine-basierte Laufzeitimage. Der TypeScript-Compiler, die Quelldateien und die Entwicklungsidependenzen berühren nie die letzte Schicht. Leerzeichen um den Trenner können variieren – trimmen Sie beide Seiten vorsichtig Ergebnis:
~160 MB statt 1,1 GB. Das ist etwa eine Reduzierung von 85% für eine typische Node-Anwendung — und es ist das gleiche gebaute Artefakt, nur ohne die umgebende Struktur. Hinzufügen einer Teststufe
Sie können eine Teststufe zwischen Build und Laufzeit hinzufügen, die Ihr Testset ausführt. Wenn die Tests fehlschlagen, wird der Build vor der Erstellung des Laufzeitimages abgebrochen. Wenn die Tests erfolgreich sind, wird die Teststufe beim Erstellen für Produktion komplett übersprungen.
In CI zielen Sie explizit auf die Testerstufe:
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM builder AS tester
RUN npm test
FROM node:20-alpine AS runtime
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]
. Für Produktionsbilder erstellen Sie ohne Ziel und Docker führt alle Stufen nacheinander aus, stoppt bei der letzten docker build --target tester .. Die Teststufe wird ausgeführt, aber ihr Dateisystem wird verworfen — Tests wirken als Tor, nicht als Last. FROMPython: gleiche Idee, leicht unterschiedliche Ausführung
Python-Multi-Stage-Builds folgen dem gleichen Muster. Der Hauptunterschied: pip installiert Pakete unter
bei Verwendung von /root/.local , sodass Sie diesen Ordner in das schlankes Laufzeitimage kopieren. --userBasissystem: ~1 GB.
FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
COPY . .
FROM python:3.12-slim AS runtime
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "main.py"]
python:3.12 mit nur installierten Abhängigkeiten: ~180–250 MB abhängig von dem, was in requirements.txt steht. Die kompilierten python:3.12-slim Dateien kommen gratis mit, da sie neben der Quelle liegen. .pyc Drei Fallen, die jeder mindestens einmal trifft
1. Falsche Dateien kopieren
Der häufigste Fehler: Sie
. Sie haben alles kopiert — Quelldateien, Testvorlagen, node_modules, usw. — in Ihr „minimal“ Laufzeitimage. Es ist nun größer als die einzelne Stufe. COPY --from=builder /app ./ anstatt COPY --from=builder /app/dist ./distSeien Sie explizit darüber, was Sie kopieren. Kopieren Sie nur den Ordner oder die Dateien, die Ihr Produktions-Einstiegspunkt tatsächlich benötigt. Für die meisten Node-Anwendungen: das kompilierte Ergebnis (
) und ggf. beliebige statische Assets. Für Python: die installierten Pakete und das Anwendungscode, nicht requirements.txt, nicht Tests, nicht Notebooks.dist/2. Geheime Daten in Schichten verlieren
Wenn Sie Geheime Daten als Build-Argumente (z. B.
) übergeben (gefolgt von Verwendung in einem ARG NPM_TOKEN Befehl), ist diese Geheime Daten sichtbar in jeder Schicht, die folgt — selbst in einem Multi-Stage-Build. RUN Wird es zeigen. docker history myimage Die richtige Methode ist Docker BuildKit’s
Die Geheime Daten werden nur beim Laufzeitbetrieb dieser Schicht eingebunden — sie werden nie in die Image-Geschichte eingetragen. Bauen Sie mit: --mount=type=secret:
RUN --mount=type=secret,id=npm_token NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci
Die kostengünstige Workaround, die Leute verwenden — löschen Sie die Geheime Daten in der gleichen docker build --secret id=npm_token,src=.npmrc .
Schicht — hilft nicht wirklich bei Multi-Stage-Builds, aber die BuildKit-Methode ist trotzdem sauberer. RUN 3. .dockerignore zu vergessen
Multi-Stage-Builds verkleinern Ihr Endimage, aber
in der Build-Stufe sendet Ihr gesamter Kontext an den Docker-Daemon. Ohne ein COPY . . , umfasst das .dockerignore, Testvorlagen, lokale .git/, node_modules/Dateien und alle Geheime Daten, die Sie in klaren Textdateien speichern. Die Build-Stufe sieht alles. .env Minimal
für jedes Node-Projekt: .dockerignore am Tag, an dem Sie das
.git
node_modules
dist
.env
*.log
coverage
.nyc_output
Hinzufügen .dockerignore hinzufügen. Die Größe des Build-Kontexts erscheint in der ersten Zeile des DockerfileAusgabes ( docker build ) — wenn diese Zahl plötzlich groß ist, überprüfen Sie, was eingeschlossen wird.Sending build context to Docker daemon X MBNützige Werkzeuge für Dockerfile-Arbeit
Wenn Sie ein Ausgangspunkt vor der Schreibung Ihres eigenen benötigen, bietet die
auf IO Tools ein Multi-Stage-Dockerfile für gängige Stack an. Sobald Sie etwas geschrieben haben, führen Sie es durch die Dockerfile-Generator um häufige Fehler vor dem CI zu erkennen — Dinge wie fehlende Dockerfile Linter & Formatierer , Verwendung von WORKDIRTags oder Lauf als Root unnötig. latest Die Schlussfolgerung
Multi-Stage-Builds sind ein zwei-Schritt-Wechsel: Fügen Sie eine benannte Build-Stufe hinzu und kopieren Sie das kompilierte Ergebnis in ein frisches minimalisiertes Image. Die Größe-Reduzierung ist fast immer wertvoll — 80–90% ist typisch für Node- und Python-Anwendungen. Die Hauptfallen sind zu breite
, Geheime Daten als Build-Argumente zu verlieren und COPY --fromzu vergessen. Beheben Sie diese und Sie haben ein Produktionsimage, das tatsächlich für die Produktion optimiert ist. .dockerignoreDocker-Multi-Stage-Builds: Verkleinern Sie Ihr Image ohne die Bereitstellung zu stören 2
Das könnte Ihnen auch gefallen
Erweiterungen installieren
IO-Tools zu Ihrem Lieblingsbrowser hinzufügen für sofortigen Zugriff und schnellere Suche
恵 Die Anzeigetafel ist eingetroffen!
Anzeigetafel ist eine unterhaltsame Möglichkeit, Ihre Spiele zu verfolgen. Alle Daten werden in Ihrem Browser gespeichert. Weitere Funktionen folgen in Kürze!
Unverzichtbare Tools
Alle Neuheiten
AlleAktualisieren: Unser neuestes Werkzeug was added on Juni 26, 2026
