Как скопировать файл из контейнера docker

Обновлено: 07.07.2024

В идеальном случае передача изображений Docker осуществляется через реестр Docker или через полностью управляемого поставщика, такого как AWS ECR или Google GCR. Вы можете легко загрузить изображение с помощью команды docker push , а другие могут получить изображение с помощью команды docker pull .

Хотя, если вам нужно переместить изображение с одного хоста на другой, чтобы протестировать его перед отправкой в ​​производственную среду, или вы хотите поделиться этим изображением с кем-то в офисе, это можно сделать, экспортировав изображение как .tar файл.

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

  1. Docker save - Save используется для сохранения изображения (не контейнера)
  2. Docker export - Export используется для сохранения контейнера (не изображения)

Использование Docker Save Command:

Сохранение изображения Docker:

Во-первых, мы будем придерживаться плана, который сохраняет только изображение. Теперь пройдемся по команде docker save . Предположим, вам нужен образ Python с Alpine, который можно извлечь из Docker Hub:

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

Просто убедитесь, что вы используете точное имя изображения и тег при создании tar. В нашем случае так и было python:2.7.17-alpine3.9 . Вы можете проверить, сработала ли вышеуказанная команда:

Загрузка изображения докера:

Как только на целевой машине будет файл .tar , вы можете загрузить образ в локальный реестр, используя команду docker load :

Теперь проверьте, есть ли у вас это изображение на целевом компьютере, с помощью docker images или docker image list . Конечный результат будет примерно таким:

Использование команды экспорта Docker:

Примечание. Команда docker export не будет экспортировать содержимое тома, который прикреплен к контейнеру. В этом случае вам необходимо выполнить дополнительную команду для резервного копирования, восстановления или миграции существующего тома.

Посмотрев на метод docker export , сначала мы потянем альпийское изображение:

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

Чтобы получить идентификатор контейнера и имя, которое мы создали, мы можем использовать команду docker ps . На всякий случай, если на вашей машине контейнер был остановлен по какой-либо причине, вы все равно можете получить идентификатор и имя, используя docker ps -a :

Как мы видим, наш идентификатор контейнера 35f34fabfa84 (он будет другим для вас), или вы также можете использовать имя контейнера; в нашем случае это alpine-t . Теперь мы можем запустить команду docker export для экспорта изображения экземпляра:

Кроме того, вы также можете использовать OPTIONS, чтобы сделать то же самое, и ваш файл .tar будет готов для передачи.

Теперь вы можете импортировать файл .tar на целевой компьютер, используя импорт докера:

Чтобы проверить, вы можете запустить контейнер с помощью --rm (он уничтожит контейнер, как только вы его выполните):

Я думаю об использовании Docker для построения моих зависимостей на сервере Continuous Integration (CI), чтобы мне не пришлось устанавливать все среды выполнения и библиотеки на самих агентах.

Для этого мне нужно скопировать артефакты сборки, которые встроены в контейнер, обратно в хост. Это возможно?

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

Здесь goofy_roentgen - это имя контейнера, которое я получил от следующей команды:

Вы также можете использовать (часть) ID контейнера . Следующая команда эквивалентна первой

Вот удобный способ получить в вашем последний контейнер , если вы просто используете докер для среды Linux темпа: docker ps -alq . Эта команда cp также работает как есть для копирования деревьев каталогов (не только одного файла). В новых версиях Docker вы можете копировать в двух направлениях (хост-контейнер или контейнер-хост) с помощью docker cp . Мне нужно docker cp -L было скопировать символические ссылки ПРИМЕЧАНИЕ: контейнер не должен быть запущен, чтобы использовать команду cp. Удобно, если ваш контейнер постоянно падает.

Вам не нужно использовать docker run .

Вы можете сделать это с docker create .

Команда docker create создает доступный для записи слой контейнера над указанным изображением и подготавливает его для выполнения указанной команды. Идентификатор контейнера затем печатается в STDOUT . Это похоже на то, docker run -d что контейнер никогда не запускается.

Итак, вы можете сделать:

Здесь вы никогда не запускаете контейнер. Это выглядело выгодно для меня.

