Copiando arquivos do host para o contêiner Docker

1581

Estou tentando criar uma solução de backup e restauração para os contêineres do Docker com os quais trabalhamos.

Eu tenho a imagem base do Docker que criei ubuntu:basee não quero reconstruí-la sempre com um arquivo do Docker para adicionar arquivos a ele.

Quero criar um script que seja executado na máquina host e crie um novo contêiner usando a ubuntu:baseimagem do Docker e copie os arquivos para esse contêiner.

Como posso copiar arquivos do host para o contêiner?

user3001829
fonte
12
Se você não deseja reconstruir, por que não " docker commit "? Isso salva sua imagem.
Berend de Boer
28
Apenas uma observação sobre uma noção que ninguém abordou: em geral, trate os recipientes como "efêmeros". Existem casos de uso para copiar arquivos para / de um contêiner em execução (teste, prototipagem). Mas se você estiver em uma posição em que não poderá reconstruir o que precisa usando os Dockerfiles e / ou compor, poderá estar em um lugar ruim. Geralmente, você não deseja fazer backup de contêineres como se fossem objetos de SO ou VM. De um modo geral :-)
Scott Prive

Respostas:

2674

O cpcomando pode ser usado para copiar arquivos.

Um arquivo específico pode ser copiado para o contêiner, como:

docker cp foo.txt mycontainer:/foo.txt

Um arquivo específico pode ser copiado do contêiner, como:

docker cp mycontainer:/foo.txt foo.txt

Para dar ênfase, mycontaineré um ID de contêiner , não um ID de imagem .

Vários arquivos contidos na pasta srcpodem ser copiados para a targetpasta usando:

docker cp src/. mycontainer:/target
docker cp mycontainer:/src/. target

Referência: documentos da CLI do Docker paracp

Nas versões do Docker anteriores à 1.8, só era possível copiar arquivos de um contêiner para o host. Não do host para um contêiner.

0x7d7b
fonte
2
Também note que este pode estar no vm host ou OS principal e funciona tanto anfitrião a embalagem ou o vm para host (ou OS principal)
Adam Tuliper - MSFT
7
Em um Dockerfile, você pode usar a palavra-chave ADD para adicionar arquivos durante o tempo de compilação.
0x7d7b
4
@ h3nrik COPYprefereADD quando aplicável.
Franklin Yu
10
usar docker cppara copiar do contêiner para o host funciona bem, mas quando usá-lo para copiar arquivos do host para o contêiner, sem efeito ... alguém sabe por quê? versão do docker: Docker versão 1.10.3, compilação cb079f6-sem suporte
Ace.Yin
2
Posso copiar vários arquivos usando o docker cp do host para o contêiner?
Yogesh
182
  1. Obter nome do container ou ID curto do container:

    $ docker ps
    
  2. Obter código completo do contêiner:

    $ docker inspect -f   '{{.Id}}'  SHORT_CONTAINER_ID-or-CONTAINER_NAME
    
  3. Copiar arquivo:

    $ sudo cp path-file-host /var/lib/docker/aufs/mnt/FULL_CONTAINER_ID/PATH-NEW-FILE
    

EXEMPLO:

$ docker ps

CONTAINER ID      IMAGE    COMMAND       CREATED      STATUS       PORTS        NAMES

d8e703d7e303   solidleon/ssh:latest      /usr/sbin/sshd -D                      cranky_pare

$ docker inspect -f   '{{.Id}}' cranky_pare

ou

$ docker inspect -f   '{{.Id}}' d8e703d7e303

d8e703d7e3039a6df6d01bd7fb58d1882e592a85059eb16c4b83cf91847f88e5

$ sudo cp file.txt /var/lib/docker/aufs/mnt/**d8e703d7e3039a6df6d01bd7fb58d1882e592a85059eb16c4b83cf91847f88e5**/root/file.txt
solidleon
fonte
13
Para mim, o caminho de montagem do host não continha aufsapenas a devicemapper. A maneira mais fácil de verificar o caminho de montagem dos contêineres (enquanto está em execução) é executar o comando mount.
Derenio
3
Eu tentei a solução acima. Ele copiou os arquivos no diretório específico do docker. No entanto, quando eu uso o bash para o contêiner do docker, os arquivos não aparecem lá. Há algo que estou perdendo?
AppleBud
2
O novo caminho é / var / lib / docker / devicemapper / mnt / <<idid>> / rootfs /
mcuadros
4
Para mim, no Docker 1.4.1 (atual atual), é/var/lib/docker/aufs/diff/<id>/
user193130 22/15/15
3
e quanto aos usuários pobres de MacOS? O diretório de montagem é /var/libpara mim. find / -name dockertambém não foi útil.
Prayagupd
141

