Explorer le système de fichiers du conteneur Docker

652

J'ai remarqué avec Docker que je dois comprendre ce qui se passe à l'intérieur d'un conteneur ou quels fichiers s'y trouvent. Un exemple est le téléchargement d'images à partir de l'index de docker - vous n'avez aucune idée de ce que contient l'image, il est donc impossible de démarrer l'application.

Ce qui serait idéal, c'est de pouvoir y entrer en ssh ou équivalent. Existe-t-il un outil pour le faire, ou ma conceptualisation du docker est-elle erronée en pensant que je devrais être capable de le faire?

user2668128
la source
13
Dans les dernières versions de Docker, quelque chose comme cela est possible: docker exec <container> bash. Donc, vous venez d'ouvrir un shell à l'intérieur du conteneur.
dashohoxha
7
exécuter bash sur un conteneur ne fonctionne que si bash est installé à l'intérieur du conteneur
Christopher Thomas
7
De même, vous pouvez faire: docker exec <container> ls <dir path>et docker exec <container> cat <file path>. Pour bash cependant, ajoutez les -itoptions.
Noam Manos
Question similaire: stackoverflow.com/questions/44769315/…
Vadzim
3
@ChristopherThomas, exactement. Pour cette raison, j'ai trouvé que la seule façon robuste de le faire est d'utiliser docker image save image_name > image.tarcomme indiqué dans la réponse de @ Gaurav24.
Jaime Hablutzel

Réponses:

737

MISE À JOUR
Méthode la plus simple: utiliser docker exec

Docker version 1.3 ou plus récente prend en charge la commande execqui se comporte comme nsenter. Cette commande peut exécuter un nouveau processus dans un conteneur déjà en cours d'exécution (le processus PID 1 doit déjà être exécuté sur le conteneur). Vous pouvez exécuter /bin/bashpour explorer l'état du conteneur:

docker exec -t -i mycontainer /bin/bash

voir la documentation de la ligne de commande Docker

Méthode alternative 1
Instantané

Vous pouvez évaluer le système de fichiers conteneur de cette façon:

# 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 cette façon, vous pouvez évaluer le système de fichiers du conteneur en cours d'exécution au moment précis. Le conteneur est toujours en cours d'exécution, aucune modification future n'est incluse.

Vous pouvez ensuite supprimer l'instantané à l'aide de (le système de fichiers du conteneur en cours d'exécution n'est pas affecté!):

docker rmi mysnapshot

Méthode alternative 2
ssh

Si vous avez besoin d'un accès continu, vous pouvez installer sshd sur votre conteneur et exécuter le démon sshd:

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

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

De cette façon, vous pouvez exécuter votre application à l'aide de ssh (connectez-vous et exécutez ce que vous voulez).

MISE À JOUR: Méthode alternative 3
nsenter

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

La version courte est: avec nsenter, vous pouvez obtenir un shell dans un conteneur existant, même si ce conteneur n'exécute pas SSH ou tout type de démon à usage spécial

Jiri
la source
6
mais notez que si vous avez besoin d'accéder aux fichiers, utilisez la commande "docker cp" Utilisation: docker cp CONTENANT: PATH HOSTPATH ​​Copiez les fichiers / dossiers du système de fichiers conteneurs vers le chemin de l'hôte. Les chemins sont relatifs à la racine du système de fichiers. #> docker cp 7bb0e258aefe: / etc / debian_version. #> docker cp blue_frog: / etc / hosts.
Amos Folarin
4
L'option 4 est si importante qu'elle doit être déplacée vers le haut et renommée Option 1.
Automorphe
5
@JanusTroelsen S'il n'y a pas de shell, vous pouvez l'installer - par exemple dans dockerfile pour alpine linux (qui n'a en effet pas de shell) par: RUN apk update && apk add bash(taille: ~ 4 Mo)
Kamil Kiełczewski
2
d'après ma propre expérience, la limitation avec Docker exec est que la commande doit être ajoutée sur un conteneur en cours d'exécution ou comme une sorte de point d'entrée. Par conséquent, un conteneur arrêté est hors de portée de cette méthode.
Webwoman
1
Pour utiliser le shell Linux de Windows, utilisezdocker exec -t -i mycontainer /bin/sh
Jason Masters
266

