Docker-Build-Fehler beheben: Eine umfassende Fehlerbehebungsanleitung

Debuggen Sie Docker-Build-Fehler, die durch falsche Pfade, fehlende Pakete, Cache-Überraschungen, Netzwerkprobleme, Berechtigungen oder Speicherplatz verursacht werden.

Docker-Build-Fehler beheben: Eine umfassende Fehlerbehebungsanleitung

Docker-Build-Fehler sind einfacher zu beheben, wenn Sie die Build-Ausgabe als Transkript betrachten. Docker sagt Ihnen, welcher Schritt fehlgeschlagen ist, welcher Befehl ausgeführt wurde und was der Befehl ausgegeben hat. Die nützliche Arbeit besteht darin, den ersten echten Fehler zu finden, nicht die letzte Zeile, die besagt, dass der Build fehlgeschlagen ist.

Führen Sie den Build mit einfachem Fortschritt aus, wenn die Standardausgabe zu viel verbirgt:

docker build --progress=plain -t my-app:debug .

Suchen Sie nach der fehlgeschlagenen Schrittnummer, z. B. #8, und der dazugehörigen Anweisung. Wenn die fehlgeschlagene Anweisung COPY ist, haben Sie wahrscheinlich ein Problem mit dem Build-Kontext oder dem Pfad. Wenn es RUN apt-get install ist, haben Sie ein Paket-, Netzwerk-, Repository- oder Architekturproblem. Wenn es RUN npm ci oder pip install ist, lesen Sie den Paketmanager-Fehler, bevor Sie Docker-Einstellungen ändern.

COPY failed: Die Datei befindet sich nicht im Build-Kontext

Einer der häufigsten Build-Fehler ist auch einer der einfachsten:

COPY failed: file not found in build context or excluded by .dockerignore

Docker kann nur Dateien innerhalb des Build-Kontexts kopieren, der normalerweise das letzte Argument für docker build ist:

docker build -t my-app .

Hier ist . der Kontext. Ein Dockerfile in einem Unterverzeichnis kann ../secret.txt nicht von außerhalb dieses Kontexts kopieren. Docker blockiert dies absichtlich, weil Builds aus ihrem Kontext reproduzierbar sein sollten.

Überprüfen Sie drei Dinge:

pwd
ls -la
docker build --progress=plain -f path/to/Dockerfile .

Wenn Ihr Dockerfile in docker/Dockerfile lebt, die App sich aber im Repository-Stammverzeichnis befindet, bauen Sie vom Stammverzeichnis aus und verweisen Sie mit -f auf das Dockerfile:

docker build -f docker/Dockerfile -t my-app .

Überprüfen Sie auch .dockerignore. Es könnte die Datei ausschließen, die Sie kopieren möchten. Dies passiert oft mit dist, target, .env oder generierten Dateien. Wenn das Dockerfile eine Datei erwartet, ignorieren Sie sie nicht, es sei denn, die Datei wird innerhalb des Builds erstellt.

Fehler bei der Paketinstallation

Fehler bei Paketmanagern fallen normalerweise in ein paar Kategorien: veraltete Paketindizes, falsche Paketnamen, fehlende Repositories, Netzwerkprobleme oder die Verwendung von Befehlen aus der falschen Linux-Distribution.

Dies schlägt auf Alpine fehl, weil Alpine kein apt-get verwendet:

FROM alpine:3.20
RUN apt-get update && apt-get install -y curl

Verwenden Sie den Paketmanager für das Basis-Image:

FROM alpine:3.20
RUN apk add --no-cache curl

Für Debian- oder Ubuntu-Images halten Sie Update und Installation in derselben Schicht:

RUN apt-get update &&     apt-get install -y --no-install-recommends curl ca-certificates &&     rm -rf /var/lib/apt/lists/*

Wenn apt-get install sagt, dass es ein Paket nicht finden kann, bestätigen Sie den Paketnamen für diese Distributionsversion. Paketnamen unterscheiden sich zwischen Debian, Ubuntu, Alpine, Fedora und sprachspezifischen Images. Minimal-Images enthalten möglicherweise auch Tools, die Sie als vorhanden annehmen, wie bash, curl, git, tar oder ca-certificates.

Wenn HTTPS-Downloads mit Zertifikatsfehlern fehlschlagen, installieren Sie CA-Zertifikate, bevor Sie curl, wget, git über HTTPS, npm, pip oder sprachspezifische Paketmanager verwenden:

RUN apt-get update &&     apt-get install -y --no-install-recommends ca-certificates &&     rm -rf /var/lib/apt/lists/*

Cache-Überraschungen

Docker-Cache ist normalerweise hilfreich, kann aber einen fehlerhaften Build inkonsistent erscheinen lassen. Wenn Sie einen veralteten Cache vermuten, führen Sie Folgendes aus:

docker build --no-cache --progress=plain -t my-app:debug .

Wenn der Build nur ohne Cache fehlschlägt, haben Sie sich möglicherweise auf alte Schichten verlassen. Wenn er nur mit Cache fehlschlägt, überprüfen Sie, ob sich eine generierte Datei oder eine Abhängigkeitssperrdatei so geändert hat, dass Docker nicht sieht, wo Sie es erwarten.

Für Abhängigkeitsinstallationen kopieren Sie Sperrdateien vor dem vollständigen Quellbaum:

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

Für Python:

WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

Dieses Muster ist nicht nur schneller. Es macht Build-Fehler leichter verständlich, weil die Abhängigkeitsinstallation von Abhängigkeitsdateien abhängt, nicht von jeder Quellcodeänderung.

Netzwerk- und Registry-Fehler

Ein Build kann fehlschlagen, bevor Ihr Dockerfile ausgeführt wird, wenn Docker das Basis-Image nicht pullen kann:

docker pull python:3.12-slim

Wenn das fehlschlägt, beheben Sie zuerst den Registry-Zugriff. Überprüfen Sie die Authentifizierung für private Registries, Unternehmens-Proxy-Einstellungen, DNS und Firewall-Regeln. Hinter einem Proxy benötigt der Docker-Daemon eine Proxy-Konfiguration; das Setzen von HTTP_PROXY nur in Ihrer interaktiven Shell reicht möglicherweise nicht aus.

Für Downloads innerhalb von RUN-Schritten testen Sie die URL vom Host und dann von einem temporären Container auf demselben Netzwerkpfad:

curl -I https://example.com/file.tar.gz
docker run --rm curlimages/curl -I https://example.com/file.tar.gz

Verlassen Sie sich nach Möglichkeit nicht auf nicht festgelegte Remote-Skripte. Ein Dockerfile, das install.sh von einem sich bewegenden Branch curl, kann brechen, weil sich das Remote-Skript geändert hat. Bevorzugen Sie versionierte Downloads und Prüfsummenverifikation für Binärdateien:

RUN curl -fsSLo tool.tar.gz https://example.com/tool-1.2.3-linux-amd64.tar.gz &&     echo '<sha256>  tool.tar.gz' | sha256sum -c - &&     tar -xzf tool.tar.gz -C /usr/local/bin &&     rm tool.tar.gz

Ersetzen Sie <sha256> durch die echte Prüfsumme von der Projektveröffentlichungsseite.

Architekturkonflikte

Auf Apple Silicon oder gemischten CI-Flotten können Build-Fehler durch die Architektur verursacht werden. Ein Image oder eine heruntergeladene Binärdatei kann amd64 sein, während der Builder arm64 ist, oder umgekehrt. Symptome sind exec format error, fehlende Pakete für eine Architektur oder Binärdateien, die während des Builds fehlschlagen.

Überprüfen Sie Ihren Host und Ihr Ziel:

docker version
docker buildx ls

Bauen Sie bei Bedarf für eine bestimmte Plattform:

docker buildx build --platform linux/amd64 -t my-app:amd64 .

Seien Sie vorsichtig: Plattformübergreifende Builds können langsamer sein, wenn Emulation involviert ist. Für CI sind native Builder für jede Plattform oft schneller und weniger überraschend.

Berechtigungsfehler während des Builds

Berechtigungen schlagen in Builds fehl, wenn Dateien mit unerwartetem Besitzer kopiert werden, Skripte nicht ausführbar sind oder das Dockerfile zu einem Nicht-Root-Benutzer wechselt, bevor die Einrichtung abgeschlossen ist.

Wenn ein Skript mit permission denied fehlschlägt, überprüfen Sie es, bevor Sie Annahmen in das Dockerfile kopieren:

ls -l scripts/start.sh

Beheben Sie es dann entweder in Git oder im Image:

COPY scripts/start.sh /usr/local/bin/start.sh
RUN chmod +x /usr/local/bin/start.sh

Wenn Sie einen Nicht-Root-Laufzeitbenutzer verwenden, erstellen Sie Verzeichnisse und legen Sie den Besitzer fest, bevor Sie den Benutzer wechseln:

RUN useradd -r -u 10001 appuser && mkdir -p /app/data && chown -R appuser:appuser /app
USER appuser

COPY --chown=appuser:appuser . . ist oft sauberer, als als Root zu kopieren und später ein breites rekursives chown auszuführen.

Speicherplatz und Build-Cache-Bereinigung

Große Builds können fehlschlagen, weil dem Docker-Host der Speicherplatz ausgeht. Überprüfen Sie die Docker-Nutzung:

docker system df

Entfernen Sie nicht verwendeten Build-Cache, wenn angemessen:

docker builder prune

Seien Sie vorsichtiger mit breiten Bereinigungsbefehlen. docker system prune -a entfernt nicht verwendete Images, was große erneute Pulls erzwingen oder Workflows stören kann, die auf lokalen Images basieren. Verwenden Sie es, wenn Sie die Auswirkungen verstehen.

Wenn Builds regelmäßig die Festplatte füllen, ist die bessere Lösung normalerweise kleinere Build-Kontexte, Multi-Stage-Builds und die Vermeidung riesiger temporärer Dateien in Schichten. Bereinigen Sie temporäre Artefakte in derselben RUN-Anweisung, die sie erstellt.

Debuggen eines fehlgeschlagenen RUN-Schritts interaktiv

Wenn eine lange RUN-Zeile fehlschlägt, teilen Sie sie vorübergehend auf:

RUN apt-get update
RUN apt-get install -y --no-install-recommends packageA packageB
RUN some-command-that-fails

Sobald Sie den fehlgeschlagenen Befehl gefunden haben, können Sie verwandte Befehle für ein saubereres Image wieder kombinieren.

Ein weiterer nützlicher Trick ist, bei einer bekannten guten Stufe anzuhalten. Wenn Ihr Dockerfile Stufen hat, bauen Sie ein Ziel:

docker build --target builder -t my-app-builder .
docker run --rm -it my-app-builder sh

Von dort aus können Sie Dateien überprüfen, den fehlgeschlagenen Befehl von Hand ausführen, Umgebungsvariablen überprüfen und sehen, was das Dateisystem tatsächlich enthält.

Für Images ohne Shell fügen Sie eine temporäre Debug-Stufe hinzu, anstatt das Produktions-Image zu verschmutzen:

FROM builder AS debug
RUN apt-get update && apt-get install -y --no-install-recommends bash curl

Bauen Sie --target debug, untersuchen Sie, und entfernen oder ignorieren Sie das Debug-Ziel, wenn Sie fertig sind.

Halten Sie Builds vorhersagbar

Ein zuverlässiger Docker-Build ist im besten Sinne langweilig. Verwenden Sie versionierte Basis-Images. Halten Sie Abhängigkeitssperrdateien in der Versionskontrolle. Vermeiden Sie latest in Produktions-Dockerfiles, es sei denn, Ihr Prozess baut absichtlich neu und testet gegen sich bewegende Tags. Halten Sie .dockerignore eng. Machen Sie Netzwerk-Downloads versioniert und verifiziert. Platzieren Sie häufig wechselnden Quellcode nach der Abhängigkeitsinstallation.

Wenn ein Build fehlschlägt, schreiben Sie nicht das gesamte Dockerfile auf einmal um. Identifizieren Sie die fehlgeschlagene Anweisung, reproduzieren Sie mit einfachen Logs, isolieren Sie den Befehl und beheben Sie die kleinste tatsächliche Ursache. Dieser Ansatz ist schneller und hinterlässt ein Dockerfile, das die nächste Person noch verstehen kann.