Это требует больше голосов. Отлично подходит для случаев, когда вам просто нужно создать что-то в контейнере, а затем скопировать результаты. @HonzaKalfus Я согласен, что это должно быть выше. Это именно то, что я был после. Я использовал это так, чтобы я мог создавать некоторые двоичные файлы, используя известную среду (amazon linux в определенной версии). смог создать сценарий оболочки, который полностью собрал докер и извлек из него полученный бинарный файл! Отлично. @jII, я сделал это, потому что позже я запускаю на нем докер. В простых случаях это не нужно, но и здесь не вредит. Можно ли как-то использовать подстановочные знаки? Я имею в виду . Я не знаю точное имя файла, который мне нужно скопировать, потому что на нем есть номер версии.

Смонтируйте «том» и скопируйте туда артефакты:

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

редактировать

Предостережение: при этом вы можете столкнуться с проблемами с идентификатором пользователя докера, совпадающим с идентификатором текущего запущенного пользователя. То есть файлы в /artifacts будут показаны как принадлежащие пользователю с UID пользователя, использованного внутри контейнера докера. Обходным путем может быть использование UID вызывающего пользователя:

На самом деле вы можете использовать chown команду для сопоставления идентификатора пользователя и идентификатора группы на хост-компьютере. Уже сделал, и это не сработает. После того как контейнер скопировал файлы на том в первый раз, в следующий раз том больше не будет пустым, и файлы не будут перезаписаны более новыми. Контейнер отдает приоритет файлам хоста (те, которые были скопированы при первом подключении образа контейнера). звучит как что-то, что может быть своим собственным вопросом @Frondor

Смонтируйте том, скопируйте артефакты, настройте идентификатор владельца и идентификатор группы:

Описание

docker run с томом хоста, chown артефактом, cp артефактом для тома хоста:

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

  • Вы не должны docker container run --name или docker container create --name раньше
  • вам не нужно docker container rm после
Проголосовал за сравнение cp и ответы на основе объема. Кроме того, для id трюка за владение, это иногда настоящая головная боль Кстати, вопрос о том, должен ли контейнер / должен быть запущен / остановлен / зависит от типа хоста / технологии виртуализации . Текущий докер говорит, что «КОНТЕЙНЕР может быть работающим или остановленным контейнером». Множество мест на SO, включая комментарий к принятому ответу, говорят «это также работает на остановленном контейнере». Под Windows Hyper-V это, по- видимому необходимо , чтобы остановить контейнер перед копированием файла . Копирование также работает, когда контейнер остановлен.

Если у вас нет работающего контейнера, только изображение, и если вы хотите скопировать только текстовый файл, вы можете сделать что-то вроде этого:

Я публикую это для всех, кто использует Docker для Mac. Вот что сработало для меня:

Обратите внимание, что при монтировании с использованием -v этого backup каталога автоматически создается.

Надеюсь, это кому-нибудь пригодится. :)

Если вы используете docker-compose, volume-from устарела в версии 3 и после.

Если вы просто хотите извлечь файл из изображения (вместо работающего контейнера), вы можете сделать это:

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

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

С выпуском Docker 19.03 вы можете пропустить создание контейнера и даже создание образа. Существует вариант с сборками на основе BuildKit для изменения выходного назначения. Вы можете использовать это для записи результатов сборки в локальный каталог, а не в изображение. Например, вот сборка go-файла:

Из приведенного выше Dockerfile я создаю artifact этап, который включает только файлы, которые я хочу экспортировать. И недавно введенный --output флаг позволяет мне записывать их в локальный каталог вместо изображения. Это необходимо выполнить с помощью движка BuildKit, который поставляется с 19.03:

Docker имеет две похожие инструкции Dockerfile, COPY и ADD, обе из которых используются для импорта файлов в образ. В этой статье объясняется, почему лучше использовать COPY вместо ADD, если вы не хотите автоматически извлекать локальный пакет tar в образ.

Рекомендации по использованию инструкции КОПИРОВАТЬ

Эта инструкция Dockerfile копирует один или несколько локальных файлов или папок в целевой образ докера.

  • COPY <source>… <destination>
  • COPY ["<источник>", . "<место назначения>"] (этот формат требуется для путей, содержащих пробелы)

Например, используйте инструкцию COPY в Dockerfile.

Это простой пример того, как использовать инструкцию COPY в Dockerfile для создания приложения Ruby.

Он строит изображение в слоях, начиная с родительского изображения ruby: 2.5.1, используя определение FROM.

Используйте инструкцию WORKDIR, чтобы определить рабочий каталог, а затем используйте инструкцию COPY или ADD.

В этом случае, когда используется копия, он будет копировать файл из локального источника. Указывает файл в текущем каталоге в месте, определенном WORKDIR. В приведенном выше примере вторая КОПИЯ означает, что рабочий каталог в зеркале копируется из текущего каталога.

