Копіювання файлів з хоста в контейнер Docker


1575

Я намагаюся створити рішення для резервного копіювання та відновлення контейнерів Docker, з якими ми працюємо.

У мене є базове зображення Докера, яке я створив, ubuntu:baseі не хочу кожного разу його відновлювати за допомогою файла Docker, щоб до нього додавати файли.

Я хочу створити сценарій, який працює від хост-машини і створює новий контейнер за допомогою ubuntu:baseзображення Docker, а потім копіює файли в цей контейнер.

Як можна скопіювати файли з хоста в контейнер?


11
Якщо ви не хочете перебудовувати, чому б не " докер здійснити "? Це зберігає ваш образ.
Беренд де Бур,

26
Лише зауваження до поняття, до якого ніхто не звертався: загалом, трактуйте контейнери як "ефемерні". Там використовуються випадки для копіювання файлів у / із запущеного контейнера (тестування, прототипізація). Але якщо ви опинитеся в положенні, коли ви не зможете відновити те, що вам потрібно, використовуючи Dockerfiles та / або створити композицію, то ви можете опинитися в поганому місці. Як правило, ви не хочете створювати резервну копію контейнерів, як якщо б вони були ОС або навіть об'єктами VM. Взагалі кажучи :-)
Скотт Прів

Відповіді:


2671

cpКоманда може бути використана для копіювання файлів.

Один конкретний файл можна скопіювати в контейнер, наприклад:

docker cp foo.txt mycontainer:/foo.txt

З контейнера можна скопіювати один конкретний файл, наприклад:

docker cp mycontainer:/foo.txt foo.txt

Для акценту, mycontainerє контейнер ID, НЕ зображення ID.

Кілька файлів, що містяться в папці, srcможна скопіювати в targetпапку за допомогою:

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

Довідка: документи Docker CLI дляcp

У версіях Docker до версії 1.8 можна було лише копіювати файли з контейнера на хост. Не від хоста до контейнера.


2
також зауважте, що це може бути на хості vm або основній ОС і працює або хостом до контейнера, або vm для хосту (або головного ОС)
Адам Туліпер - MSFT

7
У Dockerfile ви можете використовувати ключове слово ADD для додавання файлів під час збирання.
0x7d7b

4
@ h3nrik надає COPYперевагу, ніжADD застосовано.
Франклін Ю

10
використання docker cpдля копіювання з контейнера на хост працює добре, але коли використовувати його для копіювання файлів з хоста в контейнер, ефекту немає ... хтось знає чому? версія докера: версія Docker 1.10.3, збірка cb079f6-не підтримується
Ace.Yin

2
Чи можу я скопіювати кілька файлів за допомогою docker cp з хоста в контейнер?
Йогеш

182
  1. Отримати ім’я контейнера або короткий ідентифікатор контейнера:

    $ docker ps
    
  2. Отримайте повний ідентифікатор контейнера:

    $ docker inspect -f   '{{.Id}}'  SHORT_CONTAINER_ID-or-CONTAINER_NAME
    
  3. Скопіювати файл:

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

ПРИКЛАД:

$ 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

або

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

d8e703d7e3039a6df6d01bd7fb58d1882e592a85059eb16c4b83cf91847f88e5

$ sudo cp file.txt /var/lib/docker/aufs/mnt/**d8e703d7e3039a6df6d01bd7fb58d1882e592a85059eb16c4b83cf91847f88e5**/root/file.txt

13
Для мене шлях монтажу хоста містив не aufsлише a devicemapper. Найпростіший спосіб перевірити шлях монтажу контейнерів (поки він працює) - це запустити команду mount.
derenio

3
Я спробував вищевказане рішення. Він скопіював файли в специфічний докер-каталог. Однак, коли я використовую bash для контейнера docker, файли не відображаються там. Щось мені не вистачає?
AppleBud

2
Новий шлях - / var / lib / docker / devicemapper / mnt / <<id>> / rootfs /
mcuadros

4
Для мене на Docker 1.4.1 (поточний останній), це/var/lib/docker/aufs/diff/<id>/
user193130

3
як щодо бідних користувачів MacOS? Для /var/libмене є каталог монтажу . find / -name dockerтеж не було корисно.
prayagupd

141

Найчистішим способом є встановлення каталогу хостів на контейнері під час запуску контейнера:

