Ответ
Multi-stage сборка в Docker достигается за счет использования в одном Dockerfile нескольких инструкций FROM, каждая из которых начинает новый этап (stage). Это позволяет отделить среду сборки (со всеми компиляторами и зависимостями) от финального рантайм-образа.
Принцип работы:
- Первый этап (часто называемый
builder) основан на большом образе с инструментами разработки (например,golang:1.21,maven:3.8). Здесь выполняется компиляция, установка зависимостей и сборка артефактов. - Последующие этапы основаны на минимальных образах (например,
alpine:latest,scratch). С помощью инструкцииCOPY --from=<stage_name>в них копируются только необходимые артефакты (бинарники, библиотеки) из предыдущих этапов. - Промежуточные слои и инструменты сборки остаются в истории, но не попадают в финальный образ, что радикально уменьшает его размер и повышает безопасность (меньше attack surface).
Пример для Go-приложения:
# --- STAGE 1: Builder ---
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# Статическая линковка для работы в пустом образе 'scratch'
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /myapp .
# --- STAGE 2: Runtime ---
FROM scratch
# Копируем только скомпилированный бинарник из этапа 'builder'
COPY --from=builder /myapp /myapp
# Копируем SSL сертификаты, если приложение делает HTTPS-запросы
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
CMD ["/myapp"]
Преимущества:
- Размер: Финальный образ может весить мегабайты вместо гигабайт.
- Безопасность: В продакшене нет компилятора, исходного кода или пакетов для разработки.
- Чистота: Упрощается управление зависимостями, так как среда выполнения изолирована от среды сборки.