Рекомендации по использованию КОПИРОВАНИЯ для создания зеркальных слоев

Docker рекомендует использовать COPY для создания слоев изображений, сохраняя разные контексты файлов в разных слоях изображений. Это означает, что реконструкция изображения эффективна. Файлы, которые, скорее всего, будут изменены, должны находиться на нижних уровнях, а файлы, которые, скорее всего, будут изменены, должны быть добавлены последними.

Если есть несколько шагов dockerfile с использованием контекстов из разных файлов, скопируйте их по отдельности, а не все сразу. Это гарантирует, что кеш сборки для каждого шага становится недействительным только при изменении особо необходимых файлов.
–Best practices for writing Dockerfiles

Этот принцип продемонстрирован в приведенном выше примере файла dockerfile. Скопировав Gemfiles, а затем выполнив Run bundle install, вы можете использовать установленные рубиновые драгоценные камни для создания слоя изображения, который можно кэшировать. Последние две инструкции докера копируют файлы приложения в образ и используют CMD для установки команд по умолчанию.

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

Почему не стоит использовать инструкцию ADD

Синтаксис инструкции ADD аналогичен синтаксису COPY. Помимо копирования локальных файлов и каталогов в место назначения в образе Docker, он также имеет некоторые дополнительные функции.

  • ADD <source>… <destination>
  • ДОБАВИТЬ ["<источник>", . "<место назначения>"] (Этот формат требуется для путей, содержащих пробелы)

Однако официальное руководство Dockerfile по лучшей практике указывает, что в большинстве случаев COPY является предпочтительной инструкцией по сравнению с ADD.

Хотя функции ДОБАВЛЕНИЯ и КОПИРОВАНИЯ схожи, в общем случае предпочтительнее КОПИРОВАТЬ. Это потому, что он более прозрачен, чем ADD. COPY поддерживает только копирование локальных файлов в контейнер, в то время как ADD имеет некоторые менее очевидные функции (такие как локальное извлечение tar и поддержка удаленных URL). Поэтому лучше всего использовать ADD для автоматического извлечения локального tar-файла на зеркало, например ADD rootfs.tar.xz /
-— Best practices for writing Dockerfiles

Еще одна дополнительная функция ADD - это то, что он может копировать файлы с URL-адресов, но Docker рекомендует не использовать его для этой цели.

Рекомендации по копированию файлов с URL

Если источником ADD является URL-адрес, он загрузит файл и скопирует его в место назначения в образе докера. Докер считает, что использование добавления для копирования с URL-адреса обычно неэффективно, и для включения необходимых удаленных файлов лучше использовать другие стратегии.

Поскольку размер изображения важен, настоятельно рекомендуется не использовать ADD для получения пакетов с удаленного URL-адреса; вам следует использовать curl или wget. Таким образом, вы можете удалить файлы, которые больше не нужны после извлечения, без добавления к изображению других слоев.
-— Dockerfile Best Practices

Например, следует избегать следующих действий:

Вместо этого выполните следующие операции:

Когда следует использовать инструкцию ADD

Если <source> является локальным tar-файлом в узнаваемом формате сжатия, он будет автоматически распакован в образ Docker как каталог. Например: добавьте rootfs.tar.xz /. Это сценарий ADD, официально рекомендованный докером.

Для других файлов или каталогов, для которых функция автоматической распаковки ADD не требуется, всегда следует использовать COPY.

Это третья часть серии статей про Docker и она всецело посвящена Docker-файлам. В первой части основные концепции Docker объясняются на простых примерах из жизни. Во второй статье — краткий обзор экосистемы Docker.

Docker-образы

Docker-образ создаётся во время сборки, а Docker-контейнер — во время запуска приложения.

Каждый Docker-образ содержит файл с именем Dockerfile (он без расширения). При вызове docker build предполагается, что Dockerfile будет находиться в текущей рабочей директории. Но с помощью флага -f можно указать другое расположение.

Руководитель направления (Technical Product Manager)

Sportmaster Lab , Липецк, Санкт-Петербург, Москва , От 200 000 до 300 000 ₽

При загрузке Docker-образа из удалённого репозитория скачиваются только отсутствующие у вас слои. Docker экономит место и время, повторно используя уже существующие слои.