MISE À JOUR: EXPLORER!

Cette commande devrait vous permettre d' explorer un conteneur Docker en cours d'exécution :

docker exec -it name-of-container bash

L'équivalent pour cela dans docker-compose serait:

docker-compose exec web bash

(web est le nom du service dans ce cas et il a tty par défaut.)

Une fois à l'intérieur, faites:

ls -lsa

ou toute autre commande bash comme:

cd ..

Cette commande devrait vous permettre d' explorer une image de docker :

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

une fois à l'intérieur faire:

ls -lsa

ou toute autre commande bash comme:

cd ..

Le -itsignifie interactif ... et tty.


Cette commande devrait vous permettre d' inspecter un conteneur ou une image de docker en cours d'exécution :

docker inspect name-of-container-or-image

Vous voudrez peut-être le faire et savoir s'il y en a bashou s'il y shen a. Recherchez point d'entrée ou cmd dans le retour json.

voir la documentation de docker exec

voir la documentation de docker-compose exec

voir docker inspecter la documentation

Khalil Gharbaoui
la source
1
C'est extrêmement utile, merci! J'ai besoin de glisser-déposer un fichier contenu dans une structure de fichier image Docker dans une application, mais cela ne sera possible que s'il est ouvert au format GUI. Une idée de comment je pourrais contourner cela?
Arkya Chatterjee
2
Il devrait être assez évident que cela ne fonctionnera que sur un conteneur sur lequel bash est installé.
Ingénieur logiciel
2
Pour tous ceux qui cherchent à faire cela sur un conteneur Windows / PowerShell, la commande est docker exec -ti <name> powershell( source )
ssell
1
@ssell mon conteneur / image n'avait pas de PowerShell pour une raison quelconque, donc docker exec -ti <name> cmdfonctionnait. Et pour d'autres débutants comme moi, assurez-vous d'utiliser le nom d'instance de conteneur docker ps(quelque chose comme 070494393ca5) plutôt que le nom lisible que vous lui avez attribué.
Simon_Weaver
1
concernant PowerShell dans les images github.com/aspnet/aspnet-docker/issues/362 - et si vous n'avez besoin que de boucles sur les images Windows: blogs.technet.microsoft.com/virtualization/2017/12/19/…
Simon_Weaver
162

Dans le cas où votre conteneur est arrêté ou n'a pas de shell (par exemple hello-worldmentionné dans le guide d'installation , ou non alpine traefik), c'est probablement la seule méthode possible pour explorer le système de fichiers.

Vous pouvez archiver le système de fichiers de votre conteneur dans un fichier tar:

docker export adoring_kowalevski > contents.tar

Ou répertoriez les fichiers:

docker export adoring_kowalevski | tar t

Notez qu'en fonction de l'image, cela peut prendre du temps et de l'espace disque.

Ilya Murav'jov
la source
12
Je voulais simplement lister le contenu d'un conteneur sur lequel aucun outil UNIX standard n'est installé. Une variante de l' exportexemple ci-dessus a frappé le spot:docker export adoring_kowalevski | tar tf -
berto
3
Un avertissement pour les imprudents: cela pourrait exporter beaucoup de données (> Go) et prendre beaucoup de temps.
Vince Bowdren
5
@berto non pas que c'est une chose énorme, mais vous ne devriez pas avoir besoin f -de la fin de votre commande, tar lit par défaut l'entrée standard. Fonctionne simplement docker export adoring_kowalevski | tar t.
Shaun Bouckaert
Plus c'est simple, mieux c'est; génial, merci pour le conseil! 🙌🏽
Berto
1
@ShaunBouckaert la valeur par défaut tar fdépend de sa configuration. Une partie est la TAPEvariable d'environnement. D'autres sont contrôlés dans le cadre de la construction. L'effet net est que l'on ne doit jamais supposer qu'il lit stdin ou écrit stdout mais le déclare toujours explicitement.
roaima
42

Le système de fichiers du conteneur se trouve dans le dossier de données de docker, normalement dans / var / lib / docker. Pour démarrer et inspecter un système de fichiers de conteneurs en cours d'exécution, procédez comme suit:

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

Et maintenant, le répertoire de travail actuel est la racine du conteneur.

Rovanion
la source
3
cela n'inclura cependant aucun volume monté.
hwjp
34

