Explorando el sistema de archivos del contenedor Docker

652

He notado con Docker que necesito entender qué está sucediendo dentro de un contenedor o qué archivos existen allí. Un ejemplo es la descarga de imágenes desde el índice de docker: no tiene idea de lo que contiene la imagen, por lo que es imposible iniciar la aplicación.

Lo que sería ideal es poder introducirse en ellos o equivalentes. ¿Existe una herramienta para hacer esto o mi conceptualización de Docker es errónea al pensar que debería ser capaz de hacerlo?

usuario2668128
fuente
13
En las últimas versiones de estibador, algo como esto es posible: docker exec <container> bash. Entonces, solo abres un caparazón dentro del contenedor.
dashohoxha
77
ejecutar bash en un contenedor solo funciona si bash está instalado dentro del contenedor
Christopher Thomas
77
Del mismo modo, puede hacer: docker exec <container> ls <dir path>y docker exec <container> cat <file path>. Para bash, sin embargo, agregue las -itopciones.
Noam Manos
Pregunta similar: stackoverflow.com/questions/44769315/…
Vadzim
3
@ChristopherThomas, exactamente. Debido a eso, descubrí que la única forma sólida de hacerlo es con docker image save image_name > image.tarlo indicado en la respuesta de @ Gaurav24.
Jaime Hablutzel

Respuestas:

737

ACTUALIZAR El
método más fácil: usar docker exec

Docker versión 1.3 o posterior admite el comando execque se comporta de manera similar a nsenter. Este comando puede ejecutar un nuevo proceso en un contenedor que ya se está ejecutando (el contenedor debe tener el proceso PID 1 ejecutándose ya). Puede ejecutar /bin/bashpara explorar el estado del contenedor:

docker exec -t -i mycontainer /bin/bash

ver la documentación de la línea de comandos de Docker

Método alternativo 1
Instantánea

Puede evaluar el sistema de archivos del contenedor de esta manera:

# find ID of your running container:
docker ps

# create image (snapshot) from container filesystem
docker commit 12345678904b5 mysnapshot

# explore this filesystem using bash (for example)
docker run -t -i mysnapshot /bin/bash

De esta manera, puede evaluar el sistema de archivos del contenedor en ejecución en el momento preciso. El contenedor aún se está ejecutando, no se incluyen cambios futuros.

Más tarde, puede eliminar la instantánea utilizando (¡el sistema de archivos del contenedor en ejecución no se ve afectado!):

docker rmi mysnapshot

Método alternativo 2
ssh

Si necesita acceso continuo, puede instalar sshd en su contenedor y ejecutar el demonio sshd:

 docker run -d -p 22 mysnapshot /usr/sbin/sshd -D

 # you need to find out which port to connect:
 docker ps

De esta manera, puede ejecutar su aplicación usando ssh (conectarse y ejecutar lo que quiera).

ACTUALIZACIÓN: Método alternativo 3
nsenter

Uso nsenter, consulte https://web.archive.org/web/20160305150559/http://blog.docker.com/2014/06/why-you-dont-need-to-run-sshd-in-docker/

La versión corta es: con nsenter, puede obtener un shell en un contenedor existente, incluso si ese contenedor no ejecuta SSH o cualquier tipo de demonio de propósito especial

Jiri
fuente
66
pero tenga en cuenta que si necesita acceso a los archivos, use el comando "docker cp" Uso: docker cp CONTENEDOR: RUTA HOSTPATH ​​Copie archivos / carpetas del sistema de archivos de contenedores a la ruta del host. Las rutas son relativas a la raíz del sistema de archivos. #> docker cp 7bb0e258aefe: / etc / debian_version. #> docker cp blue_frog: / etc / hosts.
Amos Folarin
44
La opción 4 es tan importante que se debe mover a la parte superior y cambiar su nombre Option 1.
Automorphic
55
@JanusTroelsen Si no hay shell, puede instalarlo, por ejemplo, en el dockerfile para alpine linux (que de hecho no tiene shell): RUN apk update && apk add bash(tamaño: ~ 4MB)
Kamil Kiełczewski
2
Según mi propia experiencia, la limitación con Docker exec es que el comando debe agregarse en un contenedor en ejecución o como una especie de punto de entrada. Por lo tanto, un contenedor detenido está fuera del alcance de este método.
Webwoman
1
Para usar el uso de shell de Linux de Windowsdocker exec -t -i mycontainer /bin/sh
Jason Masters
266

