Копирование файлов с хоста в Docker-контейнер

1582

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

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

Я хочу создать скрипт, который запускается с хост-машины и создает новый контейнер с использованием ubuntu:baseобраза Docker, а затем копирует файлы в этот контейнер.

Как я могу скопировать файлы с хоста в контейнер?

user3001829
источник
12
Если вы не хотите перестраивать, почему бы не « Docker commit »? Это сохраняет ваш образ.
Беренд де Бур
28
Просто замечание к понятию, к которому никто не обращался: в общем, рассматривайте контейнеры как «эфемерные». Существуют сценарии использования для копирования файлов в / из работающего контейнера (тестирование, создание прототипов). Но если вы оказались в положении, когда вы не можете восстановить то, что вам нужно, используя Dockerfiles и / или создавать, тогда вы можете оказаться в плохом месте. Как правило, вы не хотите создавать резервные копии контейнеров, как если бы они были объектами ОС или даже виртуальными машинами. Вообще говоря :-)
Скотт Прайв

Ответы:

2676

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

Справка: докерская документация по CLI дляcp

В версиях Docker до 1.8 было возможно только копировать файлы из контейнера на хост. Не от хоста до контейнера.

0x7d7b
источник
2
Кроме того, обратите внимание , это может быть на хост VM или основной ОС и работает либо хост контейнера или виртуальной машины хоста (или основной ОС)
Adam Tuliper - MSFT
7
В Dockerfile вы можете использовать ключевое слово ADD для добавления файлов во время сборки.
0x7d7b
4
@ h3nrik COPYпредпочтительнее,ADD когда это применимо.
Франклин Ю
10
использовать docker cpдля копирования из контейнера на хост работает хорошо, но когда он используется для копирования файлов с хоста на контейнер, ничего не происходит ... кто-нибудь знает почему? версия докера: версия докера 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
solidleon
источник
13
Для меня путь монтажа хозяина не содержал, aufsно 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>/
версия
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
Питер n
2
Это не работает для меня. Atleast не может запустить контейнер. Может работать только изображение
Шашанк Хегде
1
Я поражен, что docker cpэто односторонняя операция!
ThorSummoner
115

Следующее - довольно уродливый способ сделать это, но это работает.

docker run -i ubuntu /bin/bash -c 'cat > file' < file
Erik
источник
7
Это прекрасно работает! Но не забудьте совершить изменение docker commit `docker ps -l -q` ubuntu-with-file. В противном случае изменения будут потеряны (используйте любое имя, которое хотите вместо ubuntu-with-file)
Michael_Scharf
@Erik: Где находится файл, когда работает контейнер?
коанор
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

Затем мы можем выполнить exec /bin/bashв контейнере и убедиться, что он работает:

$ docker exec -it elated_hodgkin /bin/bash
root@b9b7400ddd8f:/# ls /var/www
file1  file2
adean
источник
Отлично работает на докере 1.16 на Centos 7.4 Отличная инновационная идея.
Dudi Boy
41
  1. Создайте новый файл Docker и используйте существующий образ в качестве своей базы.

    FROM myName/myImage:latest
    
    ADD myFile.py bin/myFile.py
    
  2. Затем создайте контейнер:

    docker build .
    
RustyShackleford
источник
2
Это то, что сработало для меня. Ничего больше. Спасибо!
Оуэн
Это создаст новый образ, а не новый контейнер. Если вы повторно используете это изображение, а myFile.py изменился, он будет использовать более старую версию файла, если вы не перестроите изображение.
Гийом Лебретон
Я считаю, что это самый быстрый способ, только если вы тестируете на удаленном сервере.
Доминик Крулак
В соответствии с этим большинство людей должны использовать COPY, а не ADD. Но для локальных файлов (как в этом примере) они эквивалентны.
hoosierEE
39

Решение приведено ниже,

Из оболочки Docker,

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

От хозяина

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

Файл должен быть непосредственно скопирован в место, где контейнер находится в файловой системе.

проколоть
источник
10
Отличный ответ. В более новых версиях Docker путь был переименован в / var / lib / docker / aufs / mnt /
Алекс Волков
путь к устройству устройства не работает на fedora с докером 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 работает в обе стороны. Не нужно выполнять exec, cat и redirect. 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, благодаря комментарию Мартена .

