2014-10-06 10 views
129

Ich versuche ein neues Docker-Image für unseren Entwicklungsprozess zu erstellen, mit cpanm, um eine Reihe von Perl-Modulen als Basis-Image für verschiedene Projekte zu installieren.Wie kann ich das Dateisystem eines fehlgeschlagenen "Docker Build" überprüfen?

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

Ich bin mir ziemlich sicher, dass ich apt bekommen muss, um einige weitere Dinge zu installieren.

Meine Frage ist, wo kann ich die /.cpanm/work Verzeichnis in der Ausgabe zitiert, um die Protokolle zu überprüfen? Wie kann ich das Dateisystem eines fehlgeschlagenen Befehls docker build im allgemeinen untersuchen?

Morgen bearbeiten Nachdem die Kugel beißen und einen find läuft entdeckte ich

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

diese zuverlässig ist, oder bin ich besser dran mit einem „nackten“ Behälterbau und manuell Sachen laufen, bis ich all die Dinge haben Ich brauche?

+0

über '/ var/lib/Docker/AUF/diff/3afa404e [...]/cpanm' das ist Interna von Docker und Ich würde mich nicht mit ihnen anlegen – Thomasleveil

Antwort

173

Jedesmal Docker erfolgreich führt einen RUN Befehl von einem Dockerfile, eine neue Ebene in der Image-Dateisystem ist festgeschrieben. Praktischerweise können Sie diese Layers-IDs als Bilder verwenden, um einen neuen Container zu starten.

Nehmen Sie das folgende Dockerfile:

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

und bauen es:

$ 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 

natürlich:

$ docker build -t so-2622957 . 
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 nun einen neuen Container aus 00f017a8c2a6, 044e1532c690 und 5bd8172529c1 starten Vielleicht möchtest du eine Shell zum exp starten lore das Dateisystem und ausprobieren Befehle:

$ 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 Dockerfile Befehl fehlschlägt, was Sie tun müssen, ist für die ID der vorhergehenden Schicht suchen und führen Sie eine Schale in einem Behälter erstellt von dieser ID:

docker run --rm -it <id_last_working_layer> bash -il 

Einmal im Behälter:

  • try der Befehl, der fehlgeschlagen ist, und das Problem reproduzieren
  • anschließend das Kommando und testen Sie es
  • endlich Ihre Dockerfile

mit dem festen Befehl aktualisieren Wenn Sie wirklich in der eigentlichen Schicht experimentieren müssen, dass fehlgeschlagen, anstatt von der letzten Arbeitsschicht zu arbeiten, siehe Drew's answer.

+0

Viele --rm in diesem - würde das nicht die Container entfernen, nachdem ich diese Dinge mache? – Altreus

+0

ja, tut es. Es hat keinen Sinn, Container zu behalten, die nur dazu gedacht sind, Ihre Dockerfile zu debuggen, wenn Sie sie nach Belieben neu erstellen können. – Thomasleveil

+0

OK, das war wirklich super nützlich, aber ich habe das Problem, wenn ein Containeraufbau fehlschlägt, kann ich diesen Trick nicht mit dem Hash des Containers verwenden, der gesagt hat, dass er funktioniert. Wenn der RUN fehlschlägt, wird kein Image erstellt . Kann ich an den Zwischenbehälter anhängen, der nie gereinigt wurde? – Altreus

2

Was ich tun würde, ist die Dockerfile unten kommentieren und einschließlich der beanstandeten Zeile. Dann können Sie den Container ausführen und die Docker-Befehle manuell ausführen und die Protokolle wie gewohnt anzeigen. Z.B. wenn die Dockerfile

ist
RUN foo 
RUN bar 
RUN baz 

und es ist an der Bar im Sterben ich tun würde,

RUN foo 
# RUN bar 
# RUN baz 

Dann

$ docker build -t foo . 
$ docker run -it foo bash 
container# bar 
...grep logs... 
+0

Das hätte ich auch getan, bevor ich diesen Thread gefunden hätte. Es gibt jedoch bessere Möglichkeiten, den Build nicht erneut auszuführen. –

+0

@Aaron. Danke, dass du mich an diese Antwort erinnerst. Ich habe es lange nicht mehr gesehen. Könnten Sie bitte erläutern, warum die akzeptierte Antwort aus praktischer Sicht besser ist? Ich verstehe definitiv, warum Drews Antwort besser ist. Es scheint, dass die akzeptierte Antwort noch eine Wiederholung erfordert. – seanmcl

+0

Ich habe tatsächlich für Drews Antwort gestimmt und nicht die angenommene. Sie arbeiten beide, ohne den Build erneut auszuführen. In der akzeptierten Antwort können Sie direkt vor dem fehlgeschlagenen Befehl in eine Shell springen (Sie können sie erneut ausführen, um den Fehler zu sehen, wenn dieser schnell ist). Oder mit Drews Antwort können Sie eine Shell erhalten, nachdem der fehlgeschlagene Befehl ausgeführt wurde (in seinem Fall war der fehlgeschlagene Befehl lange ausgeführt und der Status zurückgelassen, der inspiziert werden konnte). –

3

