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


1707

Я думаю використовувати Docker для побудови моїх залежностей на сервері безперервної інтеграції (CI), щоб мені не довелося встановлювати всі режими виконання та бібліотеки на самі агенти.

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


ви , хлопці могли б мій метод хакера тут: stackoverflow.com/a/55876794/990618
Colin Ламарр

1
Правильна та фактична відповідь капітана докера внизу відповідей.
burtsevyg

Відповіді:


2942

Для того, щоб скопіювати файл з контейнера на хост, ви можете скористатися командою

docker cp <containerId>:/file/path/within/container /host/path/target

Ось приклад:

$ sudo docker cp goofy_roentgen:/out_read.jpg .

Тут goofy_roentgen - ім'я контейнера, яке я отримав із наступної команди:

$ sudo docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                            NAMES
1b4ad9311e93        bamos/openface      "/bin/bash"         33 minutes ago      Up 33 minutes       0.0.0.0:8000->8000/tcp, 0.0.0.0:9000->9000/tcp   goofy_roentgen

Ви також можете використовувати (частина) ідентифікатор контейнера . Наступна команда еквівалентна першій

$ sudo docker cp 1b4a:/out_read.jpg .

42
Ось зручний спосіб отримати в вашому останній контейнер , якщо ви просто використовуєте докер для середовища Linux темпу: docker ps -alq.
Джош Хабдас

37
ця команда cp працює так само, як і для копіювання дерев каталогів (не лише одного файлу).
еко

88
У новіших версіях докера ви можете скопіювати двостороння (хост в контейнер або контейнер для розміщення) за допомогоюdocker cp ...
Freedom_Ben

9
Мені потрібно docker cp -Lбуло скопіювати посилання
Harrison Powers

24
ПРИМІТКА: контейнер не повинен працювати, щоб використовувати команду cp. Зручно, якщо ваш контейнер постійно виходить з ладу.
Martlark

219

Вам не потрібно користуватися docker run.

Ви можете це зробити за допомогою docker create.

З документів :

docker createКоманда створює записується шар поверх контейнер зазначеного зображення і готує його для виконання зазначеної команди. Потім ідентифікатор контейнера друкується в STDOUT. Це аналогічно docker run -dтому, що контейнер ніколи не запускається.

Отже, ви можете:

docker create -ti --name dummy IMAGE_NAME bash
docker cp dummy:/path/to/file /dest/to/file
docker rm -f dummy

Тут ви ніколи не запускаєте контейнер. Це виглядало для мене вигідно.


19
Для цього потрібно більше коштів. Відмінно підходить, коли вам потрібно просто щось скласти в контейнер і потім скопіювати результати.
Хонза Кальфус

4
@HonzaKalfus Я згоден, що це повинно бути вищим. Це саме те, що я був після. Я використовував це, щоб я міг створити деякі бінарні файли, використовуючи відоме середовище (Amazon linux у певній версії). вдалося скласти скрипт оболонки, який повністю побудував докер і витяг з нього отриманий бінар! Ідеально.
Марк

1
Це -tiпотрібно і bashпотрібно?
jII

@jII, я це зробив, тому що пізніше я докер запускаю його. У простих випадках вона не потрібна, але і тут не шкодить.
Ішан Бхатт

Чи можна якось використати маклери? Я маю на увазі ... Я не знаю точного імені файлу, який мені потрібно скопіювати, оскільки на ньому є номер версії.
джузлін

87

Змонтуйте "том" і скопіюйте туди артефакти:

mkdir artifacts
docker run -i -v ${PWD}/artifacts:/artifacts ubuntu:14.04 sh << COMMANDS
# ... build software here ...
cp <artifact> /artifacts
# ... copy more artifacts into `/artifacts` ...
COMMANDS

Потім, коли збірка закінчується і контейнер більше не працює, він вже скопіював артефакти з збірки в artifactsкаталог на хості.

Редагувати

