Kopiowanie plików z hosta do kontenera Docker

1574

Próbuję zbudować rozwiązanie do tworzenia kopii zapasowych i przywracania dla kontenerów Docker, z którymi współpracujemy.

Mam podstawowy obraz Dockera, który utworzyłem ubuntu:basei nie chcę go za każdym razem przebudowywać za pomocą pliku Docker, aby dodać do niego pliki.

Chcę utworzyć skrypt uruchamiany z komputera hosta i tworzy nowy kontener za pomocą ubuntu:baseobrazu Docker, a następnie kopiuje pliki do tego kontenera.

Jak mogę skopiować pliki z hosta do kontenera?

użytkownik3001829
źródło
11
Jeśli nie chcesz odbudowywać, dlaczego nie „ zatwierdzić dokera ”? To zapisuje twój obraz.
Berend de Boer
26
Tylko uwaga na temat pojęcia, do którego nikt się nie odniósł: ogólnie traktuj pojemniki jako „efemeryczne”. Istnieją przypadki użycia do kopiowania plików do / z działającego kontenera (testowanie, prototypowanie). Ale jeśli znajdziesz się w sytuacji, w której nie możesz odbudować tego, czego potrzebujesz za pomocą Dockerfiles i / lub komponować, możesz być w złym miejscu. Zasadniczo nie chcesz tworzyć kopii zapasowych kontenerów tak, jakby były one obiektami systemu operacyjnego lub nawet maszyn wirtualnych. Ogólnie rzecz biorąc :-)
Scott Prive

Odpowiedzi:

2670

cpKomenda może być używany do kopiowania plików.

Jeden konkretny plik można skopiować do kontenera, na przykład:

docker cp foo.txt mycontainer:/foo.txt

Jeden konkretny plik można skopiować z kontenera, np .:

docker cp mycontainer:/foo.txt foo.txt

Dla podkreślenia, mycontainerto pojemnik ID, nie obrazu ID.

Wiele plików zawartych w folderze srcmożna skopiować do targetfolderu za pomocą:

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

Odniesienie: Dokumentacja interfejsu Docker CLI dlacp

W wersjach Docker wcześniejszych niż 1.8 możliwe było tylko kopiowanie plików z kontenera na host. Nie od hosta do kontenera.

0x7d7b
źródło
2
zauważ również, że może to być na vm hosta lub głównym systemie operacyjnym i działa albo z hosta do kontenera, albo z vm na hosta (lub main os)
Adam Tuliper - MSFT
7
W Dockerfile możesz użyć słowa kluczowego ADD, aby dodać pliki podczas kompilacji.
0x7d7b
4
@ h3nrik COPYpreferowane,ADD jeśli dotyczy.
Franklin Yu,
10
służy docker cpdo kopiowania z kontenera do hosta działa dobrze, ale kiedy używasz go do kopiowania plików z hosta do kontenera, bez efektu ... ktoś wie dlaczego? wersja dokera: wersja Docker 1.10.3, kompilacja cb079f6-nieobsługiwana
Ace.Yin
2
Czy mogę skopiować wiele plików przy użyciu dokera cp z hosta do kontenera?
Jogesh,
182
  1. Uzyskaj nazwę kontenera lub krótki identyfikator kontenera:

    $ docker ps
    
  2. Uzyskaj pełny identyfikator kontenera:

    $ docker inspect -f   '{{.Id}}'  SHORT_CONTAINER_ID-or-CONTAINER_NAME
    
  3. Skopiować plik:

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

PRZYKŁAD:

$ 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

lub

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

d8e703d7e3039a6df6d01bd7fb58d1882e592a85059eb16c4b83cf91847f88e5