{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

3
як можна запускати контейнер? я думав, що ти можеш це зробити лише із зображенням.
Павло Зайцев

Я не можу змусити його працювати, коли контейнер вже існує. Дьоготь внизу працює добре.
Ейно Макітало

1
Єдиний спосіб, який це працював для мене, - додавання гучності разом із запуском зображення (інстанціювання контейнера). Закінчено:docker run -d -p -v /host/path:/mnt --name container_name image_name
peter n

2
Це не працює для мене. Atleast не може запустити контейнер. Може запускати лише зображення
Шашанк Хегде

1
Я вражений, що docker cpце одностороння операція!
ThorSummoner

115

Далі йде досить потворний спосіб зробити це, але це працює.

docker run -i ubuntu /bin/bash -c 'cat > file' < file

7
Це чудово працює! Але не забудьте зафіксувати зміни: docker commit `docker ps -l -q` ubuntu-with-file. В іншому випадку зміни будуть втрачені (використовуйте будь-яке ім'я замість ubuntu-with-file)
Michael_Scharf

@Erik: Де знаходиться файл, коли контейнер працює?
coanor

49
На додаток ми можемо використовувати нову docker execфункцію для роботи з запущеним контейнером:docker exec -it <container_id> bash -c 'cat > /path/to/container/file' < /path/to/host/file/
Mikl

17
@Mikl Я думаю, що це повинно бути docker exec -i ...замість цього -it, оскільки немає TTY при підключенні до файлу.
z0r

4
Якщо ви все ще затрималися на старій версії Docker (як і я) і хочете скопіювати цілий каталог, ви можете зробити це: 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

Якщо вам потрібно зробити це на запущеному контейнері, ви можете використовувати docker exec (додано в 1.3).

Спочатку знайдіть ім’я або ідентифікатор контейнера:

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

У наведеному вище прикладі ми можемо використовувати b9b7400ddd8fабо elated_hodgkin.

Якщо ви хочете скопіювати все /tmp/somefilesна хост /var/wwwу контейнер:

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

Потім ми можемо виконати /bin/bashв контейнері і переконатися, що він працював:

$ docker exec -it elated_hodgkin /bin/bash
root@b9b7400ddd8f:/# ls /var/www
file1  file2

Відмінно працює на докер 1.16 на Centos 7.4 Чудова інноваційна ідея.
Дуді хлопчик

41
  1. Створіть новий докер-файл і використовуйте наявне зображення як базу.

    FROM myName/myImage:latest
    
    ADD myFile.py bin/myFile.py
    
  2. Потім складіть контейнер:

    docker build .
    

2
Це те, що працювало для мене. Більш нічого. Дякую!
Оуен

Це створить нове зображення, а не безпосередньо новий контейнер. Якщо ви повторно використовуєте це зображення під час зміни myFile.py, воно використовуватиме старішу версію файлу, якщо ви не відновите зображення.
Гійом Лебретон

Я вважаю це найшвидшим способом, лише якщо ви тестуєте на віддаленому сервері.
Домінік Крулак

Відповідно до цього більшість людей повинні використовувати КОПІЮВАННЯ, а не ДОДАТИ. Але для локальних файлів (як у цьому прикладі) вони еквівалентні.
hoosierEE

39

Рішення наведено нижче,

З оболонки Докера,

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

Від господаря

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

Файл безпосередньо копіюється в місце, де контейнер сидить у файловій системі.


10
Чудова відповідь. У новіших докерних випусках шлях було перейменовано на / var / lib / docker / aufs / mnt /
Алекс Волков

Шлях devicemapper, здається, не працює на Fedora з docker 1.6. Поставивши це як окремий Q, stackoverflow.com/questions/29939419/… , будь-які коментарі будуть вдячні.
Yogesh_D

33

Зазвичай існує три типи:

  1. Від контейнера до хазяїна

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

dev1

  1. Від хоста до контейнера

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

dev2

  1. З контейнера в контейнер змішується 1 і 2

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

dev3


6
docker cp працює обома способами. Не потрібно виконувати, котувати та перенаправляти. Докер ср host_file.txt контейнер: / шлях /
TBM

32

Іншим рішенням для копіювання файлів у запущений контейнер є використання tar:

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

Копіює файл foo.shу /tmpконтейнер.

Редагувати: Видаліть надлишки -f, завдяки коментарю Maarten


Це добре, якщо вам потрібно надіслати цілий каталог. Для одного файлу відповідь Еріка простіша.
Келвін

1
@Kelvin: Але tar також зберігає атрибути файлу та ім'я. Крім іншого, це означає, що вам потрібно ввести ім'я лише один раз (і там ви отримаєте заповнення вкладки зі своєї оболонки). Тому я б сказав, що дьоготь насправді простіший, якщо він встановлений у контейнері.
Маартен

1
Хоча -f -це трохи зайве, поведінка за замовчуванням - це все-таки написати в stdout.
Маартен

це означає, що залежність господаря від дьогтю
166

Ви маєте рацію - вам потрібно встановити дьоготь на хості та всередині контейнера. Сьогодні використання docker cp - краще рішення.
joemat

24

Щоб скопіювати файл з хоста в запущений контейнер

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

На основі відповіді Еріка та коментарів Мікла та z0r.


Прийняті рішення іноді порушують відступ файлів при перенесенні в запущені контейнери. Це ідеально підходить для таких випадків
Сновидіння


15

Це пряма відповідь на питання "Копіювання файлів з хоста в контейнер Docker", порушеного в цьому запитанні в заголовку.

Спробуйте docker cp. Це найпростіший спосіб зробити це і працює навіть на моєму Mac. Використання:

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

Це скопіює файл some-file.txtу каталозі /rootвашого хост-машини в контейнер Docker, названий some-docker-containerу каталог /root. Він дуже близький до синтаксису захищеної копії. І як показано в попередньому дописі, ви можете використовувати його навпаки. Тобто ви також копіюєте файли з контейнера на хост.

І перш ніж ви перейдете за цим посиланням, будь ласка, введіть docker cp --help. Читання документації може бути дуже корисним, іноді ...

Якщо вам це не подобається, і ви хочете обсяги даних у вже створеному та запущеному контейнері, то відпочинок - це ваш єдиний варіант сьогодні. Див. Також Як я можу додати об'єм до існуючого контейнера Docker? .


15

Я спробував більшість (схвалених) рішень тут, але в docker 17.09 (у 2018 році) більше немає папки / var / lib / docker / aufs.

Цей простий docker cpвирішив цю задачу.

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

Як отримати ім’я_контажу?

 docker ps 

Є NAMESрозділ. Не використовуйте IMAGE.


12

Щоб скопіювати файли / папки між контейнером та локальною файловою системою, введіть команду:

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

Наприклад,

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

Щоб отримати ідентифікатор contianer, введіть задану команду:

docker ps

Наведений вище вміст взято з docker.com .


8

Припускаючи, що контейнер вже працює, введіть задану команду:

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

Щоб ділитися файлами за допомогою спільного каталогу, запустіть контейнер, ввівши дану команду:

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

Примітка. Проблеми з дозволами можуть виникнути, оскільки користувачі контейнера не такі, як користувачі хосту.


1
Крім того:docker exec -it <container_id> bash -c 'cat > /path/to/container/file' < /path/to/host/file/
Мікл

2
Зауважте, що catне буде припинено, коли воно закінчиться. Якщо для вас це важливо (якщо ви копіюєте bash-скрипти, bash відмовиться запускати їх), вам слід запустити lsof | grep yourfilenameі вбити catпроцес, який містить цей файл.
johndodo

Дякую! Чудова порада. Чи можете ви сказати мені, як вбити цей процес однією командою? Щось подібне kill $(lsof | grep /path/to/file | sed ...). Я буду вдячний за вашу допомогу
Mikl

kill $(docker top CONTAINERNAME | sed -n '/cat$/p' | sed 's/^root[^0-9]\+\([0-9]\+\).*$/\1/')
Мікль

8

Це команда скопіювати дані з Docker у Host:

docker cp container_id:file path/filename /hostpath

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

Нижче наведена команда копіювання даних з хоста в докер:

docker cp a.txt ccfbeb35116b:/home/

7

У докерному середовищі всі контейнери знаходяться в каталозі:

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

Щоб скопіювати вихідний каталог / файл у будь-яку частину контейнера, введіть задану команду:

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


5

tarі docker cpє хорошим комбо для копіювання всього в каталог.

Створіть контейнер обсягу даних

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

Для збереження ієрархії каталогів

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

Перевірте свою роботу

docker run --rm --volumes-from dvc cirros ls -al /path/on/container

5

Якщо хостом є CentOS або Fedora, проксі НЕ є /var/lib/docker/aufs, але він знаходиться під /proc:

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

Цей cmd скопіює весь вміст dataкаталогу до /контейнера з id "containerid".


Це не властиво Redhat: він також працює на Debian. (можливо, всі Gnu / Linux з /proc). Також розгорніть шлях, щоб розмістити файл де-небудь ще, а не тільки root.
ctrl-alt-delor

5

Якщо комусь, як я, не зрозуміло, що mycontainerозначає відповідь @ h3nrik, це ідентифікатор контейнера. Щоб скопіювати файл WarpSquare.mp4в /app/example_scenes/1440p60з порушеної Docker контейнера в поточну папку , я використовував це.

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

де docker ps -q -lвитягує ідентифікатор контейнера останнього вийшов екземпляра. Якщо це не контейнер, що вийшов, ви можете отримати його docker container lsабоdocker ps


1
Ви можете перелічити ідентифікатори вихідних контейнерів за допомогою docker ps -aабо docker container ls -a.
0x7d7b

4

У багатьох, хто знайде це питання, може бути проблема копіювання файлів у зображення Докера під час його створення (я це робив).

У цьому випадку ви можете використовувати COPYкоманду в тій, Dockerfileяку ви використовуєте для створення зображення.

Дивіться документацію .


4

Ви можете просто простежити IP-адресу локальної машини за допомогою

ifconfig

Потім просто введіть у свій контейнер Docker і введіть

scp user_name@ip_address:/path_to_the_file destination

У будь-якому випадку, якщо у вас немає встановленого клієнта та сервера SSH, просто встановіть його за допомогою:

sudo apt-get install openssh-server

Дякую багато, це спрацювало добре для мене. Плюс, я вважаю це більш ефективним, ніж інші способи
user1314742

Це жахливе рішення з точки зору безпеки.

4

Це он-лайн для копіювання одного файлу під час запуску контейнера tomcat.

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

Це скопіює файл війни у ​​каталог webapps і запустить ваш додаток у найкоротші терміни.


1
-v буде монтувати (тобто створити посилання), а не копіювати
Віталій Улантіков

відмінність результату полягає в тому, що монтування приховує попередній вміст контейнера, наприклад, якщо ви встановите папку хоста на папку контейнера, ви більше не можете бачити вміст попередньої папки контейнера
mrq

4

Синтаксис контейнерів:

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

У докер Файл

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

3

Найкращий спосіб копіювання файлів до знайденого нами контейнера - це встановлення каталогу на хості, використовуючи -vопцію команди docker run.


3

Є відповіді хороші, але занадто конкретні. Я дізнаюся, що docker psце хороший спосіб отримати ідентифікатор контейнера, який вас цікавить. Тоді зробіть

mount | grep <id>

щоб побачити, де встановлено гучність. Ось так

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

для мене, але це може бути інший шлях залежно від ОС та конфігурації. Тепер просто скопіюйте файли на цей шлях.

Використовувати -vне завжди практично.


3

Щойно я почав використовувати докер для компіляції VLC, ось що можна зробити, щоб скопіювати файли назад і назад з контейнерів:

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

Шукайте знайдений файл у цьому тексті, і ви матимете папку, компакт-диск до нього як root та voila! скопіюйте все, що вам потрібно.

Можливо, є шлях із "злитим" у ньому, я думаю, ви хочете, щоб той, у якому є "розріз".

Також якщо ви виходите з контейнера і хочете бути там, де ви зупинилися:

docker ps -a
docker start -i containerid

Я думаю, це корисно, коли ти нічого не назвав такою командою

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

Звичайно, хакерський метод, але так що!


3
docker cp SRC_PATH CONTAINER_ID:DEST_PATH

Наприклад, я хочу скопіювати свій файл xxxx / download / jenkins в tomcat

Я починаю отримувати ідентифікатор контейнера 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/

2

Мій улюблений метод:

КОНТЕЙНЕРИ:

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

або

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

Шлях devicemapper, здається, не працює на Fedora з docker 1.6. Поставивши це як окремий Q, stackoverflow.com/questions/29939419/… , будь-які коментарі будуть вдячні.
Yogesh_D

2

На мою думку, ви не повинні копіювати файли всередині зображення, але ви можете використовувати GIT або SVN для своїх файлів, а потім встановити гучність, синхронізовану з локальною папкою. Використовуйте скрипт під час керування контейнером, який може перевірити, чи існують дані у локальній папці, якщо не скопіювати їх із сховища GIT. Це робить ваш образ дуже легким.


Це здається ризиком для безпеки та доступу до кошмару, які чекають цього. Як ви надаєте доступ до сховища git із свого зображення? Навіть якщо припустити, що це загальнодоступне сховище, ви збираєтесь вважати, що хост, на якому працює ваш контейнер, має доступ до цього репо.
TBM

Я згоден з вами, якщо git використовується у контейнері docker. Але в нашому випадку сценарій працює від хост-машини
h.aittamaa
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.