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

Ответ

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

Сравнение COPY и ADD

Инструкция Источник Ключевая особенность
COPY Локальные файлы/директории Простое и предсказуемое копирование.
ADD Локальные файлы/директории, URL, tar-архивы Обладает «магией»: может скачивать файлы по URL и автоматически распаковывать локальные .tar архивы.

Примеры:

# Dockerfile

# COPY: Просто копирует локальную директорию app в образ
COPY ./app /usr/src/app

# ADD: Копирует и распаковывает локальный архив
ADD project.tar.gz /usr/src/project

# ADD: Скачивает файл по URL (без распаковки)
ADD https://example.com/config.json /etc/config.json

Рекомендация и лучшая практика

Всегда используйте COPY, если вам не нужна специфическая функциональность ADD.

Почему COPY предпочтительнее?

  1. Предсказуемость: COPY делает только одно — копирует. Это делает Dockerfile более понятным и прозрачным.
  2. Кэширование: ADD с URL может приводить к проблемам с кэшированием слоев. Docker не скачивает файл заново, если URL не изменился, но содержимое файла по этому URL могло измениться. Это делает сборки ненадежными. Для скачивания файлов лучше использовать RUN wget или RUN curl, так как это создает отдельный кэшируемый слой и позволяет управлять процессом (например, проверять checksum).
  3. Безопасность: Автоматическая распаковка архивов (ADD) может быть рискованной, если архив содержит файлы с абсолютными путями (tarbomb).

Когда использовать ADD?

Единственный оправданный случай — когда вам нужно скопировать локальный tar-архив и сразу же его распаковать в один слой. В остальных случаях COPY является более безопасным и ясным выбором.

Ответ 18+ 🔞

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

Короче, представь, что COPY — это как честный работяга. Говоришь ему: «Вот папка app, вот путь в образе /usr/src/app — тащи». И он тупо, без фокусов, всё переносит. Никакой магии, никаких сюрпризов. Предсказуемо, как удар кирпичом по лбу.

А вот ADD — это уже такой хитрожопый мультитул. Он тоже умеет копировать локальные файлы, но, блядь, если ему сунуть архив .tar.gz, он его на лету распакует, прям в образе! А ещё он может файлы по URL скачивать, представляешь? Дал ссылку — и он притащил.

Примеры, чтобы въехать:

# Dockerfile

# COPY: Просто скопировал папку, как есть. Никаких тебе сюрпризов.
COPY ./app /usr/src/app

# ADD: Видит архив — охуел от счастья и распаковал его сразу в /usr/src/project
ADD project.tar.gz /usr/src/project

# ADD: Видит URL — думает: «А, ну я ща скачаю!» и тащит файл с интернета.
ADD https://example.com/config.json /etc/config.json

Так что же выбрать, ёпта?

Главное правило, которое надо выжечь на жопе: ВСЕГДА ИСПОЛЬЗУЙ COPY, если тебе специально не нужны плюшки ADD.

А почему, спросишь? Да потому что ADD — это пиздопроебищно в 99% случаев!

  1. Предсказуемость, блядь! COPY делает ровно одно действие. Ты посмотрел на строчку — и сразу понял, что будет. С ADD можно охуеть: то ли скопирует, то ли распакует, то ли с интернета что-то притащит. Волнение ебать.
  2. Кэширование с URL — это пиздец. Допустим, ты скачал файл по ссылке через ADD. Docker запомнил этот слой. Потом ты пересобираешь образ, а файл-то на том сервере уже обновился! Но Docker, такой довольный, говорит: «А, URL не менялся, кэш есть, не буду качать!» И ты получаешь старую версию. Терпения ноль ебать. Для скачивания есть RUN curl или RUN wget — это отдельный, понятный слой.
  3. Безопасность. Автораспаковка архивов — это как игра в русскую рулетку. Вдруг в архиве лежат файлы с путями вроде /etc/passwd? ADD их тупо перезапишет, не моргнув глазом. Это называется «tarbomb», и это охуенно опасная хуйня.

Так когда же ADD-то применять?

Единственный более-менее адекватный случай — это когда тебе надо скопировать локальный тар-архив и сразу его распаковать в ОДИН слой образа. Всё. Во всех остальных ситуациях — COPY, и точка. Не усложняй себе жизнь, чувак.