В чем разница между командами «COPY» и «ADD» в Dockerfile?

2197

В чем разница между COPYи ADDкоманд в Dockerfile, и когда бы я использовать один над другим?

COPY <src> <dest>

Инструкция COPY скопирует новые файлы <src>и добавит их в файловую систему контейнера по пути<dest>

ADD <src> <dest>

Инструкция ADD скопирует новые файлы <src>и добавит их в файловую систему контейнера по пути <dest>.

Стив
источник
11
См. Лучшие практики: docs.docker.com/engine/userguide/eng-image/…
EricSonaron
9
По состоянию на июнь 2018 года ссылка говорит, что ADD добавляет к изображению (то есть статический файл), тогда как COPY добавляет к контейнеру (то есть экземпляр образа во время выполнения). Конечно, это подразумевает, что COPY выполняется каждый раз, когда образ запускается Docker, или, может быть, это просто случай несовместимой терминологии?
Крис Робинсон
14
Я думаю, что это противоречивая терминология
Даниэль Стивенс
6
@ChrisRobinson, было бы невозможно COPYвыполнять каждый раз, когда он запускается, потому что он не обязательно имеет доступ к исходному контексту для захвата контента.
Кен Уильямс,

Ответы:

2169

Вы должны проверить ADDи COPYдокументацию для более подробного описания их поведения, но в двух словах, главное отличие состоит в том, что ADDможет сделать больше, чем COPY:

  • ADDпозволяет <src>быть URL
  • Ссылаясь на комментарии ниже, в ADD документации говорится, что:

    Если это локальный архив tar в распознанном формате сжатия (identity, gzip, bzip2 или xz), то он распаковывается как каталог. Ресурсы с удаленных URL не распаковываются.

Обратите внимание, что лучшие практики для написания Dockerfiles предлагают использовать COPYтам, где магия ADDне требуется. В противном случае вы ( поскольку вам пришлось искать этот ответ ), скорее всего, однажды удивитесь, когда захотите скопировать keep_this_archive_intact.tar.gzв свой контейнер, но вместо этого вы распыляете содержимое на свою файловую систему.

icecrime
источник
65
Просто хотел кое-что прояснить: использование ADD с URL-адресом к .tar.gz НЕ ЭКСТРАКТИРУЕТ архив в файловую систему (сейчас я дважды проверил, чтобы убедиться, и это подтверждено)
Сесиль
42
Это важная информация, и это преступление, что официальная ссылка на Dockerfile не проясняет разницу таким образом.
Cheeso
1
Не уверен, если это отличается для изображения к изображению. Я использовал изображение busybox и ADD для файла zip. Он просто появился в каталоге назначения без разархивирования. Я предполагаю, что извлечение происходит только для тарбола, но я не проверял это сейчас.
Сантош Кумар Арджунан
4
@SantoshKumarArjunan: Документация Docker гласит следующее о ADD и автоматическом извлечении tar: If <src> is a local tar archive in a recognized compression format (identity, gzip, bzip2 or xz) then it is unpacked as a directory. Resources from remote URLs are not decompressed. Docker ADD
hmacias
1
COPY разрешает --from = <name | index>, где я не могу найти такую ​​же поддержку для ADD
Брэндон
474

COPY является

То же, что «ADD», но без tar и удаленной обработки URL.

Ссылка прямо из исходного кода .

caike
источник
15
Правильно ли я вижу это: ADDтакже создает несуществующие каталоги . Так что, хотя это как-то не рекомендуется во всей этой цепочке, у него есть преимущество перед COPYтем, что вам не нужно запускать mkdirи сохранять некоторые данные
eli
3
COPY делает это тоже @eli
bhordupur
Лучшее объяснение до сих пор. Почему это не принятый ответ?
xdevx32
141

Существует некоторая официальная документация по этому вопросу: Лучшие практики для написания Dockerfiles

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

RUN mkdir -p /usr/src/things \
  && curl -SL http://example.com/big.tar.gz \
    | tar -xJC /usr/src/things \
  && make -C /usr/src/things all

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

Виктор Ласкин
источник
18
Докер говорит предпочитать COPY, потому что это более прозрачно. Из рекомендаций по использованию файла Docker (2014-12-15): Although ADD and COPY are functionally similar, generally speaking, COPY is preferred. That’s because it’s more transparent than ADD. COPY only supports the basic copying of local files into the container, while ADD has some features that are not immediately obvious.
схема
115

Из документов Докера:

ДОБАВИТЬ или КОПИРОВАТЬ

Хотя ADD и COPY функционально схожи, в общем, COPY является предпочтительным. Это потому, что он более прозрачен, чем ADD. COPY поддерживает только базовое копирование локальных файлов в контейнер, в то время как ADD обладает некоторыми функциями (такими как локальное извлечение tar и удаленная поддержка URL), которые не сразу очевидны. Следовательно, для ADD лучше всего использовать локальное извлечение файла tar в образ, как в ADD rootfs.tar.xz /.