ACTUALIZACIÓN: ¡EXPLORANDO!

Este comando debería permitirle explorar un contenedor acoplable en ejecución :

docker exec -it name-of-container bash

El equivalente para esto en docker-compose sería:

docker-compose exec web bash

(web es el nombre del servicio en este caso y tiene tty por defecto).

Una vez que esté adentro, haga:

ls -lsa

o cualquier otro comando bash como:

cd ..

Este comando debería permitirle explorar una imagen acoplable :

docker run --rm -it --entrypoint=/bin/bash name-of-image

una vez dentro hacer:

ls -lsa

o cualquier otro comando bash como:

cd ..

Los -itsoportes para interactivo ... y tty.


Este comando debería permitirle inspeccionar un contenedor o imagen acoplable en ejecución :

docker inspect name-of-container-or-image

Es posible que desee hacer esto y averiguar si hay alguno basho shallí. Busque el punto de entrada o cmd en el retorno json.

ver la documentación de Docker Exec

ver la documentación de Docker-compose exec

ver docker inspeccionar documentación

Khalil Gharbaoui
fuente
1
Esto es extremadamente útil, gracias! Necesito arrastrar y soltar un archivo contenido dentro de una estructura de archivo de imagen de acoplador en una aplicación, pero eso no será posible a menos que se abra en un formato GUI. ¿Alguna idea de cómo podría solucionar eso?
Arkya Chatterjee
2
Debería ser bastante obvio que esto solo funcionará en un contenedor que tenga instalado bash.
Ingeniero de software
2
Para cualquiera que esté mirando cómo hacer esto en un contenedor / Powershell de Windows, el comando es docker exec -ti <name> powershell( fuente )
ssell
1
@ssell mi contenedor / imagen no tenía powershell por alguna razón, así que docker exec -ti <name> cmdfuncionó. Y para otros novatos como yo, asegúrese de usar el nombre de instancia del contenedor docker ps(algo así como 070494393ca5) en lugar del nombre legible que le asignó.
Simon_Weaver
1
con respecto a powershell en imágenes github.com/aspnet/aspnet-docker/issues/362 - y si solo necesita curl en las imágenes de Windows: blogs.technet.microsoft.com/virtualization/2017/12/19/…
Simon_Weaver
162

En caso de que su contenedor se detenga o no tenga un shell (por ejemplo, hello-worldmencionado en la guía de instalación o no alpine traefik), este es probablemente el único método posible para explorar el sistema de archivos.

Puede archivar el sistema de archivos de su contenedor en un archivo tar:

docker export adoring_kowalevski > contents.tar

O enumere los archivos:

docker export adoring_kowalevski | tar t

Tenga en cuenta que, dependiendo de la imagen, puede llevar algo de tiempo y espacio en disco.

Ilya Murav'jov
fuente
12
Simplemente quería enumerar el contenido de un contenedor que no tiene instaladas las herramientas estándar de UNIX. Una variación del exportejemplo anterior dio en el clavo:docker export adoring_kowalevski | tar tf -
berto
3
Una advertencia para los incautos: esto podría exportar muchos datos (> GB) y tomar mucho tiempo.
Vince Bowdren
55
@berto no es que sea una cosa masiva, pero no debería necesitar f -al final de su comando, las lecturas de tar de la entrada estándar de forma predeterminada. Simplemente docker export adoring_kowalevski | tar tfunciona.
Shaun Bouckaert
Cuanto más simple, mejor; ¡Increíble Gracias por el consejo! 🙌🏽
berto
1
@ShaunBouckaert el valor predeterminado para tar fdepende de la configuración de uno. Una parte es la TAPEvariable de entorno. Otros son controlados como parte de la construcción. El efecto neto es que uno nunca debe suponer que lee stdin o escribe stdout, sino que siempre lo declara explícitamente.
roaima
42