A maneira mais limpa é montar um diretório de host no contêiner ao iniciar o contêiner:

{host} docker run -v /path/to/hostdir:/mnt --name my_container my_image
{host} docker exec -it my_container bash
{container} cp /mnt/sourcefile /path/to/destfile
Ben Davis
fonte
3
como você pode executar o contêiner? Eu pensei que você poderia fazer isso apenas com uma imagem.
Pavel Zaitsev
Não consigo fazê-lo funcionar quando o contêiner existe, ou seja, já foi executado antes. O alcatrão abaixo funciona bem.
Eino Mäkitalo
1
A única maneira que funcionou para mim foi anexar o volume ao lado de executar a imagem (instanciar o contêiner). Acabou com:docker run -d -p -v /host/path:/mnt --name container_name image_name
peter n
2
Isso não funciona para mim. Pelo menos não pode executar um contêiner. Só pode executar imagem #
Shashank Hegde
1
Estou surpreso que docker cpseja uma operação de mão única!
ThorSummoner
115

A seguir, é uma maneira bastante feia de fazê-lo, mas funciona.

docker run -i ubuntu /bin/bash -c 'cat > file' < file
Erik
fonte
7
Isso funciona muito bem! Mas não se esqueça de confirmar a alteração: docker commit `docker ps -l -q` ubuntu-with-file. Então a mudança será perdido (use o nome que você quer em vez de ubuntu-with-file)
Michael_Scharf
@Erik: Onde o arquivo localizado quando o contêiner está sendo executado?
coanor
49
Além disso, podemos usar o novo docker execrecurso para trabalhar com contêiner em execução:docker exec -it <container_id> bash -c 'cat > /path/to/container/file' < /path/to/host/file/
Mikl
17
@ Mikl Eu acho que deveria ser em docker exec -i ...vez de -it, porque não há TTY ao canalizar de um arquivo.
z0r 24/05
4
Se você ainda estiver preso em uma versão antiga do Docker (como eu sou) e quiser copiar um diretório inteiro, poderá fazer o seguinte: tar -c -v -f - /path/to/host/directory | docker exec -i <container-name> bash -c 'tar -x -v --strip-components 1 -f - -C /path/to/container/directory'
eahanson
43

Se você precisar fazer isso em um contêiner em execução, poderá usar o docker exec (adicionado em 1.3).

Primeiro, encontre o nome ou o ID do contêiner:

$ docker ps
CONTAINER ID        IMAGE                        COMMAND             CREATED             STATUS              PORTS                   NAMES
b9b7400ddd8f        ubuntu:latest                "/bin/bash"         2 seconds ago       Up 2 seconds                                elated_hodgkin

No exemplo acima, podemos usar b9b7400ddd8fou elated_hodgkin.

Se você deseja copiar tudo no /tmp/somefileshost para /var/wwwo contêiner:

$ cd /tmp/somefiles
$ tar -cv * | docker exec -i elated_hodgkin tar x -C /var/www

Podemos então executar /bin/bashno contêiner e verificar se funcionou:

$ docker exec -it elated_hodgkin /bin/bash
root@b9b7400ddd8f:/# ls /var/www
file1  file2
adean
fonte
Funciona muito bem no docker 1.16 no Centos 7.4 Ótima idéia inovadora.
Dudi Boy
41
  1. Crie um novo dockerfile e use a imagem existente como sua base.

    FROM myName/myImage:latest
    
    ADD myFile.py bin/myFile.py
    
  2. Em seguida, construa o contêiner:

    docker build .
    
RustyShackleford
fonte
2
Isto é o que funcionou para mim. Nada mais. Obrigado!
Owen
Ele criará uma nova imagem, não diretamente um novo contêiner. Se você reutilizar essa imagem enquanto o myFile.py for alterado, ele usará a versão mais antiga do arquivo, a menos que você reconstrua a imagem.
Guillaume Lebreton
Acho isso da maneira mais rápida apenas se você estiver testando em um servidor remoto.
Dominik Krulak
De acordo com isso, a maioria das pessoas deve usar COPY em vez de ADD. Mas para arquivos locais (como neste exemplo) eles são equivalentes.
hoosierEE 15/01
39

A solução é dada abaixo,

No shell do Docker,

root@123abc:/root#  <-- get the container ID

Do host

cp thefile.txt /var/lib/docker/devicemapper/mnt/123abc<bunch-o-hex>/rootfs/root