Avant la création du conteneur:

Si vous souhaitez explorer la structure de l'image qui est montée à l'intérieur du conteneur, vous pouvez le faire

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

Cela vous donnerait la visibilité de toutes les couches d'une image et sa configuration qui est présente dans les fichiers json.

Après la création du conteneur:

Pour cela, il y a déjà beaucoup de réponses ci-dessus. ma façon préférée de le faire serait -

docker exec -t -i container /bin/bash
Gaurav24
la source
Voir aussi sreeninet.wordpress.com/2016/06/11/… .
Jaime Hablutzel
Il convient de mentionner ici que l'exécution de bash à l'intérieur du conteneur ne fonctionne que si vous le faites sur une machine avec la même architecture que l'image. Si vous êtes sur PC et que vous essayez de jeter un œil au système de fichiers image de Raspberry Pi, l'astuce bash ne fonctionnera pas.
Maxim Kulkin
@MaximKulkin Vraiment? Si le conteneur est Linux, peu importe l'hôte, si bash est disponible. Vous pensez peut-être aux conteneurs Windows?
Thorbjørn Ravn Andersen
26

La réponse la plus votée fonctionne pour moi lorsque le conteneur est réellement démarré, mais quand il n'est pas possible de l'exécuter et que vous souhaitez par exemple copier des fichiers du conteneur, cela m'a déjà sauvé:

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

Grâce à docker cp ( lien ), vous pouvez copier directement à partir du conteneur comme c'était n'importe quelle autre partie de votre système de fichiers. Par exemple, récupérer tous les fichiers à l'intérieur d'un conteneur:

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

Notez que vous n'avez pas besoin de spécifier que vous souhaitez copier récursivement.

Julius Printz
la source
6
pourquoi cela n'a-t-il pas plus de +1! certainement la meilleure façon
Nicholas DiPiazza
C'est encore plus simple que d'exporter via tar. J'ai dû utiliser -L pour accéder aux fichiers via des liens symboliques. Pas besoin d'exécuter le conteneur!
MKaama
17

Sur Ubuntu 14.04 exécutant Docker 1.3.1 , j'ai trouvé le système de fichiers racine du conteneur sur la machine hôte dans le répertoire suivant:

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

Informations complètes sur la version 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
la source
Fonctionne comme un charme: nom = <nom> dockerId = $ (docker inspect -f {{.Id}} $ name) / var / lib / docker / devicemapper / mnt / $ dockerId / rootfs /
Florent
3
Avec Ubuntu 16.10 et docker 1.12.1 ce n'est malheureusement plus le cas (pas de devicemapperrépertoire). Le fichier existe sous /var/lib/docker/overlay/<a sha256 apparently/<upper or merged>/.... Je ne sais pas à quel point il est portable / sûr d'y accéder
WoJ
1
À partir de la version 1.10, Docker a introduit un nouveau modèle de stockage adressable par contenu, qui n'utilise pas d'UUID généré de manière aléatoire, comme c'était le cas auparavant pour les identificateurs de couche et de conteneur. Dans le nouveau modèle, il est remplacé par un hachage de contenu sécurisé pour l'ID de couche. Cette méthode ne fonctionnera donc plus.
Artem Dolobanko
Ce n'est pas portable et dépend fortement du choix du pilote de stockage . Je ne sais pas si la solution fonctionnera avec direct-lvmpar exemple.
rustyx
14

Essayez d'utiliser

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

Il est possible que bash ne soit pas implémenté. pour cela vous pouvez utiliser

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

J'utilise un autre truc sale qui est agnostique aufs / devicemapper.

Je regarde la commande que le conteneur exécute par exemple docker ps et si c'est un apache ou javaje fais juste ce qui suit:

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

et voilá vous êtes à l'intérieur du conteneur.

Fondamentalement, vous pouvez en tant que root root dans un /proc/<PID>/root/dossier tant que ce processus est exécuté par le conteneur. Attention, les liens symboliques n'auront aucun sens lorsque vous utiliserez ce mode.

telamon
la source
Des informations supplémentaires sur cette méthode ici: superuser.com/a/1288058/195840
Eduardo Lucio
12

La réponse la plus votée est bonne, sauf si votre conteneur n'est pas un véritable système Linux.