Caveat: Коли ви це зробите, у вас можуть виникнути проблеми з ідентифікатором користувача докер-користувача, який відповідає ідентифікатору поточного працюючого користувача. Тобто, файли в /artifactsбуде показано як належне користувачеві з UID користувача, який використовується всередині контейнера докера. Шляхом цього може бути використання UID користувача виклику:

docker run -i -v ${PWD}:/working_dir -w /working_dir -u $(id -u) \
    ubuntu:14.04 sh << COMMANDS
# Since $(id -u) owns /working_dir, you should be okay running commands here
# and having them work. Then copy stuff into /working_dir/artifacts .
COMMANDS

7
Насправді ви можете використовувати chownкоманду для відповідності ідентифікатора користувача та ідентифікатора групи на хост-машині.
Димчанський

@Frondor Див. Посилання на конфігурацію тома config docs.docker.com/compose/compose-file/…
djhaskin987

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

звучить як щось, що може бути власним питанням SO @Frondor
djhaskin987

1
Я купую тобі товариша по пиву! Дякую!
Димитар Вукман

27

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

mkdir artifacts
docker run -i --rm -v ${PWD}/artifacts:/mnt/artifacts centos:6 /bin/bash << COMMANDS
ls -la > /mnt/artifacts/ls.txt
echo Changing owner from \$(id -u):\$(id -g) to $(id -u):$(id -u)
chown -R $(id -u):$(id -u) /mnt/artifacts
COMMANDS

24

TLDR;

$ docker run --rm -iv${PWD}:/host-volume my-image sh -s <<EOF
chown $(id -u):$(id -g) my-artifact.tar.xz
cp -a my-artifact.tar.xz /host-volume
EOF

Опис

docker runз об'ємом господаря, chownартефактом, cpартефактом до об'єму хоста:

$ docker build -t my-image - <<EOF
> FROM busybox
> WORKDIR /workdir
> RUN touch foo.txt bar.txt qux.txt
> EOF
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM busybox
 ---> 00f017a8c2a6
Step 2/3 : WORKDIR /workdir
 ---> Using cache
 ---> 36151d97f2c9
Step 3/3 : RUN touch foo.txt bar.txt qux.txt
 ---> Running in a657ed4f5cab
 ---> 4dd197569e44
Removing intermediate container a657ed4f5cab
Successfully built 4dd197569e44

$ docker run --rm -iv${PWD}:/host-volume my-image sh -s <<EOF
chown -v $(id -u):$(id -g) *.txt
cp -va *.txt /host-volume
EOF
changed ownership of '/host-volume/bar.txt' to 10335:11111
changed ownership of '/host-volume/qux.txt' to 10335:11111
changed ownership of '/host-volume/foo.txt' to 10335:11111
'bar.txt' -> '/host-volume/bar.txt'
'foo.txt' -> '/host-volume/foo.txt'
'qux.txt' -> '/host-volume/qux.txt'

$ ls -n
total 0
-rw-r--r-- 1 10335 11111 0 May  7 18:22 bar.txt
-rw-r--r-- 1 10335 11111 0 May  7 18:22 foo.txt
-rw-r--r-- 1 10335 11111 0 May  7 18:22 qux.txt

Цей трюк працює, тому що chownвиклик усередині heredoc приймає $(id -u):$(id -g)значення поза бігового контейнера; тобто хост докера.

Переваги:

  • вам не потрібно docker container run --nameчи docker container create --nameраніше
  • вам не доведеться docker container rmпісля

2
Запропоновано для порівняння відповідей cpта томів. Крім того, для idхитрості щодо власності, це часом справжній головний біль
Марк Гораєб

18

Більшість відповідей не вказує на те, що контейнер повинен працювати раніше docker cp:

docker build -t IMAGE_TAG .
docker run -d IMAGE_TAG
CONTAINER_ID=$(docker ps -alq)
# If you do not know the exact file name, you'll need to run "ls"
# FILE=$(docker exec CONTAINER_ID sh -c "ls /path/*.zip")
docker cp $CONTAINER_ID:/path/to/file .
docker stop $CONTAINER_ID

