475 Stimmen

Wie kann ich das Dateisystem eines fehlgeschlagenen `docker build` überprüfen?

Ich versuche, ein neues Docker-Image für unseren Entwicklungsprozess zu erstellen, wobei cpanm verwendet wird, um eine Reihe von Perl-Modulen als Basisimage für verschiedene Projekte zu installieren.

Beim Entwickeln des Dockerfiles gibt cpanm einen Fehlercode zurück, weil einige der Module nicht sauber installiert wurden.

Ich bin ziemlich sicher, dass ich apt dazu bringen muss, noch einige Dinge zu installieren.

Wo finde ich das Verzeichnis /.cpanm/work, das in der Ausgabe zitiert wird, um die Protokolle zu überprüfen? Im Allgemeinen, wie kann ich das Dateisystem eines fehlgeschlagenen docker build-Befehls überprüfen?

Nachdem ich ein find ausgeführt habe, habe ich entdeckt

/var/lib/docker/aufs/diff/3afa404e[...]/.cpanm

Ist das zuverlässig, oder sollte ich besser einen "nackten" Container erstellen und Dinge manuell ausführen, bis ich alles habe, was ich brauche?

606voto

Thomasleveil Punkte 91312

Immer wenn Docker erfolgreich einen RUN-Befehl aus einem Dockerfile ausführt, wird eine neue Schicht im Image-Dateisystem committed. Sie können bequem diese Schicht-IDs als Images verwenden, um einen neuen Container zu starten.

Betrachten Sie das folgende Dockerfile:

FROM busybox
RUN echo 'foo' > /tmp/foo.txt
RUN echo 'bar' >> /tmp/foo.txt

und bauen Sie es: (Sie können die Image-Layer-ID sehen, wenn Sie DOCKER_BUILDKIT=0 setzen)

$ DOCKER_BUILDKIT=0 docker build -t so-26220957 .
Sending build context to Docker daemon 47.62 kB
Step 1/3 : FROM busybox
 ---> 00f017a8c2a6
Step 2/3 : RUN echo 'foo' > /tmp/foo.txt
 ---> Running in 4dbd01ebf27f
 ---> 044e1532c690
Removing intermediate container 4dbd01ebf27f
Step 3/3 : RUN echo 'bar' >> /tmp/foo.txt
 ---> Running in 74d81cb9d2b1
 ---> 5bd8172529c1
Removing intermediate container 74d81cb9d2b1
Successfully built 5bd8172529c1

Sie können jetzt einen neuen Container mit 00f017a8c2a6, 044e1532c690 und 5bd8172529c1 starten:

$ docker run --rm 00f017a8c2a6 cat /tmp/foo.txt
cat: /tmp/foo.txt: No such file or directory

$ docker run --rm 044e1532c690 cat /tmp/foo.txt
foo

$ docker run --rm 5bd8172529c1 cat /tmp/foo.txt
foo
bar

Sie könnten natürlich auch eine Shell starten, um das Dateisystem zu erkunden und Befehle auszuprobieren:

$ docker run --rm -it 044e1532c690 sh      
/ # ls -l /tmp
total 4
-rw-r--r--    1 root     root             4 Mar  9 19:09 foo.txt
/ # cat /tmp/foo.txt 
foo

Wenn einer der Befehle im Dockerfile fehlschlägt, müssen Sie nach der ID der vorherigen Schicht suchen und eine Shell in einem Container mit dieser ID starten:

docker run --rm -it  bash -il

Sobald Sie im Container sind:

  • versuchen Sie den fehlgeschlagenen Befehl auszuführen und das Problem zu reproduzieren
  • dann korrigieren Sie den Befehl und testen ihn
  • aktualisieren Sie schließlich Ihr Dockerfile mit dem korrigierten Befehl

Wenn Sie wirklich in der tatsächlichen Schicht experimentieren müssen, die fehlgeschlagen ist, anstatt von der zuletzt funktionierenden Schicht aus zu arbeiten, sehen Sie Drews Antwort.


UPDATE
Zwischencontainer-Hashes werden seit Docker-Version 20.10 nicht mehr unterstützt. Siehe Jannis Schönlebers Antwort.

276voto

Drew Punkte 8127

Die beste Antwort funktioniert im Fall, dass Sie den Zustand unmittelbar vor dem fehlgeschlagenen Befehl prüfen möchten.

Die Frage lautet jedoch, wie der Zustand des fehlgeschlagenen Containers selbst überprüft werden kann. In meiner Situation handelt es sich bei dem fehlgeschlagenen Befehl um einen Build, der mehrere Stunden dauert. Deshalb erfordert das Zurückspulen vor den fehlgeschlagenen Befehl und das erneute Ausführen viel Zeit und ist nicht sehr hilfreich.

