Dockerfile: ADD или COPY?

Jul 3, 2017 08:33 · 409 words · 2 minute read docker

В данной статье рассмотрим разницу между двумя очень похожими инструкциями, которые используются при сборке 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 при сборке образов, но это будут скорее частные случаи и личные предпочтения.

tweet Share