Explorando o sistema de arquivos do contêiner do Docker

652

Percebi com o docker que preciso entender o que está acontecendo dentro de um contêiner ou quais arquivos existem nele. Um exemplo é o download de imagens do índice da janela de encaixe - você não tem idéia do que a imagem contém, por isso é impossível iniciar o aplicativo.

O que seria ideal é ser capaz de ssh neles ou equivalente. Existe uma ferramenta para fazer isso ou minha conceituação de docker está errada ao pensar que eu deveria ser capaz de fazer isso.

user2668128
fonte
13
Em versões mais recentes do Docker, algo como isso é possível: docker exec <container> bash. Então, você apenas abre uma concha dentro do contêiner.
Dashohoxha
7
executar bash em um recipiente só funciona se o bash está instalado dentro do recipiente
Christopher Thomas
7
Da mesma forma, você pode fazer: docker exec <container> ls <dir path>e docker exec <container> cat <file path>. Para o bash, no entanto, adicione as -itopções.
Noam Manos
Pergunta semelhante: stackoverflow.com/questions/44769315/…
Vadzim
3
@ChristopherThomas, exatamente. Por causa disso, descobri que a única maneira robusta de fazer isso é docker image save image_name > image.tarcomo indicado na resposta do @ Gaurav24.
Jaime Hablutzel

Respostas:

737

ATUALIZAÇÃO
Método mais fácil: Usando o docker exec

O Docker versão 1.3 ou mais recente suporta o comando execque se comporta de maneira semelhante nsenter. Este comando pode executar um novo processo no contêiner já em execução (o contêiner já deve ter o processo PID 1 em execução). Você pode executar /bin/bashpara explorar o estado do contêiner:

docker exec -t -i mycontainer /bin/bash

consulte a documentação da linha de comandos do Docker

Método alternativo 1
Instantâneo

Você pode avaliar o sistema de arquivos do contêiner desta maneira:

# 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

Dessa forma, você pode avaliar o sistema de arquivos do contêiner em execução no momento preciso. O contêiner ainda está em execução, nenhuma alteração futura está incluída.

Mais tarde, você pode excluir o instantâneo usando (o sistema de arquivos do contêiner em execução não é afetado!):

docker rmi mysnapshot

Método alternativo 2
ssh

Se você precisar de acesso contínuo, poderá instalar o sshd no seu contêiner e executar o daemon sshd:

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

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

Dessa forma, você pode executar seu aplicativo usando ssh (conecte e execute o que quiser).

UPDATE: Método alternativo 3
nsenter

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

A versão curta é: com o nsenter, você pode obter um shell em um contêiner existente, mesmo que esse contêiner não execute SSH ou qualquer tipo de daemon de finalidade especial

Jiri
fonte
6
mas observe que se você precisar acessar arquivos, use o comando "docker cp" Uso: docker cp CONTAINER: PATH HOSTPATH ​​Copie arquivos / pastas do sistema de arquivos contêineres para o caminho do host. Os caminhos são relativos à raiz do sistema de arquivos. #> docker cp 7bb0e258aefe: / etc / debian_version. #> docker cp blue_frog: / etc / hosts.
Amos Folarin
4
A opção 4 é tão importante que deve ser movida para o topo e renomeada Option 1.
automorphic
5
@JanusTroelsen Se não houver shell você pode instalá-lo - por exemplo, em dockerfile para linux alpino (que na verdade não tem shell) por: RUN apk update && apk add bash(Tamanho: ~ 4MB)
Kamil Kiełczewski
2
de acordo com minha própria experiência, a limitação do exec do Docker é que o comando deve ser adicionado a um contêiner em execução ou como um tipo de ponto de entrada. Portanto, um contêiner parado está fora do escopo desse método.
Webwoman
1
Para usar uso shell linux da Janeladocker exec -t -i mycontainer /bin/sh
Jason Mestres
266