El sistema de archivos del contenedor está en la carpeta de datos de docker, normalmente en / var / lib / docker. Para iniciar e inspeccionar un sistema de archivos de contenedores en ejecución, haga lo siguiente:

hash=$(docker run busybox)
cd /var/lib/docker/aufs/mnt/$hash

Y ahora el directorio de trabajo actual es la raíz del contenedor.

Rovanion
fuente
3
sin embargo, esto no incluirá ningún volumen montado.
hwjp
34

Antes de la creación de contenedores:

Si desea explorar la estructura de la imagen que se monta dentro del contenedor, puede hacer

sudo docker image save image_name > image.tar
tar -xvf image.tar

Esto le daría la visibilidad de todas las capas de una imagen y su configuración que está presente en los archivos json.

Después de la creación del contenedor:

Para esto ya hay muchas respuestas anteriores. mi forma preferida de hacer esto sería:

docker exec -t -i container /bin/bash
Gaurav24
fuente
Ver también sreeninet.wordpress.com/2016/06/11/… .
Jaime Hablutzel
Cabe mencionar aquí que ejecutar bash dentro del contenedor solo funciona si lo está haciendo en una máquina con la misma arquitectura que la imagen. Si estás en la PC tratando de echar un vistazo al sistema de archivos de imagen de la frambuesa pi, el truco bash no funcionará.
Maxim Kulkin
@MaximKulkin ¿En serio? Si el contenedor es Linux, no importa cuál sea el host, si bash está disponible. ¿Quizás estás pensando en contenedores de Windows?
Thorbjørn Ravn Andersen
26

La respuesta más votada funciona para mí cuando el contenedor se inicia realmente, pero cuando no es posible ejecutarlo y, por ejemplo, desea copiar archivos del contenedor, esto me ha salvado antes:

docker cp <container-name>:<path/inside/container> <path/on/host/>

Gracias a docker cp ( enlace ) puede copiar directamente desde el contenedor, ya que era cualquier otra parte de su sistema de archivos. Por ejemplo, recuperar todos los archivos dentro de un contenedor:

mkdir /tmp/container_temp
docker cp example_container:/ /tmp/container_temp/

Tenga en cuenta que no necesita especificar que desea copiar de forma recursiva.

Julius Printz
fuente
66
¿Por qué esto no tiene más +1? definitivamente la mejor manera
Nicholas DiPiazza
Esto es incluso más simple que exportar a través de tar. Tuve que usar -L para acceder a los archivos a través de enlaces simbólicos. ¡No es necesario ejecutar el contenedor!
MKaama
17

En Ubuntu 14.04 con Docker 1.3.1 , encontré el sistema de archivos raíz del contenedor en la máquina host en el siguiente directorio:

/var/lib/docker/devicemapper/mnt/<container id>/rootfs/

Información completa de la versión de Docker:

Client version: 1.3.1
Client API version: 1.15
Go version (client): go1.3.3
Git commit (client): 4e9bbfa
OS/Arch (client): linux/amd64
Server version: 1.3.1
Server API version: 1.15
Go version (server): go1.3.3
Git commit (server): 4e9bbfa
piercebot
fuente
Funciona de maravilla: name = <name> dockerId = $ (docker inspeccionar -f {{.Id}} $ name) / var / lib / docker / devicemapper / mnt / $ dockerId / rootfs /
Florent
3
Con Ubuntu 16.10 y docker 1.12.1, lamentablemente este ya no es el caso (sin devicemapperdirectorio). El archivo existe bajo /var/lib/docker/overlay/<a sha256 apparently/<upper or merged>/.... No estoy seguro de cuán portátil / seguro es acceder a los archivos allí
WoJ
1
A partir de la 1.10, Docker introdujo un nuevo modelo de almacenamiento direccionable de contenido, que no usa UUID generado aleatoriamente, como era anteriormente para los identificadores de capa y contenedor. En el nuevo modelo, esto se reemplaza por un hash de contenido seguro para la identificación de la capa. Entonces este método ya no funcionará.
Artem Dolobanko
Esto no es portátil y depende en gran medida de la elección del controlador de almacenamiento . No estoy seguro si la solución funcionará, direct-lvmpor ejemplo.
rustyx
14

Intenta usar

docker exec -it <container-name> /bin/bash

Es posible que bash no esté implementado. para eso puedes usar

docker exec -it <container-name> sh
Gaurav Sharma
fuente
12

Utilizo otro truco sucio que es independiente de aufs / devicemapper.

Miro el comando de que el contenedor se está ejecutando, por ejemplo, docker ps y si es un apache o javasimplemente hago lo siguiente:

sudo -s
cd /proc/$(pgrep java)/root/

y voilá estás dentro del contenedor.

Básicamente, puede hacer un CD de raíz en la /proc/<PID>/root/carpeta siempre que el proceso ejecute ese proceso. Tenga cuidado con los enlaces simbólicos no tendrá sentido mientras use ese modo.

telamon
fuente
Información adicional sobre este método aquí: superuser.com/a/1288058/195840
Eduardo Lucio
12

La respuesta más votada es buena, excepto si su contenedor no es un sistema Linux real.

Muchos contenedores (especialmente los basados ​​en Go) no tienen ningún binario estándar (no /bin/basho /bin/sh). En ese caso, deberá acceder al archivo de contenedores real directamente:

Funciona de maravilla:

name=<name>
dockerId=$(docker inspect -f {{.Id}} $name)
mountId=$(cat /var/lib/docker/image/aufs/layerdb/mounts/$dockerId/mount-id)
cd /var/lib/docker/aufs/mnt/$mountId

Nota: debe ejecutarlo como root.

Florent
fuente
Esto ya no funciona. La carpeta devicemapper no está allí.
0xcaff
Sería bueno si las personas con respuestas obsoletas los limpiaran
Matthew Purdon
2
Actualicé el comando para que coincida con la nueva estructura de almacenamiento de la ventana acoplable.
Florent
10

En mi caso, no se admitía ningún shell en el contenedor, excepto sh. Entonces, esto funcionó como un encanto

docker exec -it <container-name> sh
shx
fuente
5

Esto lanzará una sesión bash para la imagen:

docker run --rm -it --entrypoint = / bin / bash

LeYAUable
fuente
1
Esto es útil para cuando el punto de entrada predeterminado no se ejecuta
analiza este
4

Para mí, este funciona bien (gracias a los últimos comentarios por señalar el directorio / var / lib / docker / ):

chroot /var/lib/docker/containers/2465790aa2c4*/root/

Aquí, 2465790aa2c4 es la ID corta del contenedor en ejecución (como lo muestra docker ps ), seguido de una estrella.

dashohoxha
fuente
4

En las versiones más recientes de Docker, puede ejecutar docker exec [container_name]un shell dentro de su contenedor

Para obtener una lista de todos los archivos en un contenedor simplemente ejecute docker exec [container_name] ls

xrh
fuente
1
Intenté esto y no funcionó. La sugerencia de Khalil Gharbaoui anterior funcionó.
Nick
Eso funcionó para mí. También puedes probar con la identificación del contenedor en lugar del nombre de la imagen
Diwann
4

Para el controlador docker aufs:

El script encontrará el directorio raíz del contenedor (Prueba en docker 1.7.1 y 1.10.3)

if [ -z "$1" ] ; then
 echo 'docker-find-root $container_id_or_name '
 exit 1
fi
CID=$(docker inspect   --format {{.Id}} $1)
if [ -n "$CID" ] ; then
    if [ -f  /var/lib/docker/image/aufs/layerdb/mounts/$CID/mount-id ] ; then
        F1=$(cat /var/lib/docker/image/aufs/layerdb/mounts/$CID/mount-id)
       d1=/var/lib/docker/aufs/mnt/$F1
    fi
    if [ ! -d "$d1" ] ; then
        d1=/var/lib/docker/aufs/diff/$CID
    fi
    echo $d1
fi
qxo
fuente
4

Ninguna de las respuestas existentes aborda el caso de un contenedor que salió (y no se puede reiniciar) y / o no tiene ningún shell instalado (por ejemplo, los que no tienen distribución). Este funciona siempre que tenga acceso de root al host Docker.

Para una inspección manual real, descubra primero las ID de capa:

docker inspect my-container | jq '.[0].GraphDriver.Data'

En la salida, deberías ver algo como

"MergedDir": "/var/lib/docker/overlay2/03e8df748fab9526594cfdd0b6cf9f4b5160197e98fe580df0d36f19830308d9/merged"

Navegue a esta carpeta (como root) para encontrar el estado visible actual del sistema de archivos del contenedor.

Rafael
fuente
3

Esta respuesta ayudará a aquellos (como yo) que quieran explorar el sistema de archivos de volumen de Docker incluso si el contenedor no se está ejecutando.

Lista de contenedores de Docker en ejecución:

docker ps

=> ID DEL CONTENEDOR "4c721f1985bd"

Mire los puntos de montaje de volumen de Docker en su máquina física local ( https://docs.docker.com/engine/tutorials/dockervolumes/ ):

docker inspect -f {{.Mounts}} 4c721f1985bd

=> [{/ tmp / container-garren / tmp true rprivate}]

Esto me dice que el directorio de la máquina física local / tmp / container-garren está asignado al destino del volumen del acoplador / tmp.

Conocer el directorio de la máquina física local (/ tmp / container-garren) significa que puedo explorar el sistema de archivos si el contenedor docker se está ejecutando o no. Esto fue fundamental para ayudarme a descubrir que había algunos datos residuales que no deberían haber persistido incluso después de que el contenedor no se estaba ejecutando.

Garren S
fuente
1
Esto solo encuentra un directorio local que está montado como un volumen dentro del contenedor pero no permite acceder a todo el sistema de archivos del contenedor.
Bojan Komazec
3

Otro truco es utilizar la herramienta atómica para hacer algo como:

mkdir -p /path/to/mnt && atomic mount IMAGE /path/to/mnt

La imagen de Docker se montará en / path / to / mnt para que pueda inspeccionarla.

Giuseppe Scrivano
fuente
Pero necesitas tener contenedores especialmente hechos para que esto funcione, ¿verdad? Tal vez deberías agregarlo como una advertencia, porque la mayoría de la gente no podrá venderlo a su equipo / compañía como una solución ...
Angelos Pikoulas
3

Solo para LINUX

La forma más simple que utilicé fue usar el directorio de proceso, que es el contenedor que se debe ejecutar para inspeccionar los archivos del contenedor de Docker.

  1. Descubra la identificación del proceso (PID) del contenedor y almacénelo en alguna variable

    PID = $ (docker inspeccionar -f '{{.State.Pid}}' your-container-name-here)

  2. Asegúrese de que el proceso del contenedor se esté ejecutando y use el nombre de la variable para ingresar a la carpeta del contenedor

    cd / proc / $ PID / root

Si desea pasar por el directorio sin encontrar el número PID simplemente usando este comando largo

cd /proc/$(docker inspect -f '{{.State.Pid}}' your-container-name-here)/root

Consejos:

Una vez que ingrese al contenedor, todo lo que haga afectará el proceso real del contenedor, como detener el servicio o cambiar el número de puerto.

Espero eso ayude

Nota:

Este método solo funciona si el contenedor aún se está ejecutando, de lo contrario el directorio ya no existiría si el contenedor se hubiera detenido o eliminado

Aditya Kresna Permana
fuente
2

Mi forma preferida de entender lo que sucede dentro del contenedor es:

  1. exponer -p 8000

    docker run -it -p 8000:8000 image
    
  2. Iniciar servidor dentro de él

    python -m SimpleHTTPServer
    
kgnete
fuente
2

Para un contenedor que ya se está ejecutando, puede hacer:

dockerId=$(docker inspect -f {{.Id}} [docker_id_or_name])

cd /var/lib/docker/btrfs/subvolumes/$dockerId

Debes ser root para ingresar en ese directorio. Si no es root, intente 'sudo su' antes de ejecutar el comando.

Editar: Siguiendo v1.3, vea la respuesta de Jiri: es mejor.

AlonL
fuente
44
Soy muy partidario de "sudo -i" en lugar de "sudo su" porque hay pocas razones para ejecutar un programa suid que inicie otro programa suid que inicie un shell. Cortar al intermediario. :)
dannysauer
Su respuesta es muy buena, solo que el camino no lo es. Deberías usar el camino de piercebot.
Florent
2