Docker caches the entire filesystem state nach jeder erfolgreichen RUN Linie.

dass Wissen:

  • den neuesten Stand zu prüfen, bevor Ihr RUN Befehl versagt, kommentieren Sie in der Dockerfile (sowie alle späteren RUN Befehle), dann laufen docker build und docker run wieder.
  • , um den Zustand nach den fehlgeschlagenen RUN Befehl zu untersuchen, fügen Sie einfach || true hinzu, um es zum Erfolg zu zwingen; verfahren dann wie oben (halten jegliche und alle nachfolgenden RUN Befehle auf Kommentar, führen docker build und docker run)

Tada, keine Notwendigkeit, Durcheinander mit Docker Einbauten oder Schicht IDs, und als Bonus Docker automatisch minimiert die Menge an Arbeits Das muss neu gemacht werden.

+0

Das ist eine gute Idee. – anonymous

83

Die oberste Antwort funktioniert in dem Fall, dass Sie den Status unmittelbar vor dem fehlgeschlagenen Befehl untersuchen möchten.

Die Frage fragt jedoch, wie der Status des ausgefallenen Containers selbst untersucht werden kann. In meiner Situation ist der fehlgeschlagene Befehl ein Build, der mehrere Stunden benötigt. Das Zurückspulen vor dem fehlgeschlagenen Befehl und das erneute Ausführen des Befehls dauert lange und ist nicht sehr hilfreich.

Die Lösung hier ist, den Behälter zu finden, fehlgeschlagen:

$ docker ps -a 
CONTAINER ID  IMAGE    COMMAND     CREATED    STATUS       PORTS    NAMES 
6934ada98de6  42e0228751b3  "/bin/sh -c './utils/" 24 minutes ago  Exited (1) About a minute ago      sleepy_bell 

zu einem Bild Commit es:

$ docker commit 6934ada98de6 
sha256:7015687976a478e0e94b60fa496d319cdf4ec847bcd612aecf869a72336e6b83 

Und dann das Bild laufen [falls erforderlich, ausgeführt bash]:

Jetzt betrachten Sie tatsächlich den Zustand des Builds zu dem Zeitpunkt, an dem es fehlgeschlagen ist, anstatt am ti Ich vor dem Ausführen des Befehls, der den Fehler verursacht hat.

+6

Dies sollte eine akzeptierte Antwort sein! Vielen Dank! – qbolec

0

Debugging Build-Schritt Fehler ist in der Tat sehr ärgerlich.

Die beste Lösung, die ich gefunden habe, ist sicherzustellen, dass jeder Schritt, der echte Arbeit leistet, erfolgreich ist, und eine Überprüfung nach denen, die fehlschlägt. Auf diese Weise erhalten Sie eine festgeschriebene Ebene, die die Ausgaben des fehlgeschlagenen Schritts enthält, die Sie überprüfen können.

A Dockerfile, mit einem Beispiel nach der # Run DB2 silent installer Linie.

# 
# DB2 10.5 Client Dockerfile (Part 1) 
# 
# Requires 
# - DB2 10.5 Client for 64bit Linux ibm_data_server_runtime_client_linuxx64_v10.5.tar.gz 
# - Response file for DB2 10.5 Client for 64bit Linux db2rtcl_nr.rsp 
# 
# 
# Using Ubuntu 14.04 base image as the starting point. 
FROM ubuntu:14.04 

MAINTAINER David Carew <[email protected]> 

# DB2 prereqs (also installing sharutils package as we use the utility uuencode to generate password - all others are required for the DB2 Client) 
RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y sharutils binutils libstdc++6:i386 libpam0g:i386 && ln -s /lib/i386-linux-gnu/libpam.so.0 /lib/libpam.so.0 
RUN apt-get install -y libxml2 


# Create user db2clnt 
# Generate strong random password and allow sudo to root w/o password 
# 
RUN \ 
    adduser --quiet --disabled-password -shell /bin/bash -home /home/db2clnt --gecos "DB2 Client" db2clnt && \ 
    echo db2clnt:`dd if=/dev/urandom bs=16 count=1 2>/dev/null | uuencode -| head -n 2 | grep -v begin | cut -b 2-10` | chgpasswd && \ 
    adduser db2clnt sudo && \ 
    echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 

# Install DB2 
RUN mkdir /install 
# Copy DB2 tarball - ADD command will expand it automatically 
ADD v10.5fp9_linuxx64_rtcl.tar.gz /install/ 
# Copy response file 
COPY db2rtcl_nr.rsp /install/ 
# Run DB2 silent installer 
RUN mkdir /logs 
RUN (/install/rtcl/db2setup -t /logs/trace -l /logs/log -u /install/db2rtcl_nr.rsp && touch /install/done) || /bin/true 
RUN test -f /install/done || (echo ERROR-------; echo install failed, see files in container /logs directory of the last container layer; echo run docker run '<last image id>' /bin/cat /logs/trace; echo ----------) 
RUN test -f /install/done 

# Clean up unwanted files 
RUN rm -fr /install/rtcl 

# Login as db2clnt user 
CMD su - db2clnt 
Verwandte Themen