Подробнее: Лучшие практики для написания Dockerfiles

eddd
источник
46

Если вы хотите добавить xx.tar.gz во входной /usr/localконтейнер, разархивируйте его, а затем удалите ненужный сжатый пакет.

Для КОПИИ:

COPY resources/jdk-7u79-linux-x64.tar.gz /tmp/
RUN tar -zxvf /tmp/jdk-7u79-linux-x64.tar.gz -C /usr/local
RUN rm /tmp/jdk-7u79-linux-x64.tar.gz

Для ДОБАВИТЬ:

ADD resources/jdk-7u79-linux-x64.tar.gz /usr/local/

ADD поддерживает локальное извлечение tar. Помимо этого, COPY будет использовать три слоя, но ADD использует только один слой.

BertLi
источник
3
Любая причина, почему не просто два слоя? RUN tar -zxvf /tmp/jdk-7u79-linux-x64.tar.gz -C /usr/local && rm /tmp/jdk-7u79-linux-x64.tar.gz
Стивен С
25

COPY копирует файл / каталог с вашего хоста на ваше изображение.

ADD копирует файл / каталог с вашего хоста в ваше изображение, но также может извлекать удаленные URL, извлекать файлы TAR и т. д.

Используйте COPYдля простого копирования файлов и / или каталогов в контекст сборки.

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

JSON C11
источник
5
отличное объяснение для такого нуба, как я
uneq95
17

Из документации Docker: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy

«Хотя ADD и COPY функционально схожи, в общем случае, COPY предпочтительнее. Это потому, что он более прозрачен, чем ADD. COPY поддерживает только базовое копирование локальных файлов в контейнер, в то время как ADD имеет некоторые функции (такие как локальное извлечение tar и поддержка удаленного URL), которые не сразу очевидны. Следовательно, лучшее использование ADD - это автоматическое извлечение локального tar-файла в образ, как в ADD rootfs.tar.xz /.

Если у вас есть несколько шагов Dockerfile, которые используют разные файлы из вашего контекста, скопируйте их по отдельности, а не все сразу. Это гарантирует, что кэш сборки каждого шага становится недействительным (что приводит к повторному запуску шага), если изменяются специально необходимые файлы.

Например:

 COPY requirements.txt /tmp/
 RUN pip install --requirement /tmp/requirements.txt
 COPY . /tmp/

Приводит к меньшему количеству недействительности кэша для шага RUN, чем при установке COPY. / TMP / до этого.

Поскольку размер изображения имеет значение, использование ADD для извлечения пакетов из удаленных URL настоятельно не рекомендуется; вы должны использовать curl или wget вместо этого. Таким образом, вы можете удалить файлы, которые вам больше не нужны, после того, как они были извлечены, и вам не нужно будет добавлять еще один слой в изображение. Например, вы должны избегать таких вещей, как:

 ADD http://example.com/big.tar.xz /usr/src/things/
 RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
 RUN make -C /usr/src/things all

И вместо этого сделайте что-то вроде:

 RUN mkdir -p /usr/src/things \
     && curl -SL htt,p://example.com/big.tar.xz \
     | tar -xJC /usr/src/things \
     && make -C /usr/src/things all

Для других элементов (файлов, каталогов), которые не требуют возможности автоматического извлечения tar из ADD, вы всегда должны использовать COPY. "

jhpg
источник
7

Источник: https://nickjanetakis.com/blog/docker-tip-2-the-difference-between-copy-and-add-in-a-dockerile :

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

COPY принимает в Src и назначения. Он позволяет вам копировать только локальный файл или каталог с вашего хоста (машина, создающая образ Docker) в сам образ Docker.

ADD позволяет вам это делать, но также поддерживает 2 других источника. Во-первых, вы можете использовать URL вместо локального файла / каталога. Во-вторых, вы можете извлечь файл tar из источника непосредственно в место назначения

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

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

Шагун Прути
источник
7

При создании Dockerfile есть две команды, которые вы можете использовать для копирования файлов / каталогов в него - ADDи COPY. Хотя существуют небольшие различия в объеме их функций, они, по сути, выполняют одну и ту же задачу.

Итак, почему у нас есть две команды, и как мы знаем, когда использовать одну или другую?

ДОКЕРНАЯ ADDКОМАНДА

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

Команда копирует файлы / каталоги в файловую систему указанного контейнера.

Основной синтаксис ADDкоманды:

ADD <src> … <dest>

Он включает источник, который вы хотите скопировать ( <src>), а также место назначения, где вы хотите его сохранить ( <dest>). Если источником является каталог, ADDкопируется все внутри него (включая метаданные файловой системы).

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

ADD /source/file/path  /destination/path