joemat
источник
Это хорошо, если вам нужно отправить целый каталог. Для одного файла ответ Эрика проще.
Кельвин
1
@Kelvin: Но tar также сохраняет атрибуты и имя файла. Среди прочего это означает, что вы должны ввести имя только один раз (и там вы получаете завершение табуляции из вашей оболочки). Так что я бы сказал, что tar на самом деле проще, если он установлен в контейнере.
Мартен
1
-f -Немного избыточно , хотя, по умолчанию поведения , чтобы писать на стандартный вывод в любом случае.
Мартен
это означает, что существует зависимость хоста от tar
cellige
Вы правы - вам нужно, чтобы tar был установлен на хосте и внутри контейнера. В настоящее время использование docker cp является лучшим решением.
Joemat
24

Чтобы скопировать файл с хоста в работающий контейнер

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

Основано на ответе Эрика и комментариях Микла и Зора.

Andrea
источник
Принятые решения иногда мешают отступу файлов при передаче в работающие контейнеры. Это прекрасно работает для таких случаев
Dreams
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? ,

Hiro.Protagonist
источник
15

Я попробовал большинство решений (с голосованием) здесь, но в докере 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.

Aerin
источник
12

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

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

Например,

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

Чтобы получить идентификатор contianer, введите данную команду:

docker ps

Вышеуказанное содержание взято с docker.com .

prayagupd
источник
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 ...

Примечание. Проблемы с разрешениями могут возникнуть, поскольку пользователи контейнера не совпадают с пользователями хоста.

johndodo
источник
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 ...). Я буду благодарен за вашу помощь
Микл
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/
Maninder
источник
7

В среде докера все контейнеры находятся в каталоге:

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

Чтобы скопировать исходный каталог / файл в любую часть контейнера, введите следующую команду:

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

0x3bfc
источник
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каталога в /контейнер с идентификатором «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

ishandutta2007
источник
1
Вы можете перечислить идентификаторы вышедших контейнеров с помощью docker ps -aили docker container ls -a.
0x7d7b
4

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

В этом случае вы можете использовать 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

Это onliner для копирования одного файла при запуске контейнера Tomcat.

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

Это скопирует файл war в каталог webapps и быстро запустит ваше приложение.

karthik101
источник
1
-v будет монтировать (т.е. создавать ссылку), а не копировать
Виталий Улантиков
разница в том, что монтирование скрывает предыдущее содержимое контейнера, например, если вы смонтируете папку хоста в папке контейнера, вы больше не сможете видеть содержимое предыдущей папки контейнера
mrq
4

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

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

В файле Docker

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не всегда практично.

akostadinov
источник
3

Я только начал использовать docker для компиляции VLC, вот что вы можете сделать, чтобы копировать файлы туда и обратно из контейнеров:

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

Ищите знакомый файл в этом тексте, и у вас будет папка, перейдите к нему как root и вуаля! Скопируйте все, что вы хотите.

Там может быть путь с "слитым" в нем, я думаю, вы хотите тот, в котором есть "diff".

Также, если вы выходите из контейнера и хотите вернуться туда, где остановились:

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
user3159411
источник
путь к устройству устройства не работает на fedora с докером 1.6. Поместите это как отдельный Q, stackoverflow.com/questions/29939419/… , любые комментарии будут оценены.
Yogesh_D
2

По моему мнению, вам не нужно копировать файлы внутри изображения, но вы можете использовать GIT или SVN для ваших файлов, а затем установить том, синхронизированный с локальной папкой. Используйте сценарий при запуске контейнера, который может проверить, существуют ли данные в локальной папке, если не скопировать их из репозитория GIT. Это делает ваш образ очень легким.

h.aittamaa
источник
Это похоже на угрозу безопасности и кошмар, ожидающий доступа. Как вы предоставляете доступ к хранилищу git из своего изображения? Даже предполагая, что это публичный репозиторий, вы предполагаете, что хост, на котором работает ваш контейнер, имеет доступ к этому репо.
TBM
Я согласен с вами, если Git используется внутри Docker-контейнера. Но в нашем случае скрипт запускается с хост-машины
h.aittamaa