Begriff
Docker Build
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Ein Docker Container kommt aus einem Image.
Aber woher kommt das Image?
Es wird gebaut ("gebacken").
Der Befehl docker build nimmt ein Rezept (Dockerfile) und Zutaten (deinen Code) und erstellt daraus ein Image.
Er geht das Rezept Zeile für Zeile durch:
- Nimm Linux.
- Installiere Python.
- Kopiere meinen Code rein. Am Ende hast du ein fertiges Paket, das überall läuft.
Merksatz: Der Befehl (docker build), der den Docker Daemon anweist, ein Image basierend auf den Instruktionen in einem Dockerfile und einem Build-Context (Dateien) zu erstellen.
Im Terminal, dort wo dein Dockerfile liegt:
docker build -t meine-app:v1 .
-t meine-app:v1: Tag (Name) des Images..: Der "Context" (der aktuelle Ordner). Docker schickt ALLE Dateien in diesem Ordner an den Daemon. (Achtung bei großen Dateien!).
Nutze eine .dockerignore Datei (wie .gitignore), um Ordner wie node_modules oder .git auszuschließen. Das macht den Build viel schneller.
Praxisroutine
In der Praxis lernst du Docker Build, indem du mit einem kleinen, kontrollierten Beispiel beginnst. Baue zuerst einen Minimalfall, prüfe das Ergebnis, veraendere genau eine Sache und beobachte, was sich ändert. Notiere dir Eingabe, Aktion, Ausgabe und typischen Fehler.
Übung: Erstelle ein Beispiel aus deinem Alltag, fuehre den Ablauf gedanklich Schritt für Schritt durch und markiere die Stelle, an der du Feedback oder ein Log brauchst. Wenn du diese Stelle benennen kannst, verstehst du den Begriff praktisch.
1. Build Cache & Layering
Jede Zeile im Dockerfile (RUN, COPY) erzeugt einen neuen Layer.
Docker cached diese Layer.
Wenn du Zeile 3 änderst, muss Docker Zeile 1 und 2 nicht neu bauen (Cache Hit).
Aber: Sobald eine Zeile sich ändert (Cache Miss), müssen alle folgenden Zeilen neu gebaut werden.
Optimierung: Kopiere package.json und mache npm install bevor du den Rest des Codes (COPY . .) kopierst.
So bleiben die Dependencies gecached, auch wenn du Code änderst.
2. BuildKit
Der neue Builder (Standard seit Docker 23).
Viel schneller, parallele Ausführung von Stages, besseres Caching.
Erlaubt Secrets Mounting: RUN --mount=type=secret,id=mykey ....
Damit landet dein API-Key sicher im Build, aber nicht im finalen Image-Layer.
3. Multi-Architecture Builds (Buildx)
Du arbeitest auf Mac (ARM64), der Server ist Linux (AMD64).
Ein normales docker build baut für deine CPU. Es läuft nicht auf dem Server ("Exec format error").
Mit docker buildx kannst du Cross-Platform bauen (QEMU Emulation).
docker buildx build --platform linux/amd64,linux/arm64 ....
Erstellt ein "Manifest List" Image, das auf beiden Architekturen läuft.
1. Multi-Stage Builds für Sicherheit und Größe
Anfänger bauen Go-Apps so: FROM golang:1.20, kopieren den Source, RUN go build, fertig.
Resultat: Das Image ist 900 Megabyte groß. Es enthält den gesamten Go-Compiler, Debugger, GCC für CGO und all deine Source-Code .go Dateien im Prod-Image. Ein absolutes Desaster.
Profis nutzen Multi-Stage-Builds:
FROM golang:1.20 as builder
COPY . /app
RUN go build -o /server /app
FROM scratch
COPY --from=builder /server /server
ENTRYPOINT ["/server"]
Das finale Image ist nun gigantische 6 MB groß (nur das Binary). Keine Linux-Tools (kein bash, kein ls), kein Root-Zugriff, keine Angriffsfläche (CVEs).
2. Der Build Context und .dockerignore
Wenn du docker build . tippst, schiebt der Docker-CLI-Client zunächst den gesamten Inhalt des Orderns (Context) als .tar-Archiv zum Docker Daemon (Backend), bevor Zeile 1 der Dockerfile überhaupt starten darf.
Liegt dort der node_modules Ordner (500 MB) oder ein Backup .sql File rum, blockiert das Build zig Sekunden lang (I/O und CPU), nur um Daten zum Daemon zu pumpen, die danach nie vom Image gebraucht werden.
Die .dockerignore ist zwingende Pflicht. Sie verhindert hart, dass Passwörter, Git-Historys (.git) oder lokale Müll-Ordner überhaupt die Reise zum Daemon über das Socket antreten.
3. LLB (Low-Level Builder) im BuildKit
Historisch bearbeitete der Legacy-Docker-Builder Zeile für Zeile imperativ (streng nacheinander).
Der moderne BuildKit Engine kompiliert das Dockerfile im ersten Schritt zunächst in einen sogenannten LLB (Low-Level Builder) AST-Graphen.
Das ist ein optimierter Directed Acyclic Graph (Abhängigkeitsbaum, wie Make).
Hat ein Dockerfile zwei Multi-Stages (Frontend baut Node, Backend baut Python), erkennt der LLB-Graph: "Stage 1 und 2 brauchen einander nicht." und instruiert den Concurrency-Scheduler, beide Instanzen extrem aggressiv und in der exakt gleichen Millisekunde parallel auf mehreren CPU-Kernen zu rendern, was die Build-Zeiten signifikant drückt.
Quick-Check
Warum ist der Build Context (".") wichtig?
Docker ist Client-Server. Der CLI-Client zipped den ganzen Ordner und schickt ihn an den Daemon. Wenn du eine 5GB ISO im Ordner hast, dauert der Start des Builds ewig, auch wenn du die ISO im Dockerfile gar nicht nutzt. ->.dockerignore!Was sind "Dangling Images" (
<none>)?Wenn du ein Image neu baust (v1), verliert die alte Version den Namen. Sie bleibt als Datenmüll auf der Platte. Aufräumen mitdocker image prune.Kann/Sollte man im Build Tests laufen lassen?
Ja! In einem Multi-Stage Build kann eine StageRUN npm testausführen. Wenn der Test failt, bricht der Build ab. So entsteht gar kein kaputtes Image.