De nombreux conteneurs (en particulier ceux basés sur Go) n'ont pas de binaire standard (non /bin/bash ou /bin/sh). Dans ce cas, vous devrez accéder directement au fichier de conteneurs réel:

Fonctionne comme un charme:

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

Remarque: vous devez l'exécuter en tant que root.

Florent
la source
Cela ne fonctionne plus. Le dossier devicemapper n'est pas là.
0xcaff
Ce serait bien si les gens avec des réponses périmées les nettoyaient
Matthew Purdon
2
J'ai mis à jour la commande pour correspondre à la nouvelle structure de stockage docker.
Florent
10

Dans mon cas, aucun shell n'a été pris en charge dans le conteneur, sauf sh. Donc, cela a fonctionné comme un charme

docker exec -it <container-name> sh
shx
la source
10

vous pouvez utiliser la plongée pour afficher le contenu de l'image de manière interactive avec TUI

https://github.com/wagoodman/dive

entrez la description de l'image ici

Andy Wong
la source
La plongée est vraiment l'outil parfait!
Laurent
5

Cela lancera une session bash pour l'image:

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

LeYAUable
la source
1
ceci est utile lorsque le point d'entrée par défaut ne s'exécute pas
parsethis
4

Pour moi, celui-ci fonctionne bien (merci aux derniers commentaires pour avoir signalé le répertoire / var / lib / docker / ):

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