Инструкция Docker-файла — слово в верхнем регистре, которое стоит перед аргументом какой-либо команды. Каждая строка в Docker-файле может содержать инструкцию, все они обрабатываются сверху вниз. Инструкции выглядят так:

Эта статья предполагает использование Unix Docker-образа. Вы, конечно, можете использовать и Windows Docker-образ, но он медленнее, менее удобный и, вообще, его не часто применяют. Так что, пользуйтесь Unix по возможности.

Несколько Docker-инструкций

Инструкции и примеры к ним

Docker-файл чисто теоретически может содержать только одну строчку:

В этом примере хранилище образов — Ubuntu. Ubuntu — название официального Docker-репозитория, в котором и содержится данная ОС.

Заметьте, что этот Docker-файл содержит тег для базового образа: 18.04, который указывает Docker’у, какую именно версию образа нужно использовать. Если тег не указан, по умолчанию берётся последняя версия образа. Но лучше всё же указывать тег базового образа. Когда Docker-файл, приведённый выше, используется для создания локального Docker-образа впервые, он загружает слои, указанные в образе Ubuntu.

При создании Docker-контейнера, вы помещаете наверх слой, который впоследствии можно будет изменить.

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

Подробнее про Docker-файл

Кроме того, что ваш однострочный образ сжат, он ещё и медленный, предоставляет мало информации и ничего не делает во время запуска контейнера. Посмотрите на более длинный Docker-файл, который запускает более легковесный образ, а также выполняет скрипт во время запуска.

Но что же это всё обозначает?

В роли базового образа выступает официальный Python-образ с тегом 3.7.2-alpine3.8. Как вы можете увидеть из исходников, образ включает в себя Linux, Python и ничего более. Alpine-образы очень популярны, потому что они маленькие, быстрые и безопасные. Однако Alpine-образы не поставляются сразу со всеми компонентами, характерными для вашей ОС. Некоторые пакеты вам придётся установить самостоятельно.

LABEL

Следующая инструкция — LABEL . LABEL добавляет метаданные к образу, предоставляет контактную информацию. Она не замедляет процесс запуска и не занимает много места, наоборот, обеспечивает образ полезной информацией, так что обязательно используйте её. Больше про LABEL читайте здесь.

ENV создаёт переменную окружения, которая становится доступной во время запуска контейнера. В примере выше вы могли видеть использование переменной ADMIN при создании контейнера.

ENV удобна для обозначения констант. Если константа используется в нескольких местах файла Dockerfile, и вам понадобится изменить её значение позднее, это можно будет сделать в одном месте.

Docker-файл зачастую предоставляет несколько путей решения одной задачи. Будет хорошо, если в вашем решении будет учитываться баланс Docker-соглашений, прозрачность и скорость. К примеру, RUN , CMD и ENTRYPOINT служат различным целям и могут использоваться для выполнения команд.

RUN создаёт слой во время запуска. Docker фиксирует состояние образа после каждой инструкции RUN .

apk — это сокращение от Alpine Linux package manager. Если вы используете базовый образ не Alpine Linux, то установка пакетов производится командой RUN apt-get .

RUN и её родственные инструкции: CMD , ENTRYPOINT — могут быть как форме оболочки, так и в форме shell-скрипта. Во втором случае используют JSON-синтаксис: RUN ["my_executable", "my_first_param1", "my_second_param2"] . А в примере выше использовалась форма оболочки: RUN apk update && apk upgrade && apk add bash .

Позднее в вашем Docker-файле вы будете создавать новую директорию, используя ["mkdir", "/a_directory"] . Не забывайте, что в JSON нужно использовать двойные кавычки!

Инструкция COPY . ./app говорит Docker’у, что нужно скопировать файлы и папки из вашей локальной сборки в рабочую директорию образа. COPY создаст все нужные папки, если они отсутствуют.

ADD делает то же самое, что и COPY , но с двумя отличиями. ADD может загружать файлы по URL, а также извлекать локальные TAR-файлы.

В примере выше ADD копировала файлы по URL внутрь директории контейнера. Но официальныя документация не рекомендует использовать ADD так, потому что потом вы попросту не сможете удалить файлы. А дополнительные файлы увеличивают размер образа.

CMD — инструкция для запуска чего-либо во время запуска самого контейнера. По ходу сборки она не фиксирует никакого результата. В примере выше во время сборки запускался скрипт my_script.py .

