Что такое мультистейджинг (multi-stage builds) в Docker?

«Что такое мультистейджинг (multi-stage builds) в Docker?» — вопрос из категории Docker, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Мультистейджинг (Multi-stage builds) — это функция Dockerfile, позволяющая использовать несколько промежуточных образов (FROM) в одном Dockerfile для разделения этапов сборки и финальной доставки. Ключевая цель — создание минимальных, безопасных и эффективных production-образов, из которых исключены все инструменты сборки, исходный код и промежуточные артефакты.

Проблема, которую решает мультистейджинг: Без него итоговый образ включает в себя:

  • Компиляторы (gcc, JDK)
  • Менеджеры пакетов (npm, pip) со всеми dev-зависимостями
  • Исходный код
  • Артефакты промежуточных шагов Это увеличивает размер образа, поверхность для атак и время деплоя.

Пример для Go-приложения:

# --- STAGE 1: Builder ---
# Используем полный образ с компилятором
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./ 
RUN go mod download  # Кэширование зависимостей
COPY . .
# Статическая компиляция (не зависит от glibc)
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /myapp .

# --- STAGE 2: Runtime ---
# Используем минимальный runtime-образ
FROM scratch AS runtime
# Копируем ТОЛЬКО скомпилированный бинарник из стейджа 'builder'
COPY --from=builder /myapp /myapp
# Копируем SSL-сертификаты (необходимы для TLS-соединений)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Пользователь без привилегий для безопасности
USER 1000:1000
ENTRYPOINT ["/myapp"]

Преимущества с точки зрения DevOps:

  1. Безопасность:
    • Минимальная поверхность для атак (нет shell, пакетного менеджера).
    • Запуск от непривилегированного пользователя (USER 1000).
    • Использование scratch или distroless образов.
  2. Эффективность:
    • Размер финального образа может сократиться в 10-20 раз (с ~1GB до ~50MB).
    • Ускорение деплоя и pull/push операций в registry.
    • Лучшее использование кэша слоев Docker.
  3. Совместимость: Статически скомпилированные бинарные файлы (как в примере с Go) гарантированно работают в любом окружении, совместимом с целевой ОС.

Практика для CI/CD: В пайплайне сборки можно использовать отдельные стейджи для:

  • Тестирования: Стейдж builder используется для запуска unit-тестов и линтеров.
  • Сканирования уязвимостей: Анализируется стейдж builder на наличие уязвимостей в dev-зависимостях.
  • Production: В registry и на кластер подается только финальный стейдж runtime.

Итог: Мультистейджинг — это обязательная best practice для создания production-образов, напрямую влияющая на безопасность, стоимость хранения/передачи и скорость развертывания.