Чем отличает COPY от ADD

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

📌 Общие черты

  • Обе инструкции копируют файлы из контекста сборки (обычно папка рядом с Dockerfile).

Синтаксис одинаковый:

<br/>COPY &lt;src&gt; &lt;dest&gt;
ADD &lt;src&gt; &lt;dest&gt;
  • где:

    • <src> — путь к файлу или папке на хосте;

    • <dest> — путь внутри контейнера.

  • Обе команды создают новый слой образа, который можно кэшировать.

  • Обе инструкции не выполняют shell-команды (в отличие от RUN).

📌 Отличия между COPY и ADD

Возможность COPY ADD
Простое копирование
--- --- ---
Автоматическое извлечение архива ✅ (только .tar, .tar.gz, .tgz, .tar.bz2)
--- --- ---
Копирование из URL
--- --- ---
Поддержка только локальных файлов
--- --- ---
Явное поведение
--- --- ---

1. Копирование файлов и папок

  • COPY просто копирует указанный файл или каталог как есть.

  • ADD также копирует, но дополнительно может:

    • Распаковать архив;

    • Скачать файл по URL.

Пример:

COPY app/ /app/
ADD app/ /app/

Оба скопируют папку app/ в образ.

2. Распаковка архивов

  • ADD умеет распаковывать архивы .tar, .tar.gz и т.п. при копировании.

  • COPY — нет, он просто копирует архив как файл.

Пример:

ADD archive.tar.gz /app/

→ Контейнер получит распакованные файлы в /app/.

3. Копирование по URL

  • ADD может загружать файлы по HTTP(S).

  • COPY не поддерживает работу с удалёнными источниками.

Пример:

ADD https://example.com/config.json /config/

→ Скачивает файл и помещает в /config/.

4. Поведение с архивами: опасность неожиданностей

Если вы используете ADD и у вас есть файл .tar.gz, он будет автоматически распакован — иногда это может быть нежелательно. Это одна из причин, почему COPY чаще рекомендуется для предсказуемости.

🧠 Рекомендации по использованию

  • Используй COPY по умолчанию, когда нужно просто копировать файлы/папки.

  • Применяй ADD только при необходимости:

    • Автораспаковки .tar.* архивов;

    • Загрузки по URL.

🔒 Безопасность

  • Использование ADD для скачивания по URL может привести к уязвимостям (например, при подмене URL).

  • Поэтому при скачивании лучше использовать:

RUN curl -o file.ext https://example.com/file.ext

Это позволит явно указать, что происходит, и обработать ошибки.

🎯 Примеры

Копирование локального файла

COPY requirements.txt /app/

Распаковка архива

ADD code.tar.gz /app/

→ Распакует code.tar.gz в /app/.

Загрузка по URL

ADD https://example.com/file.tar.gz /tmp/

→ Скачает и (если это архив) распакует файл в /tmp/.

📍 Поведение с путями

  • Если src — каталог, а dest заканчивается на /, содержимое каталога копируется в эту директорию.

  • Если dest — не существует и не заканчивается на /, будет создан файл с именем dest.

🔧 Поддержка wildcards

  • Подстановочные знаки (*, ?) поддерживаются в обоих, если указан COPY/ADD в форме списка:
COPY \["\*.txt", "/app/"\]

💡 Проверка на существование

Если файл или папка, указанные в COPY или ADD, не существуют в контексте сборки, сборка прерывается с ошибкой.

Таким образом, хотя COPY и ADD похожи, они предназначены для разных задач: COPY — для предсказуемого и безопасного копирования, ADD — для продвинутых случаев (распаковка и загрузка).