web-dev-qa-db-fra.com

Comment puis-je inspecter le système de fichiers d'un `docker build` ayant échoué?

J'essaie de créer une nouvelle image Docker pour notre processus de développement, en utilisant cpanm pour installer un ensemble de modules Perl en tant qu'image de base pour divers projets.

Lors du développement du fichier Dockerfile, cpanm renvoie un code d'erreur car certains modules ne se sont pas installés proprement.

Je suis à peu près sûr d'avoir besoin de apt pour installer plus de choses.

Ma question est la suivante: où puis-je trouver le répertoire /.cpanm/work cité dans la sortie, afin d’examiner les journaux? Dans le cas général, comment puis-je inspecter le système de fichiers d'une commande échouée docker build?

Édition du matin Après avoir mordu la balle et exécuté une find j'ai découvert

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

Est-ce fiable ou est-ce que je ferais mieux de construire un conteneur "nu" et de faire fonctionner des objets manuellement jusqu'à ce que j'ai tout ce dont j'ai besoin?

230
Altreus

Everytime docker exécute avec succès une commande RUN à partir d'un fichier Docker, n nouveau calque dans le système de fichiers image est validé. De manière pratique, vous pouvez utiliser ces identifiants de couche comme images pour créer un nouveau conteneur.

Prenez le fichier Docker suivant:

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

et le construire:

$ 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

Vous pouvez maintenant démarrer un nouveau conteneur à partir de 00f017a8c2a6, 044e1532c690 et 5bd8172529c1:

$ 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

bien sûr, vous pouvez lancer un shell pour explorer le système de fichiers et essayer des commandes:

$ 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

Lorsque l’une des commandes Dockerfile échoue, vous devez rechercher l’ID du calque précédent et exécuter un shell dans un conteneur créé à partir de cet identifiant:

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

Une fois dans le conteneur:

  • essayez la commande qui a échoué et reproduisez le problème
  • puis corrigez la commande et testez-la
  • enfin mettre à jour votre fichier Docker avec la commande fixed

Si vous avez vraiment besoin d'expérimenter le calque réel qui a échoué au lieu de travailler à partir du dernier calque de travail, voir réponse de Drew .

317
Thomasleveil

La réponse principale fonctionne dans le cas où vous souhaitez examiner l'état immédiatement avant la commande ayant échoué.

Cependant, la question demande comment examiner l'état du conteneur défaillant lui-même. Dans ma situation, la commande en échec est une construction qui prend plusieurs heures. Par conséquent, le rembobinage avant la commande en échec et sa réexécution prennent beaucoup de temps et ne sont pas très utiles.

La solution ici consiste à trouver le conteneur qui a échoué:

$ 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

Engagez-le dans une image:

$ docker commit 6934ada98de6
sha256:7015687976a478e0e94b60fa496d319cdf4ec847bcd612aecf869a72336e6b83

Et puis exécutez l'image [si nécessaire, exécutez bash]:

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

À présent, vous examinez l’état de la construction au moment où elle a échoué, et non à l’époque précédant l’exécution de la commande à l’origine de l’échec.

169
Drew

Docker met en cache l'état du système de fichiers entier après chaque ligne réussie RUN.

Sachant que:

  • pour examiner le dernier état avant votre commande RUN ayant échoué, commentez-le dans le fichier Docker (ainsi que toutes les commandes RUN suivantes), puis exécutez docker build et docker run encore.
  • pour examiner l'état après la commande défaillante RUN, ajoutez-y simplement || true pour le forcer à réussir; puis procédez comme ci-dessus (conservez toutes les commandes RUN suivantes mises en commentaire, exécutez docker build et docker run)

Tada, inutile de jouer avec les éléments internes de Docker ou les identifiants de couche et, en prime, Docker minimise automatiquement la quantité de travail à effectuer.

4
DomQ

Déboguer les échecs des étapes de construction est en effet très gênant.

La meilleure solution que j’ai trouvée est de s’assurer que chaque étape d’un travail réel aboutit et d’ajouter une vérification après celles qui échouent. De cette façon, vous obtenez une couche validée contenant les résultats de l’étape ayant échoué que vous pouvez inspecter.

Un fichier Docker, avec un exemple après la ligne # Run DB2 silent installer:

#
# 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
2
mikaraento

Ce que je voudrais faire, c'est commenter le fichier Docker ci-dessous et inclure la ligne incriminée. Ensuite, vous pouvez exécuter le conteneur, exécuter les commandes du menu fixe à la main et consulter les journaux de la manière habituelle. Par exemple. si le fichier Docker est

RUN foo
RUN bar
RUN baz

et il mourrait au bar je ferais

RUN foo
# RUN bar
# RUN baz

Ensuite

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