ATUALIZAÇÃO: EXPLORANDO!

Este comando deve permitir que você explore um contêiner de estivador em execução :

docker exec -it name-of-container bash

O equivalente para isso na janela de encaixe-composição seria:

docker-compose exec web bash

(web é o nome do serviço nesse caso e tem tty por padrão.)

Quando estiver dentro, faça:

ls -lsa

ou qualquer outro comando bash como:

cd ..

Este comando deve permitir que você explore uma imagem da janela de encaixe :

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

uma vez dentro faça:

ls -lsa

ou qualquer outro comando bash como:

cd ..

A -itsignifica interativo ... e tty.


Este comando deve permitir que você inspecione um contêiner ou imagem do docker em execução :

docker inspect name-of-container-or-image

Você pode fazer isso e descobrir se há algum bash oush lá dentro. Procure o ponto de entrada ou cmd no retorno do json.

Vejo documentação executável do docker

Vejo executor de doca-composição

consulte a janela de encaixe inspecionar a documentação

Khalil Gharbaoui
fonte
1
Isso é extremamente útil, obrigado! Eu preciso arrastar e soltar um arquivo contido dentro de uma estrutura de arquivo de imagem do Docker em um aplicativo, mas isso não será possível a menos que seja aberto em um formato GUI. Alguma idéia de como eu poderia resolver isso?
Arkya Chatterjee
2
Deve ser bastante óbvio que isso funcionará apenas em um contêiner com o bash instalado.
Engenheiro de software
2
Para qualquer um que olha como fazer isso em um Windows Container / Powershell, o comando é docker exec -ti <name> powershell( fonte )
ssell
1
@ssell meu container / imagem não possui PowerShell por algum motivo, então docker exec -ti <name> cmdfuncionou. E para outros iniciantes como eu, certifique-se de usar o nome da instância do contêiner docker ps(algo como 070494393ca5) em vez do nome legível que você atribuiu a ele.
Simon_Weaver
1
sobre o powershell nas imagens github.com/aspnet/aspnet-docker/issues/362 - e se você precisar apenas se curvar nas imagens do Windows: blogs.technet.microsoft.com/virtualization/2017/12/19/…
Simon_Weaver
162

Caso seu contêiner esteja parado ou não possua um shell (por exemplo, hello-worldmencionado no guia de instalação ou não alpine traefik), este é provavelmente o único método possível de explorar o sistema de arquivos.

Você pode arquivar o sistema de arquivos do seu contêiner no arquivo tar:

docker export adoring_kowalevski > contents.tar

Ou liste os arquivos:

docker export adoring_kowalevski | tar t

Observe que, dependendo da imagem, pode levar algum tempo e espaço em disco.

Ilya Murav'jov
fonte
12
Eu simplesmente queria listar o conteúdo de um contêiner que não possui ferramentas UNIX padrão instaladas. Uma variação do exportexemplo acima atingiu o ponto:docker export adoring_kowalevski | tar tf -
berto
3
Um aviso para os incautos: isso pode exportar muitos dados (> GB) e levar muito tempo.
Vince Bowdren
5
@berto não que seja uma coisa massiva, mas você não precisa f -no final do seu comando, o tar lê da entrada padrão por padrão. Simplesmente docker export adoring_kowalevski | tar tfunciona.
Shaun Bouckaert
Quanto mais simples, melhor; incrível, obrigado pela dica! B
berto
1
@ShaunBouckaert o padrão para tar fdepende da configuração de alguém. Uma parte é a TAPEvariável de ambiente. Outros são controlados como parte da construção. O efeito líquido é que nunca se deve assumir que lê stdin ou escreve stdout, mas sempre declare explicitamente.
roaima
42

O sistema de arquivos do contêiner está na pasta de dados da janela de encaixe, normalmente em / var / lib / docker. Para iniciar e inspecionar um sistema de arquivos de contêineres em execução, faça o seguinte:

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

