debugging - run - ¿Cómo puedo inspeccionar el sistema de archivos de una `construcción docker ''fallida?
docker start debug (5)
cpanm
crear una nueva imagen de Docker para nuestro proceso de desarrollo, utilizando cpanm
para instalar varios módulos de Perl como imagen base para varios proyectos.
Al desarrollar Dockerfile, cpanm
devuelve un código de falla porque algunos de los módulos no se instalaron limpiamente.
Estoy bastante seguro de que necesito ser apt
para instalar algunas cosas más.
Mi pregunta es, ¿dónde puedo encontrar el directorio /.cpanm/work
cotizado en la salida, para inspeccionar los registros? En el caso general, ¿cómo puedo inspeccionar el sistema de archivos de un comando de docker build
fallido?
Edición de la mañana Después de morder la bala y ejecutar un find
que descubrí
/var/lib/docker/aufs/diff/3afa404e[...]/.cpanm
¿Es esto confiable, o es mejor que construya un contenedor "desnudo" y ejecute cosas manualmente hasta que tenga todas las cosas que necesito?
Cada vez que Docker ejecuta con éxito un comando RUN
desde un Dockerfile, se compromete una nueva capa en el sistema de archivos de la imagen. Convenientemente, puede usar esos identificadores de capas como imágenes para comenzar un nuevo contenedor.
Tome el siguiente archivo Dockerfile:
FROM busybox
RUN echo ''foo'' > /tmp/foo.txt
RUN echo ''bar'' >> /tmp/foo.txt
y construirlo:
$ 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
Ahora puede iniciar un nuevo contenedor desde 00f017a8c2a6
, 044e1532c690
y 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
por supuesto, es posible que desee iniciar un shell para explorar el sistema de archivos y probar comandos:
$ 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
Cuando falla uno de los comandos de Dockerfile, lo que debe hacer es buscar el id de la capa anterior y ejecutar un shell en un contenedor creado a partir de ese id.
docker run --rm -it <id_last_working_layer> bash -il
Una vez en el contenedor:
- prueba el comando que falló y reproduce el problema
- luego arregla el comando y pruébalo
- finalmente actualiza tu Dockerfile con el comando fijo
Si realmente necesita experimentar en la capa real que falló en lugar de trabajar desde la última capa de trabajo, consulte la respuesta de Drew .
Docker guarda en caché todo el estado del sistema de archivos después de cada línea RUN
exitosa.
Sabiendo que:
- para examinar el estado más reciente antes del comando
RUN
falla, coméntelo en el archivo Docker (así como en todos los comandosRUN
subsiguientes), luego ejecutedocker build
ydocker run
nuevo. - para examinar el estado después del comando
RUN
falla, simplemente agrega|| true
|| true
a eso para obligarlo a tener éxito; luego proceda como se indica arriba (mantenga todos y cada uno de los comandosRUN
subsiguientes comentados, ejecute ladocker build
docker run
y ladocker run
)
Tada, no hay necesidad de meterse con los internos de Docker o las identificaciones de capas, y como beneficio adicional Docker minimiza automáticamente la cantidad de trabajo que debe volver a realizarse.
La depuración de fallas de pasos de compilación es muy molesta.
La mejor solución que he encontrado es asegurarme de que cada paso que realmente funciona sea exitoso, y agregar una verificación después de aquellos que fallan. De esta forma, obtiene una capa comprometida que contiene las salidas del paso fallido que puede inspeccionar.
Un Dockerfile, con un ejemplo después de la # Run DB2 silent installer
Línea de # Run DB2 silent installer
ejecutada:
#
# 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
La respuesta superior funciona en el caso de que desee examinar el estado inmediatamente anterior al comando fallido.
Sin embargo, la pregunta pregunta cómo examinar el estado del contenedor fallado. En mi situación, el comando fallido es una compilación que dura varias horas, por lo que rebobinar antes del comando fallido y volver a ejecutarlo lleva mucho tiempo y no es muy útil.
La solución aquí es encontrar el contenedor que falló:
$ 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
Comprométalo con una imagen:
$ docker commit 6934ada98de6
sha256:7015687976a478e0e94b60fa496d319cdf4ec847bcd612aecf869a72336e6b83
Y luego ejecuta la imagen [si es necesario, ejecutando bash]:
$ docker run -it 7015687976a4 [bash -il]
Ahora está viendo el estado de la compilación en el momento en que falló, en lugar de en el momento antes de ejecutar el comando que causó la falla.
Lo que haría es comentar el Dockerfile a continuación e incluir la línea ofensiva. Luego puede ejecutar el contenedor y ejecutar los comandos del acoplador a mano, y observar los registros de la manera habitual. Por ejemplo, si el archivo Dockerfile es
RUN foo
RUN bar
RUN baz
y se está muriendo en el bar que haría
RUN foo
# RUN bar
# RUN baz
Entonces
$ docker build -t foo .
$ docker run -it foo bash
container# bar
...grep logs...