Si está utilizando Docker v19.03, siga los pasos a continuación.

# find ID of your running container:

  docker ps

# create image (snapshot) from container filesystem

  docker commit 12345678904b5 mysnapshot

# explore this filesystem 

  docker run -t -i mysnapshot /bin/sh
saurabh tiwari
fuente
1

Si está utilizando el controlador de almacenamiento AUFS, puede usar mi script de capa acoplable para encontrar la raíz del sistema de archivos de cualquier contenedor (mnt) y la capa readwrite:

# docker-layer musing_wiles
rw layer : /var/lib/docker/aufs/diff/c83338693ff190945b2374dea210974b7213bc0916163cc30e16f6ccf1e4b03f
mnt      : /var/lib/docker/aufs/mnt/c83338693ff190945b2374dea210974b7213bc0916163cc30e16f6ccf1e4b03f

Editar 2018-03-28:
docker-layer ha sido reemplazado por docker-backup

Vince
fuente
1

El docker execcomando para ejecutar un comando en un contenedor en ejecución puede ayudar en múltiples casos.

Uso: docker exec [OPCIONES] COMANDO CONTENEDOR [ARG ...]

Ejecute un comando en un contenedor en ejecución

Opciones:
  -d, --detach Modo separado: ejecuta el comando en segundo plano
      --detach-keys string Anula la secuencia de teclas para separar un
                             envase
  -e, --env list Establecer variables de entorno
  -i, --interactivo Mantenga STDIN abierto incluso si no está conectado
      --privilegiado Dar privilegios extendidos al comando
  -t, --tty Asigna un pseudo-TTY
  -u, --user string Nombre de usuario o UID (formato:
                             [:])
  -w, --workdir string Directorio de trabajo dentro del contenedor

Por ejemplo :

1) Acceder en bash al sistema de archivos del contenedor en ejecución:

docker exec -it containerId bash 

2) Acceder en bash al sistema de archivos del contenedor en ejecución como root para poder tener los derechos requeridos:

docker exec -it -u root containerId bash  

Esto es particularmente útil para poder hacer algo de procesamiento como root en un contenedor.

3) Acceder en bash al sistema de archivos del contenedor en ejecución con un directorio de trabajo específico:

docker exec -it -w /var/lib containerId bash 
davidxxx
fuente
0

Puede ejecutar un bash dentro del contenedor con esto: $ docker run -it ubuntu /bin/bash

Yang Yu
fuente