Ответ
Несколько инструкций FROM в одном Dockerfile используются для создания многоэтапных сборок (multi-stage builds). Я активно применяю этот подход, чтобы создавать минимальные и безопасные production-образы.
Проблема, которую это решает: При обычной сборке в итоговый образ попадают все инструменты, необходимые для компиляции (компиляторы, заголовочные файлы, менеджеры пакетов), что раздувает образ и увеличивает поверхность для атак.
Как работает многоэтапная сборка:
- Первый этап (
FROM ... AS builder) содержит полный набор инструментов для сборки приложения. - Второй (и последующие) этап начинается с чистого базового образа (например,
alpineилиdistroless). - С помощью
COPY --from=builderя копирую только готовый артефакт (бинарник, jar-файл) из этапа сборки в финальный образ. Все промежуточные слои и инструменты сборки остаются за его пределами.
Пример Dockerfile для Go-приложения:
# --- ЭТАП 1: Сборка (будет отброшен) ---
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /myapp ./cmd/app
# --- ЭТАП 2: Финальный образ ---
FROM alpine:latest AS production
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/
# Копируем ТОЛЬКО бинарник из этапа 'builder'
COPY --from=builder /myapp .
# Устанавливаем непривилегированного пользователя для безопасности
RUN adduser -D appuser && chown appuser:appuser /root/myapp
USER appuser
CMD ["./myapp"]
Результат: Итоговый образ содержит только минимальную ОС Alpine и статически слинкованный бинарник myapp. Его размер может быть в 10 и более раз меньше, чем если бы сборка происходила в одном этапе с использованием golang:1.21-alpine как базового образа. Это ускоряет деплой, снижает затраты на хранение и повышает безопасность.