O arquivo deve ser copiado diretamente para o local em que o contêiner fica no sistema de arquivos.

perfurar
fonte
10
Ótima resposta. Em versões mais recentes docker o caminho foi renomeado para / var / lib / janela de encaixe / aufs / mnt /
Alex Volkov
o caminho devicemapper não parece funcionar no fedora com o docker 1.6. Coloque-o como um Q separado, stackoverflow.com/questions/29939419/… , quaisquer comentários serão apreciados.
Yogesh_D 29/04
33

Normalmente, existem três tipos:

  1. De um contêiner para o host

    docker cp container_id:./bar/foo.txt .
    

dev1

  1. Do host para um contêiner

    docker exec -i container_id sh -c 'cat > ./bar/foo.txt' < ./foo.txt
    

dev2

  1. De um contêiner para um contêiner, mistura 1 e 2

    docker cp container_id1:./bar/foo.txt .
    
    docker exec -i container_id2 sh -c 'cat > ./bar/foo.txt' < ./foo.txt
    

dev3

Ali Hallaji
fonte
6
O docker cp funciona nos dois sentidos. Não há necessidade de exec, cat e redirecionar. docker cp host_file.txt container: / path /
tbm
32

Outra solução para copiar arquivos em um contêiner em execução é usar tar:

tar -c foo.sh | docker exec -i theDockerContainer /bin/tar -C /tmp -x

Copia o arquivo foo.shno /tmpcontêiner.

Edit: Remove reduntant -f, graças ao comentário de Maarten .

joemat
fonte
Isso é bom se você precisar enviar um diretório inteiro. Para um único arquivo, a resposta de Erik é mais simples.
Kelvin #
1
@ Kelvin: Mas o tar também preserva os atributos e o nome do arquivo. Entre outros, isso significa que você só precisa digitar o nome uma vez (e você obtém a conclusão da guia no shell). Então, eu diria que o tar é realmente mais simples, desde que esteja instalado no contêiner.
Maarten
1
O -f -é um pouco redundante, porém, o comportamento padrão é escrever para stdout de qualquer maneira.
Maarten
Isto significa que há uma dependência de acolhimento de alcatrão
cellige
Você está certo - você precisa que o tar seja instalado no host e dentro do contêiner. Atualmente, o docker cp é a melhor solução.
Joemat
24

Para copiar um arquivo do host para o contêiner em execução

docker exec -i $CONTAINER /bin/bash -c "cat > $CONTAINER_PATH" < $HOST_PATH

Com base na resposta de Erik e nos comentários de Mikl e z0r.

Andrea
fonte
As soluções aceitas às vezes perturbam o recuo dos arquivos ao serem transferidos para contêineres em execução. Esta perfeito funciona para esses casos
Sonhos
15

Esta é uma resposta direta à pergunta 'Copiando arquivos do host para o contêiner do Docker' levantada nesta pergunta no título.

Tente docker cp. É a maneira mais fácil de fazer isso e funciona mesmo no meu Mac. Uso:

docker cp /root/some-file.txt some-docker-container:/root

Isso copiará o arquivo some-file.txtno diretório /rootda máquina host para o contêiner do Docker nomeado some-docker-containerno diretório/root . Está muito próximo da sintaxe da cópia segura. E, como mostrado no post anterior, você pode usá-lo vice-versa. Ou seja, você também copia arquivos do contêiner para o host.

E antes de fazer o link desta postagem, digite docker cp --help . A leitura da documentação pode ser muito útil, às vezes ...

Se você não gosta dessa maneira e deseja volumes de dados em seu contêiner já criado e em execução, a recreação é sua única opção hoje. Consulte também Como posso adicionar um volume a um contêiner do Docker existente? .

Hiro.Protagonist
fonte
15

Tentei a maioria das soluções (aprovadas) aqui, mas no docker 17.09 (em 2018) não há mais a pasta / var / lib / docker / aufs.

Este simples docker cpresolveu esta tarefa.

docker cp c:\path\to\local\file container_name:/path/to/target/dir/

Como obter container_name?

 docker ps 

Há uma NAMESseção. Não use a IMAGE.

Aerin
fonte
12

Para copiar arquivos / pastas entre um contêiner e o sistema de arquivos local, digite o comando:

docker cp {SOURCE_FILE} {DESTINATION_CONTAINER_ID}:/{DESTINATION_PATH}

Por exemplo,

docker cp /home/foo container-id:/home/dir

Para obter o ID do contianer, digite o comando fornecido:

docker ps