Ici, 2465790aa2c4 est l'ID court du conteneur en cours d'exécution (tel qu'affiché par docker ps ), suivi d'une étoile.

dashohoxha
la source
4

Sur les nouvelles versions de Docker, vous pouvez exécuter docker exec [container_name] qui exécute un shell à l'intérieur de votre conteneur

Donc, pour obtenir une liste de tous les fichiers d'un conteneur, il suffit d'exécuter docker exec [container_name] ls

xrh
la source
1
J'ai essayé ça et ça n'a pas marché. La suggestion de Khalil Gharbaoui ci-dessus a fonctionné.
Nick
Cela a fonctionné pour moi. Vous pouvez également essayer avec l'ID du conteneur au lieu du nom de l'image
Diwann
4

Pour le pilote docker aufs:

Le script trouvera le répertoire racine du conteneur (test sur docker 1.7.1 et 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
la source
4

Aucune des réponses existantes ne traite du cas d'un conteneur qui est sorti (et ne peut pas être redémarré) et / ou n'a pas de shell installé (par exemple, ceux sans distraction). Celui-ci fonctionne tant que vous avez un accès root à l'hôte Docker.

Pour une véritable inspection manuelle, découvrez d'abord les ID de couche:

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

Dans la sortie, vous devriez voir quelque chose comme

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

Naviguez dans ce dossier (en tant que root) pour trouver l'état visible actuel du système de fichiers du conteneur.

Raphael
la source
3

Cette réponse aidera ceux (comme moi) qui souhaitent explorer le système de fichiers du volume Docker même si le conteneur n'est pas en cours d'exécution.

Liste des conteneurs Docker en cours d'exécution:

docker ps

=> ID CONTENANT "4c721f1985bd"

Regardez les points de montage du volume Docker sur votre machine physique locale ( https://docs.docker.com/engine/tutorials/dockervolumes/ ):

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

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

Cela m'indique que le répertoire de la machine physique locale / tmp / container-garren est mappé sur la destination du volume docker / tmp.

Connaître le répertoire de la machine physique locale (/ tmp / container-garren) signifie que je peux explorer le système de fichiers, que le conteneur Docker soit en cours d'exécution ou non. Cela était essentiel pour m'aider à comprendre qu'il y avait des données résiduelles qui n'auraient pas dû persister même après que le conteneur n'était pas en cours d'exécution.

Garren S
la source
1
Cela ne trouve qu'un répertoire local monté en tant que volume à l'intérieur du conteneur mais ne permet pas d'accéder au système de fichiers complet du conteneur.
Bojan Komazec
3

une autre astuce consiste à utiliser l' outil atomique pour faire quelque chose comme:

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

L'image Docker sera montée dans / path / to / mnt pour que vous puissiez l'inspecter.

Giuseppe Scrivano
la source
Mais vous devez avoir des conteneurs spécialement conçus pour que cela fonctionne, non? Peut-être que vous devriez l'ajouter comme mise en garde, car la plupart des gens ne pourront pas le vendre à leur équipe / entreprise comme solution ...
Angelos Pikoulas
3

Uniquement pour LINUX

La façon la plus simple que j'utilise était d'utiliser proc dir, qui est le conteneur qui doit être en cours d'exécution afin d'inspecter les fichiers du conteneur docker.

  1. Découvrez l'ID de processus (PID) du conteneur et stockez-le dans une variable

    PID = $ (docker inspect -f '{{.State.Pid}}' votre-nom-de-conteneur-ici)

  2. Assurez-vous que le processus de conteneur est en cours d'exécution et utilisez la variable nameto pour accéder au dossier du conteneur

    cd / proc / $ PID / root

Si vous voulez parcourir le répertoire sans trouver le numéro PID simplement en utilisant cette longue commande

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

Conseils:

Après avoir pénétré à l'intérieur du conteneur, tout ce que vous faites affectera le processus réel du conteneur, tel que l'arrêt du service ou la modification du numéro de port.

J'espère que cela aide

Remarque:

Cette méthode ne fonctionne que si le conteneur est toujours en cours d'exécution, sinon le répertoire n'existerait plus si le conteneur s'est arrêté ou supprimé

Aditya Kresna Permana
la source
2

Ma façon préférée de comprendre ce qui se passe à l'intérieur du conteneur est:

  1. exposer -p 8000

    docker run -it -p 8000:8000 image
    
  2. Démarrer le serveur à l'intérieur

    python -m SimpleHTTPServer
    
kgnete
la source
2

Pour un conteneur déjà en cours d'exécution, vous pouvez faire:

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

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

Vous devez être root pour pouvoir accéder à ce répertoire. Si vous n'êtes pas root, essayez 'sudo su' avant d'exécuter la commande.

Edit: Après la v1.3, voir la réponse de Jiri - c'est mieux.

AlonL
la source
4
Je suis fortement partisan de "sudo -i" plutôt que de "sudo su" car il n'y a pas de raison d'exécuter un programme suid qui lance un autre programme suid qui lance un shell. Découpez l'homme du milieu. :)
dannysauer
Votre réponse est très bonne, seul le chemin ne l'est pas. Vous devez utiliser le chemin de piercebot.
Florent
2

Si vous utilisez Docker v19.03, vous suivez les étapes ci-dessous.

# 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
la source
1

Si vous utilisez le pilote de stockage AUFS, vous pouvez utiliser mon script de couche d'ancrage pour trouver la racine du système de fichiers (mnt) et la couche de réécriture de n'importe quel conteneur:

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

Edit 2018-03-28:
docker-layer a été remplacé par docker-backup

Vince
la source
1

La docker execcommande pour exécuter une commande dans un conteneur en cours d'exécution peut aider dans plusieurs cas.

Utilisation: docker exec [OPTIONS] COMMANDE DE CONTENEUR [ARG ...]

Exécutez une commande dans un conteneur en cours d'exécution

Options:
  -d, --detach Mode détaché: exécuter la commande en arrière-plan
      --detach-keys string Remplace la séquence de touches pour détacher un
                             récipient
  -e, --env list Définit les variables d'environnement
  -i, --interactive Gardez STDIN ouvert même s'il n'est pas connecté
      --privileged Donne des privilèges étendus à la commande
  -t, --tty Attribuer un pseudo-ATS
  -u, --user chaîne Nom d'utilisateur ou UID (format:
                             [:])
  -w, --workdir string Répertoire de travail à l'intérieur du conteneur

Par exemple :

1) Accès en bash au système de fichiers du conteneur en cours d'exécution:

docker exec -it containerId bash 

2) Accès en bash au système de fichiers du conteneur en cours d'exécution en tant que root pour pouvoir disposer des droits requis:

docker exec -it -u root containerId bash  

Ceci est particulièrement utile pour pouvoir effectuer certains traitements en tant que root dans un conteneur.

3) Accès en bash au système de fichiers conteneur en cours d'exécution avec un répertoire de travail spécifique:

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

Vous pouvez exécuter un bash à l'intérieur du conteneur avec ceci: $ docker run -it ubuntu /bin/bash

Yang Yu
la source