ADDтакже можете копировать файлы с URL. Он может загрузить внешний файл и скопировать его в требуемое место назначения. Например:

ADD http://source.file/url  /destination/path

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

ADD source.file.tar.gz /temp

Помните, что вы не можете скачать и извлечь сжатый файл / каталог из URL. Команда не распаковывает внешние пакеты при копировании их в локальную файловую систему.

ДОКЕРНАЯ COPYКОМАНДА

Из-за некоторых функциональных проблем Docker пришлось ввести дополнительную команду для дублирования контента - COPY.

В отличие от его тесно связанной ADDкоманды, COPYимеет только одну назначенную функцию. Его роль заключается в дублировании файлов / каталогов в указанном месте в их существующем формате. Это означает, что он не занимается извлечением сжатого файла, а скорее копирует его как есть.

Инструкция может использоваться только для локально сохраненных файлов. Поэтому вы не можете использовать его с URL-адресами для копирования внешних файлов в ваш контейнер.

Чтобы использовать COPYинструкцию, следуйте основному формату команды:

Введите источник и где вы хотите, чтобы команда извлекла содержимое следующим образом:

COPY <src> … <dest> 

Например:

COPY /source/file/path  /destination/path 

Какую команду использовать? (Лучшая практика)

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

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

Если вам нужно скопировать из локального контекста сборки в контейнер, придерживайтесь его COPY.

Команда Docker также настоятельно рекомендует использовать ADDдля загрузки и копирования пакета из URL. Вместо этого безопаснее и эффективнее использовать wget или curl внутри RUNкоманды. Тем самым вы избегаете создания дополнительного слоя изображения и экономите место.

Йоги Гореча
источник
4

Важная заметка

Я должен был COPYраспаковать пакет java в моем образе докера. Когда я сравнил размер образа докера, созданного с помощью ADD, он был на 180 МБ больше, чем размер, созданный с помощью COPY, tar -xzf * .tar.gz и rm * .tar.gz.

Это означает, что хотя ADD удаляет файл tar, он все равно где-то хранится. И это делает изображение больше!

Ави Вельц
источник
Это все еще верно для последней версии Docker?
Navin
3

Поскольку Docker 17.05 COPYиспользуется с --fromфлагом в многоэтапных сборках для копирования артефактов с предыдущих этапов сборки на текущий этап сборки.

из документации

При желании COPY принимает флаг, --from=<name|index>который можно использовать для установки исходного местоположения на предыдущий этап сборки (созданный с помощью FROM .. AS), который будет использоваться вместо контекста сборки, отправленного пользователем.

MCI
источник
0
docker build -t {image name} -v {host directory}:{temp build directory} .

Это еще один способ скопировать файлы в изображение. Опция -v временно создает том, который мы использовали в процессе сборки.

Это отличается от других томов, потому что он монтирует каталог хоста только для сборки. Файлы могут быть скопированы с помощью стандартной команды cp.

Также, как curl и wget, его можно запускать в стеке команд (работает в одном контейнере) и не увеличивать размер изображения. ADD и COPY нельзя наращивать, потому что они выполняются в автономном контейнере, и последующие команды для тех файлов, которые выполняются в дополнительных контейнерах, умножат размер изображения:

С параметрами, установленными таким образом:

-v /opt/mysql-staging:/tvol

Следующее будет выполняться в одном контейнере:

RUN cp -r /tvol/mysql-5.7.15-linux-glibc2.5-x86_64 /u1 && \
    mv /u1/mysql-5.7.15-linux-glibc2.5-x86_64 /u1/mysql && \

    mkdir /u1/mysql/mysql-files && \
    mkdir /u1/mysql/innodb && \
    mkdir /u1/mysql/innodb/libdata && \
    mkdir /u1/mysql/innodb/innologs && \
    mkdir /u1/mysql/tmp && \

    chmod 750 /u1/mysql/mysql-files && \
    chown -R mysql /u1/mysql && \
    chgrp -R mysql /u1/mysql
Деннис Пэйн
источник
1
На какой версии докера вы видите эту опцию? Это не задокументировано и не работает на моем клиенте 1.12.1.
BMitch
2
На самом деле, эта функция до сих пор не включена в основной выпуск, и по-прежнему ведется много дискуссий на эту тему, поэтому мы не должны ожидать ее в течение долгого времени ... Подробнее об этом см. В отчете об ошибках: github.com/ Докер / Докер / Issues / 14080 .
Jwatkins
1
Да, такой опции нет (проверено в последней версии 17.06). Этот ответ вводит в заблуждение. unknown shorthand flag: 'v' in -v
Кирби
Вводящий в заблуждение комментарий
Гвидо ван Стин
Тома Docker здесь не имеют никакого отношения к ответу, пожалуйста, если можно, ответьте на прямой вопрос :), это легко даунвот.
Маджид Али Хан