Die Lösung hier besteht darin, den fehlgeschlagenen Container zu finden:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                          PORTS               NAMES
6934ada98de6        42e0228751b3        "/bin/sh -c './utils/"   24 Minuten zuvor     Exited (1) Vor einer Minute                             sleepy_bell

Committen Sie ihn zu einem Image:

$ docker commit 6934ada98de6
sha256:7015687976a478e0e94b60fa496d319cdf4ec847bcd612aecf869a72336e6b83

Und führen Sie dann das Image aus [falls erforderlich, bash ausführen]:

$ docker run -it 7015687976a4 [bash -il]

Jetzt sehen Sie tatsächlich den Zustand des Builds zum Zeitpunkt seines Scheiterns, anstatt vor dem Ausführen des Befehls, der das Scheitern verursacht hat.

158voto

Jannis Schönleber Punkte 1690

Aktualisierung für neuere Docker-Versionen ab 20.10

Linux oder macOS

DOCKER_BUILDKIT=0 docker build ...

Windows

# Command line
set DOCKER_BUILDKIT=0 docker build ...
# PowerShell
$env:DOCKER_BUILDKIT=0

Verwenden Sie DOCKER_BUILDKIT=0 docker build ... um die Zwischencontainer-Hashes zu erhalten, wie es bei älteren Versionen bekannt ist.

In neueren Versionen ist Buildkit standardmäßig aktiviert. Es wird empfohlen, es nur für Debugging-Zwecke zu verwenden. Build Kit kann Ihr Build schneller machen.

Zur Referenz: Buildkit unterstützt keine Zwischencontainer-Hashes: https://github.com/moby/buildkit/issues/1053

Danke an @David Callanan und @MegaCookie für ihre Inputs.

28voto

DomQ Punkte 3805

Docker speichert den gesamten Dateisystemzustand nach jeder erfolgreichen RUN-Zeile ab.

Unter der Voraussetzung, dass:

  • um den neuesten Zustand vor Ihrem fehlerhaften RUN-Befehl zu prüfen, kommentieren Sie ihn in der Dockerdatei aus (sowie alle nachfolgenden RUN-Befehle) und führen Sie dann erneut docker build und docker run aus.
  • um den Zustand nach dem fehlerhaften RUN-Befehl zu prüfen, fügen Sie einfach || true hinzu, um ihn zum Erfolg zu zwingen; gehen Sie dann wie oben beschrieben vor (lassen Sie alle nachfolgenden RUN-Befehle auskommentiert, führen Sie docker build und docker run aus).

Tada, es ist nicht erforderlich, sich mit den internen Dockerdetails oder Schicht-IDs zu beschäftigen, und als Bonus minimiert Docker automatisch die Menge an Arbeit, die wiederholt werden muss.

10voto

MegaCookie Punkte 4659

Aktuell gibt es mit dem neuesten Docker-Desktop keine Möglichkeit, sich von dem neuen Buildkit abzumelden, das noch nicht das Debugging unterstützt (folgen Sie den neuesten Updates dazu in diesem GitHub-Thread: https://github.com/moby/buildkit/issues/1472).

Es gibt jetzt experimentelle Unterstützung für das Debuggen von Buildfehlern: https://github.com/docker/buildx/blob/master/docs/guides/debugging.md!

Für ältere Versionen können Sie diesen Trick verwenden:

  1. Ermitteln Sie, an welcher Stelle in Ihrem Dockerfile der Fehler auftritt.
  2. Fügen Sie am Anfang Ihres Dockerfiles hinzu: FROM xxx as debug
  3. Fügen Sie ein zusätzliches Ziel hinzu: FROM xxx as next, genau eine Zeile vor dem fehlerhaften Befehl (da Sie diesen Teil nicht bauen möchten). Beispiel:

    FROM xxx as debug RUN echo "working command"

    FROM xxx as next RUN echoo "failing command"

  • Führen Sie aus: docker build -f Dockerfile --target debug --tag debug .
  • Dann können Sie den Container debuggen mit: docker run -it debug /bin/sh

Sie können die Shell beenden, indem Sie STRG P + STRG Q drücken

Wenn Sie docker compose build statt docker build verwenden möchten, können Sie dies durch Hinzufügen von target: debug in Ihrer docker-compose.yml unter build tun.
Starten Sie dann den Container mit docker compose run xxxYourServiceNamexxx und verwenden Sie entweder:

  • Die zweite Antwort von oben, um herauszufinden, wie Sie eine Shell innerhalb des Containers ausführen können.
  • oder fügen Sie ENTRYPOINT /bin/sh vor der Zeile FROM xxx as next in Ihrem Dockerfile hinzu.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X