$ sudo cp file.txt /var/lib/docker/aufs/mnt/**d8e703d7e3039a6df6d01bd7fb58d1882e592a85059eb16c4b83cf91847f88e5**/root/file.txt
solidleon
źródło
13
Dla mnie ścieżka montowania hosta nie zawierała, aufstylko devicemapper. Najłatwiejszym sposobem sprawdzenia ścieżki montażu kontenerów (gdy jest ona uruchomiona) jest uruchomienie polecenia mount.
derenio
3
Wypróbowałem powyższe rozwiązanie. Skopiował pliki do określonego katalogu dokera. Jednak gdy używam bash jako kontenera dokującego, pliki się tam nie wyświetlają. Czy czegoś brakuje?
AppleBud,
2
Nowa ścieżka to / var / lib / docker / devicemapper / mnt / <<id>> / rootfs /
mcuadros
4
Dla mnie, w Docker 1.4.1 (najnowszy najnowszy), to/var/lib/docker/aufs/diff/<id>/
193130
3
co z biednymi użytkownikami MacOS? Katalog montowania jest /var/libdla mnie. find / -name dockerteż nie było pomocne.
prayagupd
141

Najczystszym sposobem jest zamontowanie katalogu hosta na kontenerze podczas uruchamiania kontenera:

{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
źródło
3
jak uruchomić kontener? myślałem, że możesz to zrobić tylko z obrazem.
Pavel Zaitsev
Nie mogę go uruchomić, gdy istnieje kontener, czyli wcześniej działał jako aka. Smoła poniżej działa dobrze.
Eino Mäkitalo
1
Jedynym sposobem, w jaki mi to działało, było dołączenie woluminu wraz z uruchomieniem obrazu (utworzenie instancji kontenera). Skończyło się na:docker run -d -p -v /host/path:/mnt --name container_name image_name
Peter n
2
To mi nie działa. Przynajmniej nie można uruchomić kontenera. Można uruchomić tylko obraz
Shashank Hegde
1
Dziwi mnie, że docker cpto operacja jednostronna!
ThorSummoner
115

Poniższy sposób jest dość brzydki, ale działa.

docker run -i ubuntu /bin/bash -c 'cat > file' < file
Erik
źródło
7
To działa świetnie! Ale nie zapomnij, aby zatwierdzić zmiany: docker commit `docker ps -l -q` ubuntu-with-file. W przeciwnym razie zmiana zostanie utracona (użyj dowolnego imienia zamiast ubuntu-with-file)
Michael_Scharf,
@Erik: Gdzie znajduje się plik podczas działania kontenera?
coanor,
49
Dodatkowo możemy użyć nowej docker execfunkcji do pracy z uruchomionym kontenerem:docker exec -it <container_id> bash -c 'cat > /path/to/container/file' < /path/to/host/file/
Mikl
17
@Mikl Myślę, że powinno być docker exec -i ...zamiast -it, ponieważ nie ma TTY podczas przesyłania z pliku.
z0r
4
Jeśli nadal tkwisz w starej wersji Dockera (tak jak ja) i chcesz skopiować cały katalog, możesz to zrobić: 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

Jeśli musisz to zrobić na działającym kontenerze, możesz użyć exec Dockera (dodany w 1.3).

Najpierw znajdź nazwę lub identyfikator pojemnika:

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

W powyższym przykładzie możemy użyć b9b7400ddd8falbo elated_hodgkin.

Jeśli chcesz skopiować wszystko /tmp/somefilesna hoście do /var/wwwkontenera:

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

Następnie możemy wykonać /bin/bashw kontenerze i sprawdzić, czy zadziałało:

$ docker exec -it elated_hodgkin /bin/bash
root@b9b7400ddd8f:/# ls /var/www
file1  file2
adean
źródło
Działa świetnie w oknie dokowanym 1.16 w Centos 7.4 Świetny innowacyjny pomysł.
Dudi Boy
41
  1. Utwórz nowy plik dokera i użyj istniejącego obrazu jako podstawy.

    FROM myName/myImage:latest
    
    ADD myFile.py bin/myFile.py
    
  2. Następnie zbuduj kontener:

    docker build .
    
RustyShackleford
źródło
2
To działało dla mnie. Nic więcej. Dziękuję Ci!
Owen
Stworzy nowy obraz, a nie bezpośrednio nowy kontener. Jeśli użyjesz tego obrazu ponownie, gdy plik myFile.py został zmieniony, użyje starszej wersji pliku, chyba że odbudujesz obraz.
Guillaume Lebreton,
Uważam to za najszybszy sposób tylko wtedy, gdy testujesz na zdalnym serwerze.
Dominik Krulak,
Zgodnie z tym większość ludzi powinna używać KOPIOWANIA zamiast DODAJ. Ale dla plików lokalnych (jak w tym przykładzie) są one równoważne.
hoosierEE
39

Rozwiązanie podano poniżej,

Z powłoki Dockera

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

Od gospodarza

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

Plik należy skopiować bezpośrednio do lokalizacji, w której kontener znajduje się w systemie plików.

przebić
źródło
10
Świetna odpowiedź. W nowszych wersjach dokera nazwa ścieżki została zmieniona na / var / lib / docker / aufs / mnt /
Alex Volkov
ścieżka devicemapper nie wydaje się działać na fedorze z dokerem 1.6. Postawiłem to jako osobne Q, stackoverflow.com/questions/29939419/… , wszelkie komentarze będą mile widziane.
Yogesh_D
33

Zazwyczaj są trzy typy:

  1. Od kontenera do hosta

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

dev1

  1. Od hosta do kontenera

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

dev2

  1. Z pojemnika do pojemnika miesza 1 i 2

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

dev3

Ali Hallaji
źródło
6
docker cp działa w obie strony. Nie trzeba wykonywać poleceń, cat i przekierowywać. docker cp plik_hosta.txt kontener: / path /
tbm
32

Innym rozwiązaniem do kopiowania plików do działającego kontenera jest użycie tar:

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

Kopiuje plik foo.shdo /tmpkontenera.

Edycja: Usuń reduntant -f, dzięki komentarzowi Maarten .

joemat
źródło
Jest to dobre, jeśli musisz wysłać cały katalog. W przypadku pojedynczego pliku odpowiedź Erika jest prostsza.
Kelvin,
1
@ Kelvin: Ale tar zachowuje również atrybuty i nazwę pliku. Oznacza to między innymi, że musisz wpisać nazwę tylko raz (i tam otrzymasz uzupełnienie tabulatora ze swojej powłoki). Powiedziałbym więc, że tar jest w rzeczywistości prostszy, o ile jest zainstalowany w kontenerze.
Maarten,
1
Jest -f -to jednak trochę zbędne, domyślnym zachowaniem jest jednak pisanie na standardowe wyjście.
Maarten,
oznacza to, że istnieje zależność hosta od tar
cellige
Masz rację - musisz zainstalować tar na hoście i w kontenerze. Obecnie używanie dokera cp jest lepszym rozwiązaniem.
joemat
24

Aby skopiować plik z hosta do uruchomionego kontenera

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

Na podstawie odpowiedzi Erika i komentarzy Mikla i z0r.

Andrea
źródło
Przyjęte rozwiązania czasami zakłócają wcięcia plików podczas przesyłania do uruchomionych kontenerów. Działa to idealnie w takich przypadkach
Dreams
15

To jest bezpośrednia odpowiedź na pytanie „Kopiowanie plików z hosta do kontenera Docker” postawione w tym pytaniu w tytule.

Spróbować docker cp. Jest to najprostszy sposób, aby to zrobić i działa nawet na moim komputerze Mac. Stosowanie:

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

Spowoduje to skopiowanie pliku some-file.txtz katalogu /rootna komputerze hosta do kontenera Docker o nazwie podanej w some-docker-containerkatalogu /root. Jest to bardzo zbliżone do bezpiecznej składni kopii. I jak pokazano w poprzednim poście, możesz użyć go na odwrót. To znaczy, kopiujesz również pliki z kontenera na host.

I zanim prześlesz ten post w dół, wpisz docker cp --help. Czytanie dokumentacji może być bardzo pomocne, czasami ...

Jeśli nie podoba ci się w ten sposób i chcesz mieć woluminy danych w już utworzonym i działającym kontenerze, odtwarzanie jest dziś twoją jedyną opcją. Zobacz także Jak mogę dodać wolumin do istniejącego kontenera Docker? .

Hiro.Protagonist
źródło
15

Wypróbowałem tutaj większość (pozytywnych) rozwiązań, ale w oknie dokowanym 17.09 (w 2018 r.) Nie ma już folderu / var / lib / docker / aufs.

To proste docker cprozwiązało to zadanie.

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

Jak zdobyć nazwę kontenera?

 docker ps 

Jest NAMESsekcja. Nie używaj IMAGE.

Aerin
źródło
12

Aby skopiować pliki / foldery między kontenerem a lokalnym systemem plików, wpisz polecenie:

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

Na przykład,

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

Aby uzyskać identyfikator contianer, wpisz podane polecenie:

docker ps

Powyższa treść pochodzi z witryny docker.com .

prayagupd
źródło
8

Zakładając, że kontener już działa, wpisz podane polecenie:

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

Aby udostępnić pliki za pomocą udostępnionego katalogu, uruchom kontener, wpisując podane polecenie:

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

Uwaga: mogą wystąpić problemy z uprawnieniami, ponieważ użytkownicy kontenera nie są tacy sami jak użytkownicy hosta.

johndodo
źródło
1
Ponadto:docker exec -it <container_id> bash -c 'cat > /path/to/container/file' < /path/to/host/file/
Mikl
2
Pamiętaj, że catnie zostanie zakończone po wyjściu. Jeśli ma to dla ciebie znaczenie (jeśli kopiujesz skrypty bash, bash odmówi ich uruchomienia), powinieneś uruchomić lsof | grep yourfilenamei zabić catproces, który przechowuje wspomniany plik.
johndodo
Dzięki! Świetna wskazówka. Czy możesz mi powiedzieć, jak zabić ten proces za pomocą jednego polecenia? Coś jak kill $(lsof | grep /path/to/file | sed ...). Będę wdzięczny za twoją pomoc
Mikl
kill $(docker top CONTAINERNAME | sed -n '/cat$/p' | sed 's/^root[^0-9]\+\([0-9]\+\).*$/\1/')
Mikl
8

Oto polecenie kopiowania danych z Dockera na Host:

docker cp container_id:file path/filename /hostpath

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

Poniżej znajduje się polecenie kopiowania danych z hosta do dokera:

docker cp a.txt ccfbeb35116b:/home/
Maninder
źródło
7

W środowisku dokera wszystkie kontenery znajdują się w katalogu:

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

Aby skopiować katalog / plik źródłowy do dowolnej części kontenera, wpisz podane polecenie:

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

0x3bfc
źródło
5

tari docker cpsą dobrym zestawem do kopiowania wszystkiego w katalogu.

Utwórz kontener woluminu danych

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

Aby zachować hierarchię katalogów

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

Sprawdź swoją pracę

docker run --rm --volumes-from dvc cirros ls -al /path/on/container
Everett Toews
źródło
5

Jeśli hostem jest CentOS lub Fedora, serwer proxy NIE jest w /var/lib/docker/aufs, ale znajduje się poniżej /proc:

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

To polecenie cmd skopiuje całą zawartość datakatalogu do /kontenera o identyfikatorze „containerid”.

Abdennour TOUMI
źródło
Nie jest to unikalne dla Redhat: działa również na Debianie. (może wszystkie Gnu / Linux z /proc). Rozszerz także ścieżkę, aby umieścić plik w innym miejscu, nie tylko root.
ctrl-alt-delor
5

W przypadku, gdy dla kogoś takiego jak ja nie jest jasne, co mycontaineroznacza odpowiedź @ h3nrik, w rzeczywistości jest to identyfikator kontenera. Aby skopiować plik WarpSquare.mp4w /app/example_scenes/1440p60od wyszły pojemnika Döcker do bieżącego folderu użyłem tego.

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

gdzie docker ps -q -lpobiera identyfikator kontenera ostatniej opuszczonej instancji. W przypadku, gdy nie jest to opuszczony pojemnik, możesz go zdobyć przez docker container lslubdocker ps

ishandutta2007
źródło
1
Możesz wyświetlić listę identyfikatorów wychodzących kontenerów za pomocą docker ps -alub docker container ls -a.
0x7d7b,
4

Wiele osób, które znajdą to pytanie, może faktycznie mieć problem z kopiowaniem plików do obrazu Docker podczas jego tworzenia (ja to zrobiłem).

W takim przypadku możesz użyć COPYpolecenia Dockerfileużytego do utworzenia obrazu.

Zobacz dokumentację .

Klas Mellbourn
źródło
4

Możesz po prostu prześledzić adres IP swojego komputera lokalnego za pomocą

ifconfig

Następnie po prostu wejdź do swojego kontenera Docker i wpisz

scp user_name@ip_address:/path_to_the_file destination

W każdym razie, jeśli nie masz zainstalowanego klienta SSH i serwera, po prostu zainstaluj go za pomocą:

sudo apt-get install openssh-server
Harshit Anand
źródło
Dzięki bardzo, działało to dla mnie dobrze. Ponadto uważam, że jest bardziej wydajny niż inne sposoby
user1314742,
To okropne rozwiązanie pod względem bezpieczeństwa.
4

Jest to narzędzie do kopiowania pojedynczego pliku podczas uruchamiania kontenera tomcat.

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

Spowoduje to skopiowanie pliku wojny do katalogu webapps i uruchomienie aplikacji w krótkim czasie.

karthik101
źródło
1
-v zamontuje (tzn. utworzy link), a nie kopiuje
Vitaliy Ulantikov
różnica w wyniku polega na tym, że podczas montowania ukrywa się poprzednia zawartość kontenera, np. jeśli zamontujesz folder hosta na folderze kontenera, nie będziesz już widzieć zawartości poprzedniego folderu kontenera
mrq
4

Składnia w górę kontenera:

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

W pliku dokera

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
źródło
3

Najlepszym sposobem na skopiowanie plików do kontenera, który znalazłem, jest zamontowanie katalogu na hoście przy użyciu -vopcji polecenia docker run.

Prakash Varandani
źródło
3

Istnieją dobre odpowiedzi, ale zbyt szczegółowe. Okazało się, że docker psto dobry sposób na uzyskanie identyfikatora kontenera, który Cię interesuje

mount | grep <id>

aby zobaczyć, gdzie zamontowano wolumin. To jest

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

dla mnie, ale może to być inna ścieżka w zależności od systemu operacyjnego i konfiguracji. Teraz wystarczy skopiować pliki do tej ścieżki.

Korzystanie -vnie zawsze jest praktyczne.

akostadinov
źródło
3

Właśnie zacząłem używać dokera do kompilacji VLC, oto co możesz zrobić, aby skopiować pliki tam iz powrotem z kontenerów:

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

Wyszukaj znajomy plik w tym txt, a będziesz mieć folder, cd do niego jako root i voila! skopiuj wszystko, co chcesz.

Może być ścieżka z „scalonymi”, myślę, że chcesz tę z „diff”.

Również jeśli wyjdziesz z kontenera i chcesz wrócić tam, gdzie go przerwałeś:

docker ps -a
docker start -i containerid

Wydaje mi się, że jest to przydatne, gdy nic nie nazwałeś poleceniem typu

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

Pewnie metoda hakera, ale co z tego!

Colin Lamarre
źródło
3
docker cp SRC_PATH CONTAINER_ID:DEST_PATH

Na przykład chcę skopiować mój plik xxxx / download / jenkins do tomcat

Zaczynam dostawać identyfikator kontenera 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
źródło
2

Moja ulubiona metoda:

POJEMNIKI:

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

plik.txt

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

lub

mv -f file.txt /var/lib/docker/aufs/mnt/$CONTAINER_ID/rootfs/root/file.txt
użytkownik3159411
źródło
ścieżka devicemapper nie wydaje się działać na fedorze z dokerem 1.6. Postawiłem to jako osobne Q, stackoverflow.com/questions/29939419/… , wszelkie komentarze będą mile widziane.
Yogesh_D
2

Moim zdaniem nie musisz kopiować plików wewnątrz obrazu, ale możesz użyć GIT lub SVN dla swoich plików, a następnie ustawić wolumin zsynchronizowany z folderem lokalnym. Użyj skryptu podczas uruchamiania kontenera, który może sprawdzić, czy dane już istnieją w folderze lokalnym, jeśli nie skopiuj go z repozytorium GIT. Dzięki temu Twój obraz jest bardzo lekki.

h.aittamaa
źródło
To wydaje się być zagrożeniem bezpieczeństwa i koszmarem dostępu, który czeka. Jak zapewniasz dostęp do repozytorium git z poziomu twojego obrazu? Nawet zakładając, że jest to repozytorium publiczne, zakładasz, że host, na którym działa kontener, ma dostęp do tego repozytorium.
tbm
Zgadzam się z tobą, jeśli git jest używany w kontenerze dokera. Ale w naszym przypadku skrypt jest uruchamiany z komputera hosta
h.aittamaa