3
BTW, чи контейнер повинен / може бути запущений / зупинений / або, схоже, залежить від типу хоста / віртуалізації . Поточний docker doc каже: "Контейнер може бути запущеним або зупиненим контейнером". Кілька місць на SO, включаючи коментар до прийнятої відповіді, кажуть, "це також працює на зупиненому контейнері". Під Windows Hyper-Vце, по- видимому необхідно , щоб зупинити контейнер перед копіюванням файлу .
ToolmakerSteve

Копіювання також працює при зупинці контейнера.
Лука Ш

17

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

docker run the-image cat path/to/container/file.txt > path/to/host/file.txt

7

Я публікую це для всіх, хто використовує Docker для Mac. Це для мене працювало:

 $ mkdir mybackup # local directory on Mac

 $ docker run --rm --volumes-from <containerid> \
    -v `pwd`/mybackup:/backup \  
    busybox \                   
    cp /data/mydata.txt /backup 

Зауважте, що при монтажі за допомогою -vцього backupкаталогу автоматично створюється.

Я сподіваюся, що комусь це стане в нагоді. :)


Якщо ви використовуєте docker-compose, томи-from застаріли у версії 3 та після.
mulg0r

Щоб додати коментар mulg0r, див. Stackoverflow.com/a/45495380/199364 - у версії 3, ви розміщуєте volumesкоманду в корені config.yml, щоб томи були доступні у кількох контейнерах.
ToolmakerSteve

5

Якщо ви просто хочете витягнути файл із зображення (замість запущеного контейнера), ви можете зробити це:

docker run --rm <image> cat <source> > <local_dest>

Це підніме контейнер, напише новий файл, а потім видаліть контейнер. Однак, недоліком є ​​те, що дозволи файлів та змінена дата не зберігаються.



5

З випуском Docker 19.03 ви можете пропустити створення контейнера і навіть побудувати зображення. Існує опція з побудовами на основі BuildKit змінити вихідне призначення. Ви можете використовувати це для запису результатів збірки у свій локальний каталог, а не у зображення. Наприклад, ось побудова бінарного файлу:

$ ls
Dockerfile  go.mod  main.go

$ cat Dockerfile
FROM golang:1.12-alpine as dev
RUN apk add --no-cache git ca-certificates
RUN adduser -D appuser
WORKDIR /src
COPY . /src/
CMD CGO_ENABLED=0 go build -o app . && ./app

FROM dev as build
RUN CGO_ENABLED=0 go build -o app .
USER appuser
CMD [ "./app" ]

FROM scratch as release
COPY --from=build /etc/passwd /etc/group /etc/
COPY --from=build /src/app /app
USER appuser
CMD [ "/app" ]

FROM scratch as artifact
COPY --from=build /src/app /app

FROM release

З наведеного вище Dockerfile я будую artifactетап, який включає лише ті файли, які я хочу експортувати. І нещодавно представлений --outputпрапор дозволяє мені записати їх у локальний каталог замість зображення. Це потрібно зробити за допомогою двигуна BuildKit, який постачається з 19.03:

$ DOCKER_BUILDKIT=1 docker build --target artifact --output type=local,dest=. .
[+] Building 43.5s (12/12) FINISHED
 => [internal] load build definition from Dockerfile                                                                              0.7s
 => => transferring dockerfile: 572B                                                                                              0.0s
 => [internal] load .dockerignore                                                                                                 0.5s
 => => transferring context: 2B                                                                                                   0.0s
 => [internal] load metadata for docker.io/library/golang:1.12-alpine                                                             0.9s
 => [dev 1/5] FROM docker.io/library/golang:1.12-alpine@sha256:50deab916cce57a792cd88af3479d127a9ec571692a1a9c22109532c0d0499a0  22.5s
 => => resolve docker.io/library/golang:1.12-alpine@sha256:50deab916cce57a792cd88af3479d127a9ec571692a1a9c22109532c0d0499a0       0.0s
 => => sha256:1ec62c064901392a6722bb47a377c01a381f4482b1ce094b6d28682b6b6279fd 155B / 155B                                        0.3s
 => => sha256:50deab916cce57a792cd88af3479d127a9ec571692a1a9c22109532c0d0499a0 1.65kB / 1.65kB                                    0.0s
 => => sha256:2ecd820bec717ec5a8cdc2a1ae04887ed9b46c996f515abc481cac43a12628da 1.36kB / 1.36kB                                    0.0s
 => => sha256:6a17089e5a3afc489e5b6c118cd46eda66b2d5361f309d8d4b0dcac268a47b13 3.81kB / 3.81kB                                    0.0s
 => => sha256:89d9c30c1d48bac627e5c6cb0d1ed1eec28e7dbdfbcc04712e4c79c0f83faf17 2.79MB / 2.79MB                                    0.6s
 => => sha256:8ef94372a977c02d425f12c8cbda5416e372b7a869a6c2b20342c589dba3eae5 301.72kB / 301.72kB                                0.4s
 => => sha256:025f14a3d97f92c07a07446e7ea8933b86068d00da9e252cf3277e9347b6fe69 125.33MB / 125.33MB                               13.7s
 => => sha256:7047deb9704134ff71c99791be3f6474bb45bc3971dde9257ef9186d7cb156db 125B / 125B                                        0.8s
 => => extracting sha256:89d9c30c1d48bac627e5c6cb0d1ed1eec28e7dbdfbcc04712e4c79c0f83faf17                                         0.2s
 => => extracting sha256:8ef94372a977c02d425f12c8cbda5416e372b7a869a6c2b20342c589dba3eae5                                         0.1s
 => => extracting sha256:1ec62c064901392a6722bb47a377c01a381f4482b1ce094b6d28682b6b6279fd                                         0.0s
 => => extracting sha256:025f14a3d97f92c07a07446e7ea8933b86068d00da9e252cf3277e9347b6fe69                                         5.2s
 => => extracting sha256:7047deb9704134ff71c99791be3f6474bb45bc3971dde9257ef9186d7cb156db                                         0.0s
 => [internal] load build context                                                                                                 0.3s
 => => transferring context: 2.11kB                                                                                               0.0s
 => [dev 2/5] RUN apk add --no-cache git ca-certificates                                                                          3.8s
 => [dev 3/5] RUN adduser -D appuser                                                                                              1.7s
 => [dev 4/5] WORKDIR /src                                                                                                        0.5s
 => [dev 5/5] COPY . /src/                                                                                                        0.4s
 => [build 1/1] RUN CGO_ENABLED=0 go build -o app .                                                                              11.6s
 => [artifact 1/1] COPY --from=build /src/app /app                                                                                0.5s
 => exporting to client                                                                                                           0.1s
 => => copying files 10.00MB                                                                                                      0.1s

Після завершення збірки appбуло експортовано двійкове:

$ ls
Dockerfile  app  go.mod  main.go

$ ./app
Ready to receive requests on port 8080

Docker має інші параметри до --outputпрапора, зафіксованого в їхньому репортажі BuildKit версії: https://github.com/moby/buildkit#output


стандартний кеш збірки не використовується для збирання з виходом, це погано
burtsevyg

@burtsevyg Buildkit - це інший конструктор, який використовує інше середовище кешу. Це набагато ефективніше кеш.
BMitch

дякую, я вдосконалю свої вузли збірки.
бурцевий

4

Як більш загальне рішення, є плагін CloudBees для того, щоб Дженкінс будував всередині контейнера Docker . Ви можете вибрати зображення, яке потрібно використовувати з реєстру Docker, або визначити Dockerfile для його створення та використання.

Він змонтує робочу область в контейнер як об'єм (з відповідним користувачем), встановить його в якості робочого каталогу, виконувати всі команди, які ви вимагаєте (всередині контейнера). Для цього також можна використовувати плагін docker-workflow (якщо ви надаєте перевагу коду над інтерфейсом користувача) за допомогою команди image.inside () {}.

В основному все це, запечене на вашому сервері CI / CD, а потім і деякі.


