Докер - як я можу скопіювати файл із зображення на хост?


117

Моє запитання пов'язане з цим питанням щодо копіювання файлів з контейнерів у хости; У мене є Dockerfile, який отримує залежності, збирає артефакт збірки з джерела та запускає виконуваний файл. Я також хочу скопіювати артефакт збірки (у моєму випадку це .zipстворено sbt distв '../ target / `, але я думаю, що це питання стосується також банок, бінарних файлів тощо.

docker cpпрацює над контейнерами, а не зображеннями; чи потрібно запускати контейнер просто для того, щоб отримати файл з нього? У сценарії я спробував працювати /bin/bashв інтерактивному режимі на задньому плані, скопіювавши файл, а потім убивши контейнер, але це здається дивним. Чи є кращий спосіб?

З іншого боку, я хотів би уникнути розпакування .tarфайлу після запуску docker save $IMAGENAMEпросто для виходу одного файлу (але це здається найпростішим, якщо найповільнішим, варіантом зараз).

Я використовував би токи докера, наприклад:

docker run -v hostdir:out $IMAGENAME /bin/cp/../blah.zip /out

але я працюю boot2dockerв OSX, і я не знаю, як безпосередньо записати в мою файлову систему mac host (томи читання-запису монтуються всередині моєї VM boot2docker, а це означає, що я не можу легко поділитися сценарієм для отримання blah.zipз зображення ін. Думки?

Відповіді:


172

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

id=$(docker create image-name)
docker cp $id:path - > local-tar-file
docker rm -v $id

Яку версію докера createдодала / видалила команда (її немає в 1.01)
ThorSummoner

2
@ThorSummoner docker createбув представлений в docker
Ігор Буканов

1
Я не знаю, чому це не обрано як правильну відповідь.
CentAu

1
Однозначно правильна відповідь !!! Не покладається ні на що всередині контейнера ... Для зображень з подряпинами Golang - це єдиний можливий спосіб!
Marcello de Sales

2
якась причина скопіювати в stdout, а потім направити його у локальний файл? коли я це зробив, він скидав купу контрольних символів до та після вмісту файлу. запускаючи його безпосередньо так, як docker cp $id:path > local-tar-fileпрацював бездоганно.
Йонатан

62

На жаль, здається, не існує способу копіювання файлів безпосередньо з зображень Docker. Спочатку потрібно створити контейнер, а потім скопіювати файл із контейнера.

Однак якщо ваше зображення містить catкоманду (і це буде робити у багатьох випадках), ви можете зробити це за допомогою однієї команди:

docker run --rm --entrypoint cat yourimage  /path/to/file > path/to/destination

Якщо ваше зображення не містить cat, просто створіть контейнер і скористайтеся docker cpкомандою, запропонованою у відповіді Ігоря.


1
Фантастичне рішення. Не вдалося отримати доступ до мого контейнера, оскільки він забився секунди після запуску, але потрібно було схопити файл всередині нього. Це спрацювало чудово.
Миродіньо

23

Набагато швидший варіант - скопіювати файл із запущеного контейнера в змонтований том:

docker run -v $PWD:/opt/mount --rm --entrypoint cp image:version /data/libraries.tgz /opt/mount/libraries.tgz

реальні 0м0.446с

** VS **

docker run --rm --entrypoint cat image:version /data/libraries.tgz > libraries.tgz

реальні 0м9.014с


Це, мабуть, має більше спільного з базовою файловою системою, яка виконує ледачу / неглибоку копію файлу (думаю, що копіюється при записі) у першому прикладі, а фактично копіює байти файлу у другому прикладі. Корисним тестом було б перевірити, чи мають у cat a >bпорівнянні cp a bсхожі терміни, як показано тут. Крім того, якщо шлях джерела і шлях призначення знаходяться в різних файлових системах, то обидва приклади призведуть до повноцінної копії байта для байта.
KevinOrr

14

Коментар батьків уже показав, як користуватися котом . Ви також можете використовувати дьоготь подібним чином:

docker run yourimage tar -c -C /my/directory subfolder | tar x

1
Ця відповідь полягає в тому, щоб скопіювати каталоги, а не файли, як задається оригінальне запитання. Однак +1, оскільки він також працює з файлами та має додаткову функцію: дозвіл та збереження власника. Чудово!
caligari

5
Власне, я використовуюdocker run --rm --entrypoint tar _image_ cC _img_directory_ . | tar xvC _host_directory_
caligari

6
docker cp $(docker create registry.example.com/ansible-base:latest):/home/ansible/.ssh/id_rsa ./hacked_ssh_key

хотів поставити однолінійне рішення

редагувати: контейнер навіть не потрібно запускати в цьому рішенні


1

Ще одна (коротка) відповідь на цю проблему:

docker run -v $PWD:/opt/mount --rm -ti image:version bash -c "cp /source/file /opt/mount/"

0

Я використовую boot2docker на MacOS. Можу запевнити, що сценарії на основі "docker cp" є портативними. Оскільки будь-яка команда передається всередині boot2docker, але потім бінарний потік передається назад до клієнта командного рядка docker, що працює на вашому mac. Отож операції запису від клієнта docker виконуються всередині сервера та записуються назад до виконавчого екземпляра клієнта!

Я ділюсь сценарієм резервного копіювання томів docker з будь-яким наданим контейнером докера, і мої сценарії резервного копіювання тестуються як на Linux, так і на MacOS з boot2docker. Резервні копії легко обмінюватися між платформами. В основному я виконую наступну команду всередині мого сценарію:

docker run --name=bckp_for_volume --rm --volumes-from jenkins_jenkins_1 -v /Users/github/jenkins/backups:/backup busybox tar cf /backup/JenkinsBackup-2015-07-09-14-26-15.tar /jenkins

Запускає новий контейнер зайнятий і монтує об'єм мого контейнера jenkins з назвою jenkins_jenkins_1. Весь том записаний у резервні копії файлів / JenkinsBackup-2015-07-09-14-26-15.tar

Я вже перемістив архіви між контейнером linux та моїм mac-контейнером без будь-яких коригувань сценарію резервного копіювання чи відновлення. Якщо це те, що ви хочете, ви знайдете тут весь підручник: blacklabelops / jenkins


0

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

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest

Потім копіювати не потрібно.

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