Dockerfile: ADD или COPY?
Jul 3, 2017 08:33 · 409 words · 2 minute read
В данной статье рассмотрим разницу между двумя очень похожими инструкциями, которые используются при сборке docker-образов из Dockerfile — ADD
и COPY
, а также определимся, какую из них лучше использовать.
Давайте разберемся! TL;DR: если вас не интересуют нюансы и нужен быстрый ответ — используйте COPY
.
При сборке docker-образов из Dockerfile можно использовать две инструкции для добавления каталогов/файлов в собираемый образ: ADD
и COPY
. Обе эти инструкции выглядят одинаково и, на первый взгляд, выполняют те же действия:
ADD <источник>... <приемник>
COPY <источник>... <приемник>
В обоих случаях, каталоги или файлы из источника будут добавлены в файловую систему контейнера по адресу приемника. Казалось бы, зачем две идентичные инструкции?
Следует упомянуть, что инструкция COPY
появилась несколько позже, в то время как инструкция ADD
была частью докера с самого начала. При сборке образов ADD
поддерживает несколько дополнительных возможностей, например, вы можете указать в качестве источника URL-адрес:
ADD http://foo.com/bar.go /tmp/main.go
В этом случае в момент сборки docker-образа файл будет скачан и добавлен в файловую систему контейнера по адресу /tmp/main.go
. Можно также использовать следующую форму инструкции:
ADD http://foo.com/bar.go /tmp/
При такой записи файл будет скачан и добавлен в файловую систему контейнера по адресу /tmp/bar.go
.
Второй особенностью инструкции ADD
является возможность автоматической распаковки архивов. Например, если аргумент-источник будет распознан как сжатый формат (tar
, gzip
, bzip2
, и т. д.) он будет распакован по адресу приемника в файловую систему контейнера:
ADD /foo.tar.gz /tmp/
В этом примере содержимое архива foo.tar.gz
будет распаковано в каталог /tmp
внутри контейнера.
Примечание. К сожалению, использовать обе эти возможности (скачать архив и распаковать его) одновременно нельзя.
Инструкция ADD
выглядит «магической» — поддерживает слишком широкую функциональность и не всегда ведет себя так, как ожидает пользователь (пример). Поэтому начиная с версии docker 1.0 была добавлена инструкция COPY
, которая не поддерживает URL-адреса в качестве источника, не умеет распаковывать архивы, все делает предельно просто и без сюрпризов — копирует файлы из локального контекста сборки (тот же каталог, где находится Dockerfile) внутрь контейнера.
Разработчики docker советуют использовать для добавления каталогов/файлов внутрь контейнера именно инструкцию COPY
. Если же вам просто необходимо скачивать и распаковывать архивы, то можно воспользоваться утилитами curl
или wget
(конечно же, они должны быть предварительно установлены).
Например, следующую конструкцию:
ADD http://foo.com/package.tar.bz2 /tmp/
RUN tar -xjf /tmp/package.tar.bz2 \
&& make -C /tmp/package \
&& rm /tmp/package.tar.bz2
гораздо проще и оптимальнее (как мы упоминали ранее) заменить на следующую:
RUN curl http://foo.com/package.tar.bz2 \
| tar -xjf /tmp/package \
&& make -C /tmp/package
Конечно, никто не запрещает вам использовать инструкции ADD
при сборке образов, но это будут скорее частные случаи и личные предпочтения.