FROM <base> AS build, FROM <base> AS runtime и т.д. Каждый такой этап создаёт свой промежуточный образ, из которого в финальный этап мы с помощью COPY --from=... забираем только нужные файлы (бинарники, статические ресурсы, конфигурацию). В результате сборка и запуск чётко разделены, а итоговый прод-образ остаётся «тонким» и простым.Основные причины использовать multi-stage build:
golang, node, maven), а запускать на лёгкой (alpine, distroless, минимальный runtime-образ).Ключевая идея: сборочный этап может содержать всё тяжёлое и промежуточное, а в финальный этап мы «пробрасываем» только итог артефакта, не таща за собой сборочную среду.
Ниже пример для Go-сервиса: сначала собираем бинарник во временном образе с полным SDK, затем упаковываем только исполняемый файл в минимальный runtime-образ.
В этом примере в прод уезжает образ на базе alpine только с бинарником и минимальным набором библиотек. Образ golang:1.21 с компилятором и инструментами разработки используется только на этапе сборки и не попадает в реестр как итоговый прод-образ.
Multi-stage build также удобно применять для фронтенда: мы собираем статику в одном контейнере, а отдаём её через лёгкий веб-сервер в другом этапе.
Такой подход позволяет держать Dockerfile компактным, собирать образы быстрее и гарантировать, что в прод-окружении нет ничего лишнего, кроме того, что нужно приложению для работы.
Отметьте свой прогресс