n1ro°
RU

Текст и данные · Инструкция

.dockerignore: как работают паттерны и исключения

.dockerignore: паттерны и исключения определяют, какие файлы вообще попадут в build context до начала сборки.

Редакция N1RO · Проверено

Короткий ответ

Как настроить .dockerignore: **, исключения через !, порядок правил, Dockerfile-specific ignore и диагностика ошибки COPY ignored file.

Что именно фильтрует .dockerignore и почему это ускоряет build

Перед выполнением Dockerfile клиент формирует build context и передаёт его builder. Если в корне контекста есть .dockerignore, совпавшие файлы и каталоги убираются до отправки. Это уменьшает объём передачи, ускоряет удалённые и BuildKit-сборки и снижает риск случайно включить .git, локальные кэши, логи или секреты. Важный практический вывод: строка COPY . не может вернуть то, что уже исключено из контекста. Если сборка пишет, что файл не найден, сначала проверьте не только путь в COPY, но и правила ignore. Сам Dockerfile и .dockerignore можно исключить паттерном: builder всё равно получает их для сборки, однако скопировать эти файлы в образ через COPY/ADD уже нельзя. Для нескольких Dockerfile допускаются отдельные файлы вроде build.Dockerfile.dockerignore; такой файл имеет приоритет над корневым .dockerignore для соответствующей сборки.

Совет: Начните оптимизацию большого контекста с .git, node_modules, локальных артефактов сборки и временных файлов — это обычно даёт самый заметный эффект.

Базовые шаблоны: что совпадёт

  • node_modules. исключает путь node_modules относительно контекста
  • **/*.log. исключает .log на любой глубине
  • *.md. исключает markdown на соответствующем уровне сопоставления
  • !README.md. возвращает README.md, если более позднее правило снова его не исключит
  • dist/. исключает каталог dist

Как работает ! и почему последнее совпадение побеждает

Восклицательный знак в начале правила создаёт исключение из исключения: файл снова включается в контекст. Но это не безусловный whitelist. Docker последовательно рассматривает правила, и итог определяет последнее правило, совпавшее с конкретным путём. Поэтому пары *.md затем !README*.md и тот же набор строк в обратном порядке дают разные результаты. Если требуется оставить один файл внутри большой исключённой группы, располагайте разрешающее правило после общего запрета и затем проверяйте, не перекрывает ли его ещё одно правило ниже. Специальный шаблон ** совпадает с любым количеством каталогов, включая ноль, поэтому **/*.log удобен для логов на любой глубине. Визуально похожие ведущие и завершающие слэши для foo/bar в .dockerignore нормализуются: ориентируйтесь прежде всего на путь относительно корня build context, а не относительно каталога Dockerfile.

Предупреждение: Не копируйте .gitignore вслепую: синтаксис похож, но build context и порядок исключений нужно проверять именно в Docker-сценарии.

Как безопасно настроить .dockerignore

  1. Запустите сборку с тем же build context, который используется в CI, и зафиксируйте, какой каталог передаётся последним аргументом docker build/buildx build. Именно от него считаются пути.
  2. Добавьте крупные и заведомо ненужные каталоги: .git, node_modules, coverage, локальные кеши, временные выгрузки и секретные env-файлы, если они не должны попадать в контекст.
  3. Если общий паттерн исключает нужный файл, добавьте ниже правило с !. После этого перечитайте все более поздние строки: последнее совпадение может снова исключить файл.
  4. Для разных Dockerfile создайте <Dockerfile>.dockerignore рядом с конкретным Dockerfile, когда dev-, lint- и production-сборкам действительно нужен разный набор контекста.
  5. Если COPY сообщает missing/ignored file, временно упростите правила до минимальных, затем возвращайте их по одному. Так быстрее найти конкретное совпадение, чем менять COPY наугад.

Важно: Ошибка COPY ignored file — сигнал проверять контекст и .dockerignore, а не добавлять обходные COPY из путей вне контекста.

Частые ошибки: контекст не тот, правило слишком широкое, секрет уже отправлен

Самая частая ловушка — запуск docker build из одного каталога с Dockerfile через -f из другого. Путь Dockerfile не меняет корень build context: его задаёт финальный аргумент команды. Вторая ошибка — слишком широкое ** или имя каталога, которое встречается в нескольких местах. Третья — ожидание, что .dockerignore гарантированно защитит секрет после того, как он уже оказался в контексте: правильнее вообще не хранить секреты рядом с исходниками и использовать BuildKit secret mounts. Наконец, не оценивайте результат только по успешности сборки. Проверьте, что образ действительно не получает лишние исходники, а кэш не инвалидируется изменениями файлов, которые не нужны конкретному этапу. Хороший .dockerignore одновременно уменьшает контекст, делает COPY предсказуемым и не скрывает необходимые lock-файлы или конфигурацию сборки.

Как проверить, что ignore не ломает кэш и multi-stage сборку

После изменения .dockerignore сравните не только время передачи контекста, но и поведение кэша по этапам Dockerfile. Например, если package-lock.json случайно исключён, COPY package*.json перестанет работать; если, наоборот, огромный каталог с часто меняющимися артефактами остаётся в контексте и попадает в ранний COPY, кэш следующих RUN будет инвалидироваться чаще. В multi-stage сборке полезно отдельно проверить, какие файлы нужны builder-stage, а какие должны попадать только в финальный образ. Не пытайтесь решить это одним сверхшироким правилом с десятком исключений, если структура проекта позволяет точнее задавать COPY. Хороший тест — чистая сборка из CI-команды, затем изменение файла, который заведомо не должен влиять на build, и повторная сборка. Если кэш неожиданно сбрасывается, проверьте границы COPY и контекст. Если нужный файл исчезает, временно добавьте диагностическое правило ! для конкретного пути и отследите порядок совпадений. Так .dockerignore становится частью воспроизводимой сборки, а не случайным списком мусора.

Как проверить правила на реальном build context, а не на глаз

После редактирования .dockerignore полезно сделать контрольную сборку с подробным выводом и посмотреть размер отправляемого контекста. Если ожидаемый файл внезапно пропал, сначала сопоставьте его путь со всеми правилами сверху вниз, включая исключения через !: итог задаёт последнее совпавшее правило. Для монорепозитория отдельно проверьте, какой каталог передан последним аргументом docker build или docker buildx build — именно он является корнем контекста, и .dockerignore из другого каталога не исправит неверно выбранный context. Если используете несколько Dockerfile, Docker поддерживает Dockerfile-specific ignore-файлы рядом с ними; это позволяет не превращать общий .dockerignore в набор противоречивых правил для всех сборок. После исправления повторите build с тем же контекстом и убедитесь, что нужный COPY снова видит файл, а лишние каталоги не передаются builder. Так вы проверяете не только синтаксис, но и фактический результат фильтрации, что особенно важно при сложных **-шаблонах и последовательностях exclude/re-include.

Что учитывать

Перед выполнением Dockerfile клиент формирует build context и передаёт его builder. Если в корне контекста есть .dockerignore, совпавшие файлы и каталоги убираются до отправки. Это уменьшает объём передачи, ускоряет удалённые и BuildKit-сборки и снижает риск случайно включить .git, локальные кэши, логи или секреты. Важный практический вывод: строка COPY . не может вернуть то, что уже исключено из контекста. Если сборка пишет, что файл не найден, сначала проверьте не только путь в COPY, но и…

Источники и проверка

Фактическая часть сверена по первичным источникам (в т.ч. Build context — .dockerignore files). Пример и формулировки — редакция N1RO на 2026-09-22.