В чем разница между инструкциями COPY и ADD в Dockerfile?

Ответ

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

COPY <src>... <dest>

  • Копирует локальные файлы/директории из <src> (относительно контекста сборки) в <dest> внутри образа.
  • Рекомендуется использовать по умолчанию для простого копирования, так как его поведение предсказуемо и прозрачно.
    COPY ./package.json ./app.py /usr/src/app/
    COPY ./configs/ /etc/app/

ADD <src>... <dest>

  • Делает всё то же, что и COPY, плюс две специфические функции:
    1. Автоматическая распаковка локальных tar-архивов (.tar, .tar.gz, .tar.bz2 и т.д.) в пункте назначения.
      ADD ./application.tar.gz /opt/  # Содержимое архива будет распаковано в /opt/
    2. Поддержка URL в качестве <src>. Docker скачает файл по ссылке и поместит его в образ.
      ADD https://example.com/downloads/tool.tar.gz /tmp/

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

Ответ 18+ 🔞

Слушай, давай разжую эту тему про COPY и ADD, а то народ путается, как последний дурак в аэропорту. Всё проще, чем кажется, если не лезть в дебри.

Представь, что COPY — это такой прямолинейный работяга. Ему дали файлы — он их тупо перенёс из точки А в точку Б внутри образа. Никаких фокусов, всё честно и прозрачно. Вот смотри:

COPY ./package.json ./app.py /usr/src/app/
COPY ./configs/ /etc/app/

Взял package.json, app.py и всю папку configs — и перетащил куда сказали. Ёпта, это твой основной инструмент. Используй его всегда, когда просто нужно скопировать свои файлы. Доверия к нему — ебать, стопроцентное, потому что он нихуя лишнего не делает.

А теперь ADD — это тот же работяга, но после трёх банок энергетика. Он тоже умеет копировать, но у него в запасе два особых, ебаньких, трюка.

Трюк первый: волшебная распаковка. Подсовываешь ему локальный .tar.gz архив — а он, хитрая жопа, не просто копирует этот комок файлов, а распаковывает его прямо на месте!

ADD ./application.tar.gz /opt/  # Он тут сам всё развернёт в /opt/, как по маслу

Удобно? Иногда — да, овердохуища. Но если ты не ждал этого фокуса, можно охуеть с неожиданности.

Трюк второй: интернет-зависимость. Можешь написать ему URL вместо пути.

ADD https://example.com/downloads/tool.tar.gz /tmp/

И он сам сходит в сеть, скачает этот файл и засунет в образ. Звучит заманчиво, но это, блядь, пиздопроебибна идея. Почему? Потому что твой образ становится заложником какого-то левого сайта. Упал сайт — сломался билд. Поменяли файл — инвалидировалось кэширование, и теперь каждый раз качается заново. Терпения ноль, ебать!

Поэтому золотое правило, чувак:

Хочешь просто скопировать свои файлы — юзай COPY. Всё. Предсказуемо, надёжно, без сюрпризов.

Хочешь распаковать архив — тогда можно ADD. Это его законная фича.

Хочешь что-то скачать из интернета — НЕ используй ADD. Вместо этого сделай всё явно и понятно через RUN:

RUN curl -fsSL https://example.com/tool.tar.gz -o /tmp/tool.tar.gz 
    && tar -xzf /tmp/tool.tar.gz -C /opt/ 
    && rm /tmp/tool.tar.gz

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

Короче, ADD — как опасная игрушка. Можно пользоваться, но только если точно знаешь, зачем, иначе сам от себя охуеешь, когда сборка начнёт вести себя неадекватно.