4

Я використовував PowerShell (Адміністратор) з цією командою.

docker cp {container id}:{container path}/error.html  C:\\error.html

Приклад

docker cp ff3a6608467d:/var/www/app/error.html  C:\\error.html

2

Ще один хороший варіант - спочатку скласти контейнер, а потім запустити його, використовуючи прапор -c з інтерпретатором оболонки, щоб виконати деякі кому

docker run --rm -i -v <host_path>:<container_path> <mydockerimage> /bin/sh -c "cp -r /tmp/homework/* <container_path>"

Наведена вище команда робить це:

-i = запустити контейнер в інтерактивному режимі

--rm = вилучено контейнер після виконання.

-v = поділилася папкою як об'єм з вашого хостового шляху до шляху контейнера.

Нарешті, / bin / sh -c дозволяє ввести команду як параметр, і ця команда скопіює файли домашнього завдання в шлях контейнера.

Я сподіваюся, що ця додаткова відповідь може вам допомогти


1

Створіть каталог даних у хост-системі (поза контейнером) та встановіть її до каталогу, видимого зсередини контейнера. Це розміщує файли у відомому місці в хост-системі та спрощує доступ до файлів інструментів та програм у хост-системі.

docker run -d -v /path/to/Local_host_dir:/path/to/docker_dir docker_image:tag

4
Це дозволяє вводити каталог і його вміст від хоста в контейнер. Це не дозволяє копіювати файли з контейнера назад на хост.
BMitch

Це робить, якщо папка хоста має дуже широкі дозволи?
giorgiosironi

0

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

docker run -d -v hostpath:dockerimag

0

Ви можете використовувати bindзамість того, volumeякщо потрібно монтувати лише одну папку, а не створювати спеціальне сховище для контейнера:

  1. Створіть своє зображення тегом:

    docker build . -t <image>

  2. Запустіть своє зображення та зв’яжіть поточний каталог $ (pwd), де зберігається app.py, і нанесіть його на / root / example / всередині вашого контейнера.

    docker run --mount type=bind,source="$(pwd)",target=/root/example/ <image> python app.py


0

Це також можна зробити в SDK, наприклад, python. Якщо у вас вже є контейнер, ви можете знайти ім'я через console ( docker ps -a), ім'я вченого є деяким об'єднанням вченого та прикметником (наприклад, "relax_pasteur").

Перевірте help(container.get_archive):

Help on method get_archive in module docker.models.containers:

get_archive(path, chunk_size=2097152) method of docker.models.containers.Container instance
    Retrieve a file or folder from the container in the form of a tar
    archive.

    Args:
        path (str): Path to the file or folder to retrieve
        chunk_size (int): The number of bytes returned by each iteration
            of the generator. If ``None``, data will be streamed as it is
            received. Default: 2 MB

    Returns:
        (tuple): First element is a raw tar data stream. Second element is
        a dict containing ``stat`` information on the specified ``path``.

    Raises:
        :py:class:`docker.errors.APIError`
            If the server returns an error.

    Example:

        >>> f = open('./sh_bin.tar', 'wb')
        >>> bits, stat = container.get_archive('/bin/sh')
        >>> print(stat)
        {'name': 'sh', 'size': 1075464, 'mode': 493,
         'mtime': '2018-10-01T15:37:48-07:00', 'linkTarget': ''}
        >>> for chunk in bits:
        ...    f.write(chunk)
        >>> f.close()

Тоді щось подібне витягнеться із зазначеного шляху (/ виводу) у контейнері до вашої хост-машини і розпакує дьоготь.

import docker
import os
import tarfile

# Docker client
client = docker.from_env()
#container object
container = client.containers.get("relaxed_pasteur")
#setup tar to write bits to
f = open(os.path.join(os.getcwd(),"output.tar"),"wb")
#get the bits
bits, stat = container.get_archive('/output')
#write the bits
for chunk in bits:
    f.write(chunk)
f.close()
#unpack
tar = tarfile.open("output.tar")
tar.extractall()
tar.close()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.