E agora o diretório de trabalho atual é a raiz do contêiner.

Rovanion
fonte
3
isso não inclui nenhum volume montado.
hwjp
34

Antes da criação do contêiner:

Se você explorar a estrutura da imagem montada dentro do contêiner, poderá fazer

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

Isso lhe daria a visibilidade de todas as camadas de uma imagem e sua configuração, presente nos arquivos json.

Após a criação do contêiner:

Para isso, já existem muitas respostas acima. minha maneira preferida de fazer isso seria -

docker exec -t -i container /bin/bash
Gaurav24
fonte
Consulte também sreeninet.wordpress.com/2016/06/11/… .
Jaime Hablutzel
Deve-se mencionar aqui que a execução do bash dentro do contêiner só funcionará se você estiver fazendo isso na máquina com a mesma arquitetura da imagem. Se você estiver no PC tentando espiar o sistema de arquivos de imagem do raspberry pi, o truque do bash não funcionará.
Maxim Kulkin
@MaximKulkin Realmente? Se o contêiner for Linux, não importa qual seja o host, se o bash estiver disponível. Talvez você esteja pensando em contêineres do Windows?
Thorbjørn Ravn Andersen
26

A resposta mais votada está funcionando para mim quando o contêiner é realmente iniciado, mas quando não é possível executar e você, por exemplo, deseja copiar arquivos do contêiner, isso me salvou antes:

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

Graças ao docker cp ( link ), você pode copiar diretamente do contêiner, como qualquer outra parte do seu sistema de arquivos. Por exemplo, recuperando todos os arquivos dentro de um contêiner:

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

Observe que você não precisa especificar que deseja copiar recursivamente.

Julius Printz
fonte
6
por que isso não tem mais +1? definitivamente a melhor maneira
Nicholas DiPiazza
Isso é ainda mais simples do que exportar via alcatrão. Eu tive que usar -L para acessar os arquivos através de links simbólicos. Não há necessidade de executar o contêiner!
MKaama 26/07/19
17

No Ubuntu 14.04, executando o Docker 1.3.1 , encontrei o sistema de arquivos raiz do contêiner na máquina host no seguinte diretório:

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

Informações completas da versão do 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
fonte
Funciona como um encanto: name = <name> dockerId = $ (docker inspeciona -f {{.Id}} $ name) / var / lib / docker / devicemapper / mnt / $ dockerId / rootfs /
Florent
3
Com o Ubuntu 16.10 e o docker 1.12.1, infelizmente este não é mais o caso (sem devicemapperdiretório). O arquivo existe em /var/lib/docker/overlay/<a sha256 apparently/<upper or merged>/.... Não estou certo como portátil / seguro é acessar arquivos lá
woj
1
A partir da 1.10, o Docker introduziu um novo modelo de armazenamento endereçável por conteúdo, que não usa UUID gerado aleatoriamente, como era anteriormente para identificadores de camada e contêiner. No novo modelo, isso é substituído por um hash de conteúdo seguro para o ID da camada. Portanto, esse método não funcionará mais.
Artem Dolobanko 10/03
Isso não é portátil e depende muito da escolha do driver de armazenamento . Não tenho certeza se a solução funcionará, direct-lvmpor exemplo.
Rustyx # 23/18
14

Tente usar

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

Pode haver possibilidade de que o bash não seja implementado. para isso você pode usar

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

Eu uso outro truque sujo que é aufs / devicemapper agnóstico.

Eu olho para o comando que o contêiner está executando, por exemplo, docker ps e se é um apache ou javaeu apenas faço o seguinte:

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

e voilá você está dentro do contêiner.

Basicamente, você pode colocar o CD raiz na /proc/<PID>/root/pasta, desde que esse processo seja executado pelo contêiner. Cuidado com links simbólicos não fará sentido usar esse modo.

