В чем разница COPY и ADD в Dockerfile
Что проверяют
Знаете ли вы, что ADD умеет больше, чем кажется, и почему это чаще минус, чем плюс. Следом спрашивают, как правильно скачать файл в образ и что делать с архивом, чтобы не раздуть слой.
Как отвечать
COPY делает одно: переносит файлы и каталоги из контекста сборки в образ. С флагом --from он берёт файлы из другой стадии multi-stage сборки или из другого образа, и это основной способ отделить сборочное окружение от итогового.
ADD копирует так же, но добавляет два поведения:
- локальный tar-архив (в том числе сжатый gzip, bzip2 или xz) автоматически распаковывается в каталог назначения;
- удалённый источник: файл скачивается по URL, а в свежих версиях Dockerfile можно забрать и Git-репозиторий. Файл, скачанный по URL, не распаковывается, даже если это архив.
Именно неявная распаковка делает ADD непредсказуемым: достаточно положить в контекст .tar.gz, который нужен как файл, и в образе окажется его содержимое.
Общие флаги у обеих команд: --chown, --chmod, --link. У ADD есть --checksum, который сверяет хэш скачанного, у COPY есть --from.
Практическое правило: по умолчанию COPY. ADD оправдан для распаковки локального архива (например, rootfs в базовом образе) и для скачивания с --checksum. Если скачанный файл нужно распаковать и удалить, лучше RUN curl ... && tar ... && rm ... одной командой: промежуточный архив не останется в отдельном слое. Линтер hadolint предупреждает об ADD там, где хватило бы COPY.
Где спотыкаются
Считают, что ADD распакует архив и по URL. Не распакует, для этого нужен отдельный RUN.
Скачивают через ADD без проверки хэша. Сборка перестаёт быть воспроизводимой, и в образ может попасть подменённый файл.
Забывают про .dockerignore. Он действует на обе команды, и без него COPY . . тащит в образ node_modules, .git и локальные .env, заодно сбрасывая кэш слоя при любой правке.