O conteúdo acima é retirado do docker.com .

prayagupd
fonte
8

Supondo que o contêiner já esteja em execução, digite o comando fornecido:

# cat /path/to/host/file/ | docker exec -i -t <container_id> bash -c "/bin/cat > /path/to/container/file"

Para compartilhar arquivos usando o diretório compartilhado, execute o contêiner digitando o comando fornecido:

# docker run -v /path/to/host/dir:/path/to/container/dir ...

Nota: Podem surgir problemas com as permissões, pois os usuários do contêiner não são iguais aos usuários do host.

johndodo
fonte
1
Além disso:docker exec -it <container_id> bash -c 'cat > /path/to/container/file' < /path/to/host/file/
Mikl
2
Observe que catnão será encerrado quando sair. Se isso for importante para você (se você estiver copiando scripts bash, o bash se recusará a executá-los), você deve executar lsof | grep yourfilenamee interromper o catprocesso que contém o referido arquivo.
Johndodo #
Valeu! Ótima dica. Você pode me dizer como matar esse processo com um comando? Algo como kill $(lsof | grep /path/to/file | sed ...). Serei grato por sua ajuda.
Mikl 14/11/14
kill $(docker top CONTAINERNAME | sed -n '/cat$/p' | sed 's/^root[^0-9]\+\([0-9]\+\).*$/\1/')
Mikl 14/11
8

Este é o comando para copiar dados do Docker para o Host:

docker cp container_id:file path/filename /hostpath

docker cp a13fb9c9e674:/tmp/dgController.log /tmp/

Abaixo está o comando para copiar dados do host para a janela de encaixe:

docker cp a.txt ccfbeb35116b:/home/
Maninder
fonte
7

Em um ambiente de docker, todos os contêineres são encontrados no diretório:

/var/lib/docker/aufs/required-docker-id/

Para copiar o diretório / arquivo de origem para qualquer parte do contêiner, digite o comando fornecido:

sudo cp -r mydir/ /var/lib/docker/aufs/mnt/required-docker-id/mnt/

0x3bfc
fonte
5

tare docker cpsão uma boa combinação para copiar tudo em um diretório.

Crie um contêiner de volume de dados

docker create --name dvc --volume /path/on/container cirros

Para preservar a hierarquia de diretórios

tar -c -C /path/on/local/machine . | docker cp - dvc:/path/on/container

Verifique seu trabalho

docker run --rm --volumes-from dvc cirros ls -al /path/on/container
Everett Toews
fonte
5

Se o host for CentOS ou Fedora, existe um proxy NOT in /var/lib/docker/aufs, mas está abaixo de /proc:

cp -r /home/user/mydata/* /proc/$(docker inspect --format "{{.State.Pid}}" <containerid>)/root

Este cmd copiará todo o conteúdo do datadiretório para o /container com o ID "containerid".

Abdennour TOUMI
fonte
Isso não é exclusivo do Redhat: ele também funciona no Debian. (talvez todo o Gnu / Linux com /proc). Também estenda o caminho para colocar o arquivo em outro lugar, não apenas o root.
CTRL-ALT-DELOR
5

Caso não esteja claro para alguém como eu o que mycontainerna resposta @ h3nrik significa, na verdade, é o ID do contêiner. Para copiar um arquivo WarpSquare.mp4em /app/example_scenes/1440p60partir de um recipiente janela de encaixe saiu a pasta atual eu usei isso.

docker cp `docker ps -q -l`:/app/example_scenes/1440p60/WarpSquare.mp4 .

onde docker ps -q -lpuxa o ID do contêiner da última instância encerrada. Caso não seja um contêiner encerrado, você pode obtê-lo docker container lsoudocker ps

ishandutta2007
fonte
1
Você pode listar IDs de contêineres encerrados com docker ps -aou docker container ls -a.
0x7d7b 08/08/19
4

Muitos que encontram essa pergunta podem realmente ter o problema de copiar arquivos em uma imagem do Docker enquanto ela está sendo criada (eu fiz).

Nesse caso, você pode usar o COPYcomando Dockerfileusado para criar a imagem.

Veja a documentação .

Klas Mellbourn
fonte
4

Você pode apenas rastrear o endereço IP da sua máquina local usando

ifconfig

Em seguida, basta entrar no seu contêiner Docker e digite

scp user_name@ip_address:/path_to_the_file destination

De qualquer forma, se você não tiver um cliente e servidor SSH instalado, basta instalá-lo usando:

sudo apt-get install openssh-server
Harshit Anand
fonte
Muito obrigado, funcionou bem para mim. Além disso, eu o achei mais eficiente do que outras maneiras
#
Esta é uma solução horrível em termos de segurança.
4

Este é um onliner para copiar um único arquivo enquanto executa um contêiner de tomcat.

docker run -v /PATH_TO_WAR/sample.war:/usr/local/tomcat/webapps/myapp.war -it -p 8080:8080 tomcat

Isso copiará o arquivo war para o diretório webapps e fará com que seu aplicativo seja executado rapidamente.

karthik101
fonte
1
-v irá montar (ou seja, criar um link), não copiar
Vitaliy Ulantikov
a diferença no resultado é que a montagem esconde o conteúdo do recipiente anterior, por exemplo, se você montar uma pasta de acolhimento em um recipiente pasta que você não pode mais ver o conteúdo da pasta recipiente anterior
mrq
4

Sintaxe de Container Up:

 docker run -v /HOST/folder:/Container/floder 

Na janela de encaixe Arquivo

COPY hom* /myFolder/        # adds all files starting with "hom"
COPY hom?.txt /myFolder/    # ? is replaced with any single character, e.g., "home.txt"
Isura Nimalasiri
fonte
3

A melhor maneira de copiar arquivos para o contêiner que encontrei é montar um diretório no host usando a -vopção do comando docker run.

Prakash Varandani
fonte
3

Existem boas respostas, mas muito específicas. Descobri que docker psé uma boa maneira de obter o ID do contêiner de seu interesse.

mount | grep <id>

para ver onde o volume está montado. Isso é

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

para mim, mas pode ser um caminho diferente, dependendo do sistema operacional e da configuração. Agora simplesmente copie os arquivos para esse caminho.

O uso -vnem sempre é prático.

akostadinov
fonte
3

Comecei a usar o docker para compilar o VLC. Aqui está o que você pode fazer para copiar arquivos de um lado para outro dos contêineres:

su -
cd /var/lib/docker
ls -palR > /home/user/dockerfilelist.txt

Procure um arquivo familiar nesse txt e você terá a pasta, o cd como root e pronto! copie tudo o que quiser.

Pode haver um caminho com "mesclado", acho que você quer o caminho com "diff".

Além disso, se você sair do contêiner e quiser voltar ao ponto em que parou:

docker ps -a
docker start -i containerid

Eu acho que é útil quando você não nomeou nada com um comando como

docker run -it registry.videolan.org:5000/vlc-debian-win64 /bin/bash

Claro que o método hacker, mas e daí?

Colin Lamarre
fonte
3
docker cp SRC_PATH CONTAINER_ID:DEST_PATH

Por exemplo, quero copiar meu arquivo xxxx / download / jenkins para o tomcat

Começo a obter o ID do contêiner Tomcat

docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
63686740b488        tomcat              "catalina.sh run"   12 seconds ago      Up 11 seconds       0.0.0.0:8080->8080/tcp   peaceful_babbage

docker cp xxxx/download/jenkins.war  63686740b488:usr/local/tomcat/webapps/
Mourad MAMASSI
fonte
2

Meu método favorito:

RECIPIENTES:

CONTAINER_ID=$(docker ps | grep <string> | awk '{ print $1 }' | xargs docker inspect -f '{{.Id}}')

file.txt

mv -f file.txt /var/lib/docker/devicemapper/mnt/$CONTAINER_ID/rootfs/root/file.txt

ou

mv -f file.txt /var/lib/docker/aufs/mnt/$CONTAINER_ID/rootfs/root/file.txt
user3159411
fonte
o caminho devicemapper não parece funcionar no fedora com o docker 1.6. Coloque-o como um Q separado, stackoverflow.com/questions/29939419/… , quaisquer comentários serão apreciados.
Yogesh_D 29/04
2

Na minha opinião, você não precisa copiar arquivos dentro da imagem, mas pode usar GIT ou SVN para seus arquivos e definir um volume sincronizado com uma pasta local. Use um script ao executar o contêiner, que pode verificar se os dados já existem na pasta local, se não os copiar do repositório GIT. Isso torna sua imagem muito leve.

h.aittamaa
fonte
Isso parece um risco à segurança e pesadelo de acesso esperando para acontecer. Como você fornece acesso ao repositório git de dentro da sua imagem? Mesmo assumindo que é um repositório público, você assumirá que o host em que o contêiner é executado tem acesso a esse repositório.
tbm
Concordo com você se o git for usado dentro do contêiner do docker. Mas, no nosso caso, o script está sendo executado na máquina host
h.aittamaa