telamon
fonte
Informações adicionais sobre esse método aqui: superuser.com/a/1288058/195840
Eduardo Lucio
12

A resposta mais votada é boa, exceto se o seu contêiner não for um sistema Linux real.

Muitos contêineres (especialmente os baseados em go) não têm nenhum binário padrão (nenhum /bin/bashou/bin/sh ). Nesse caso, você precisará acessar o arquivo de contêineres diretamente:

Funciona como um encanto:

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: Você precisa executá-lo como root.

Florent
fonte
Isso não funciona mais. A pasta devicemapper não está lá.
0xcaff
Seria bom se as pessoas com respostas desatualizadas seria limpá-los
Matthew Purdon
2
Atualizei o comando para corresponder à nova estrutura de armazenamento do Docker.
Florent
10

No meu caso, nenhum shell era suportado no contêiner, exceto sh. Então, isso funcionou como um encanto

docker exec -it <container-name> sh
shx
fonte
10

você pode usar o mergulho para visualizar o conteúdo da imagem interativamente com a TUI

https://github.com/wagoodman/dive

insira a descrição da imagem aqui

Andy Wong
fonte
O mergulho é realmente a ferramenta perfeita!
Laurent
5

Isso iniciará uma sessão do bash para a imagem:

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

LeYAUable
fonte
1
isso é útil quando o ponto de entrada padrão não é executado
analisa
4

Para mim, este funciona bem (graças aos últimos comentários por apontar o diretório / var / lib / docker / ):

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

Aqui, 2465790aa2c4 é o ID curto do contêiner em execução (conforme exibido pelo docker ps ), seguido por uma estrela.

dashohoxha
fonte
4

Nas versões mais recentes do Docker, você pode executar docker exec [container_name]um shell dentro do contêiner

Então, para obter uma lista de todos os arquivos em um contêiner, execute docker exec [container_name] ls

xrh
fonte
1
Eu tentei isso e não funcionou. A sugestão de Khalil Gharbaoui acima funcionou.
Nick
Isso funcionou para mim. Você também pode tentar com o ID de recipiente em vez do nome da imagem
Diwann
4

Para o docker aufs driver:

O script encontrará o diretório raiz do contêiner (Teste no docker 1.7.1 e 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
fonte
4

Nenhuma das respostas existentes trata do caso de um contêiner que saiu (e não pode ser reiniciado) e / ou não possui nenhum shell instalado (por exemplo, sem distração). Este funciona desde que você tenha acesso root ao host do Docker.

Para uma inspeção manual real, descubra primeiro os IDs da camada:

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

Na saída, você verá algo como

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

Navegue até esta pasta (como root) para encontrar o estado visível atual do sistema de arquivos do contêiner.

Rafael
fonte
3

Esta resposta ajudará aqueles (como eu) que desejam explorar o sistema de arquivos de volume do docker, mesmo que o contêiner não esteja em execução.

Lista de contêineres de docker em execução:

docker ps

=> ID DO RECIPIENTE "4c721f1985bd"

Observe os pontos de montagem do volume da janela de encaixe na sua máquina física local ( https://docs.docker.com/engine/tutorials/dockervolumes/ ):

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

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

Isso indica que o diretório da máquina física local / tmp / container-garren é mapeado para o destino do volume da janela de encaixe / tmp.

Conhecer o diretório da máquina física local (/ tmp / container-garren) significa que eu posso explorar o sistema de arquivos se o contêiner do docker está ou não em execução. Isso foi fundamental para me ajudar a descobrir que havia alguns dados residuais que não deveriam ter persistido mesmo depois que o contêiner não estava em execução.

Garren S
fonte
1
Isso localiza apenas um diretório local montado como um volume dentro do contêiner, mas não permite acessar todo o sistema de arquivos do contêiner.
Bojan Komazec
3

outro truque é usar a ferramenta atômica para fazer algo como:

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

A imagem do Docker será montada em / path / to / mnt para você inspecioná-la.

Giuseppe Scrivano
fonte
Mas você precisa ter recipientes feitos especialmente para isso funcionar, certo? Talvez você deve adicioná-lo como uma advertência, porque a maioria das pessoas não será capaz de vendê-lo para sua equipe / empresa como uma solução ...
Angelos Pikoulas
3

Somente para LINUX

A maneira mais simples de usar usando proc dir, que é o contêiner, deve estar em execução para inspecionar os arquivos do contêiner do docker.

  1. Descubra a identificação do processo (PID) do contêiner e armazene em alguma variável

    PID = $ (janela de encaixe inspeciona -f '{{.State.Pid}}' your-container-name-here)

  2. Verifique se o processo do contêiner está em execução e use a variável nameto para entrar na pasta do contêiner

    cd / proc / $ PID / root

Se você deseja passar pelo diretório sem descobrir o número PID, basta usar este comando longo

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

Dicas:

Depois de entrar no contêiner, tudo o que você fizer afetará o processo real do contêiner, como interromper o serviço ou alterar o número da porta.

Espero que ajude

Nota:

Esse método funciona apenas se o contêiner ainda estiver em execução, caso contrário, o diretório não existiria mais se o contêiner tivesse parado ou removido

Aditya Kresna Permana
fonte
2

Minha maneira preferida de entender o que está acontecendo dentro do contêiner é:

  1. expor -p 8000

    docker run -it -p 8000:8000 image
    
  2. Iniciar servidor dentro dele

    python -m SimpleHTTPServer
    
kgnete
fonte
2

Para um contêiner já em execução, você pode:

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

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

Você precisa ser root para entrar nesse diretório. Se você não é root, tente 'sudo su' antes de executar o comando.

Edit: Após a v1.3, veja a resposta de Jiri - é melhor.

AlonL
fonte
4
Sou fortemente parcial de "sudo -i" em vez de "sudo su" porque há poucas razões para executar um programa suid que lança outro programa suid que lança um shell. Corte o homem do meio. :)
dannysauer
Sua resposta é muito boa, apenas o caminho não é. Você deve usar o caminho do piercebot.
Florent
2

Se você estiver usando o Docker v19.03, siga as etapas abaixo.

# 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
fonte
1

Se você estiver usando o driver de armazenamento AUFS, poderá usar o script da camada de encaixe para encontrar a camada de raiz do sistema de arquivos (mnt) e a leitura e gravação de qualquer contêiner:

# 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 foi substituído por docker-backup

Vince
fonte
1

O docker execcomando para executar um comando em um contêiner em execução pode ajudar em vários casos.

Uso: docker exec [OPÇÕES] COMANDO DE RECIPIENTE [ARG ...]

Executar um comando em um contêiner em execução

Opções:
  -d, --detach Modo desanexado: execute o comando em segundo plano
      --detach-keys string Substitui a sequência de teclas para desanexar um
                             recipiente
  -e, --env list Definir variáveis ​​de ambiente
  -i, --interactive Mantenha o STDIN aberto, mesmo que não esteja conectado
      --privileged Concede privilégios estendidos ao comando
  -t, --tty Aloca um pseudo-TTY
  -u, --user string Nome de usuário ou UID (formato:
                             [:])
  -w, --workdir string Diretório de trabalho dentro do contêiner

Por exemplo :

1) Acessando no bash o sistema de arquivos do contêiner em execução:

docker exec -it containerId bash 

2) Acessando no bash o sistema de arquivos do contêiner em execução como root para poder ter os direitos necessários:

docker exec -it -u root containerId bash  

Isso é particularmente útil para poder fazer algum processamento como raiz em um contêiner.

3) Acesso no bash ao sistema de arquivos do contêiner em execução com um diretório de trabalho específico:

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

Você pode executar um bash dentro do contêiner com este: $ docker run -it ubuntu /bin/bash

Yang Yu
fonte