Ещё пара моментов о CMD :

  • Только одна CMD -инструкция на весь Docker-файл. Иначе все кроме последней будут проигнорированы;
  • CMD может включать исполняемый файл;
  • Если же CMD не содержит никакого файла, обязательно должна быть инструкция ENTRYPOINT . В этом случает обе инструкции должны быть в формате JSON;
  • Аргументы командной строки для запуска Docker переопределяют аргументы, предоставленные CMD в Docker-файле.

Готовы к большему?

В следующем примере представлены ещё несколько Docker-инструкций:

Для Alpine Docker-образа вы используете apk. apk для типичной Linux-сборки — apt-get . Например, пакеты для базового Ubuntu-образа могут быть установлены и обновлены так: RUN apt-get update && apt-get install my_package .

В дополнение к apk и apt-get , Python-пакеты могут быть установлены через pip, wheel и conda. Методы варьируются в зависимости от языка.

Нижележащие слои должны предоставить свое средство установки и управления пакетами. Если возникнет проблема с установкой пакетов, убедитесь, что у вас установлен менеджер пакетов.

Можно использовать RUN вместе с pip и списком нужных пакетов. Для этого объедините команды установки пакетов в одну инструкцию и разделите их символом продолжения строки ( \ ). Этот метод позволяет улучшить читаемость и уменьшить количество слоев (из-за отсутствия возможности использовать несколько RUN инструкций).

Также вы можете запустить установщик, указав ему файл, содержащий все зависимости для вашего образа. Обычно он называется requirements.txt.

WORKDIR

Меняет текущую рабочую директорию в контейнере для инструкций: COPY , ADD , RUN и ENTRYPOINT .

  • Предпочтительно задать абсолютный путь с помощью WORKDIR, а не перемещаться по файловой системе с помощью команд cd в Docker-файле;
  • WORKDIR автоматически создаёт директорию, если её ещё нет;
  • Можно использовать несколько WORKDIR -инструкций. Если используются относительные пути — каждая инструкция поменяет рабочую директорию.

Определяет переменную для передачи из командной строки в образ. Для ARG можно указать значение по умолчанию: ARG my_var=my_default_value .

В отличие от ENV -переменных, ARG -переменные не доступны для запущенных контейнеров. Однако вы можете использовать их для установки дефолтных значений для ENV -переменных, когда вы создаёте образ. И затем ENV-переменные сохраняются. Больше про это вы найдёте здесь.

ENTRYPOINT

ENTRYPOINT тоже позволяет вам задавать дефолтные команды и аргументы во время запуска контейнера. Она похожа на CMD , но параметры ENTRYPOINT не переопределяются, если контейнер запущен с параметрами командной строки.

Вместо этого аргументы командной строки, передаваемые docker run myimagename , добавляются к аргументам инструкции ENTRYPOINT . Например, docker run my_image bash добавляет аргумент bash в конец, ко всем другим аргументам ENTRYPOINT .

Docker-файл обязательно должен содержать либо CMD -инструкцию, либо ENTRYPOINT -инструкцию.
В официальной документации есть несколько советов, которые помогут сделать выбор между CMD и ENTRYPOINT для начальной команды:

  • Если вам нужно запускать одну и туже команду несколько раз, выбирайте ENTRYPOINT ;
  • Используйте ENTRYPOINT , когда ваш контейнер выступает в роли исполняющейся программы;
  • При наличии дополнительных дефолтных аргументов, которые могут быть изменены через командную строку, лучше подойдёт CMD .

В примере выше, ENTRYPOINT ["python", "my_script.py", "my_var"] запускает в контейнере Python-скрипт my_script.py с аргументом my_var . Затем переменная my_var может быть использована в my_script argparse. Заметьте, у my_var есть дефолтное значение, ранее установленное в Docker-файле при помощи ARG . Так что, если аргумент не будет задан через командную строку, возьмётся его значение по умолчанию.

Как правило, Docker рекомендует вам использовать исполняемую форму с JSON-синтаксисом ENTRYPOINT ["executable", "param1", "param2"] .

EXPOSE

Инструкция EXPOSE показывает, какой порт пробрасывать из контейнера.

Используйте команду docker run с флагом -p для пробрасывания и сопоставления нескольких портов во время запуска. Флаг в верхнем регистре -P будет пробрасывать все открытые порты.

VOLUME

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

Заключение

В этой статье не были упомянуты такие инструкции, как USER , ONBUILD , STOPSIGNAL , SHELL , и HEALTHCHECK , информацию про них вы сможете найти здесь.

Читайте также: