Раздутый Docker-образ — это медленные сборки, долгие выкладки и лишняя площадь для атак. При этом ужать образ в несколько раз можно базовыми приёмами, без экзотики. Разберём, что даёт основной выигрыш в 2025 году и почему порядок строк в Dockerfile важнее, чем кажется.

Многоэтапная сборка: главный рычаг

Самый мощный приём — многоэтапная сборка (multi-stage build). Идея в том, чтобы разделить сборку и запуск. На одном этапе вы собираете приложение со всеми компиляторами, сборщиками и инструментами отладки. На финальный этап копируете только то, что нужно для запуска, и берёте за основу более лёгкий образ.

  • Используйте полноценный образ для сборки и тестов.
  • Для продакшена берите слим-образ только с рантаймом.
  • В финальный образ переносите лишь готовые артефакты, а не весь хлам сборки.

Результат — образ без компиляторов и dev-зависимостей, который может быть в разы меньше и имеет меньшую площадь атаки.

Порядок строк решает судьбу кэша

Docker кэширует слои сверху вниз и сбрасывает кэш с того места, где что-то изменилось. Отсюда правило: располагайте инструкции от самых редко меняющихся к самым частым.

  1. Сначала установка зависимостей — она меняется реже всего.
  2. Потом копирование кода приложения — оно меняется чаще всего.
  3. В конце настройка рантайма.

Если скопировать весь код до установки зависимостей, любая правка строки кода будет сбрасывать кэш зависимостей и заставлять ставить их заново. Правильный порядок экономит минуты на каждой сборке.

Кэш-маунты: ускорение без раздувания слоёв

В BuildKit есть кэш-маунты, которые кэшируют отдельные операции, не записывая их в слои образа. Например, кэш npm или apt живёт между сборками, но не утяжеляет итоговый образ. В типичном Node.js-приложении кэширование сокращает время сборки до 70%. Кэш-маунты и параллельная сборка требуют включённого BuildKit — это Docker версии 23.0 и выше или переменная DOCKER_BUILDKIT равная единице.