Ответ
Многоэтапная сборка (Multi-stage builds) — это функция Docker, позволяющая использовать несколько инструкций FROM в одном Dockerfile. Каждая инструкция FROM начинает новый этап сборки, и можно копировать артефакты (например, скомпилированные бинарники, зависимости) из одного этапа в другой. Основная цель — создать минимальный и безопасный итоговый образ, исключив из него инструменты сборки, промежуточные файлы и ненужные зависимости.
Типичная проблема, которую решает Multi-stage:
Без нее в финальном образе остаются компиляторы, заголовочные файлы, пакеты для разработки (например, gcc, python3-dev), которые нужны только для сборки приложения, но не для его запуска. Это увеличивает размер образа и поверхность для атак.
Пример Dockerfile для Go-приложения:
# ЭТАП 1: Сборка (Builder Stage)
# Используем полный образ с компилятором
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: Финальный образ (Runtime Stage)
# Используем минимальный образ без компилятора
FROM alpine:latest
RUN apk --no-cache add ca-certificates # Добавляем только необходимые для работы пакеты
WORKDIR /root/
COPY --from=builder /myapp . # Копируем ТОЛЬКО бинарник из этапа сборки
CMD ["./myapp"]
Пример для Python-приложения:
# Этап сборки зависимостей
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt # Устанавливаем зависимости в домашнюю директорию пользователя
# Финальный этап
FROM python:3.11-slim
WORKDIR /app
# Копируем только установленные пакеты из домашней директории пользователя этапа builder
COPY --from=builder /root/.local /root/.local
# Копируем исходный код приложения
COPY src/ .
# Убедимся, что скрипты могут найти пакеты из /root/.local
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "main.py"]
Ключевые преимущества:
- Значительное уменьшение размера образа: Финальный образ содержит только рантайм-зависимости и артефакты.
- Повышение безопасности: Уменьшается количество установленных пакетов и, следовательно, потенциальных уязвимостей.
- Улучшение структуры и читаемости: Весь процесс сборки и финальной упаковки описан в одном файле, что упрощает CI/CD.
Ответ 18+ 🔞
Давай разберём эту многоэтажную сборку, а то звучит как будто про небоскрёб речь, а на деле — просто хитрая жопа в Docker.
Вот смотри, раньше было как: пишешь Dockerfile, компилируешь в нём своё приложение, а в итоге получаешь образ, который весит овердохуища. Потому что внутри остаётся весь этот сброд: компиляторы, заголовочные файлы, тонны пакетов для разработки. А для запуска-то нужен только готовый бинарник! Это как если бы ты, чтобы съесть суп, тащил на кухню целую свинью, топор и дровосека. Ёперный театр!
Так вот, умные дядьки придумали Multi-stage builds. Суть проста до безобразия: ты разбиваешь сборку на этапы. На первом этапе — в грязном цеху — ты компилируешь, собираешь, паяешь своё приложение. А потом из этого бардака ты забираешь только готовый продукт (бинарник, зависимости) и переносишь его в чистую, стерильную комнату — второй этап. А весь строительный мусор остаётся в прошлом и в финальный образ не попадает. Гениально, ёпта!
Смотри на примере Go. Раньше бы пришлось тащить golang:1.21-alpine в продакшен. А теперь:
# ЭТАП 1: Грязный цех (Builder Stage)
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: Чистая комната (Runtime Stage)
FROM alpine:latest # Смотри какая крошка, а не образ!
RUN apk --no-cache add ca-certificates # Только самое необходимое
WORKDIR /root/
COPY --from=builder /myapp . # Вот магия! Крадём бинарник из первого этапа.
CMD ["./myapp"]
Видишь фокус? COPY --from=builder. Мы как воры в законе — зашли в первый контейнер, вынесли только ценности (/myapp), а весь инструмент (go, исходники) оставили там. Финальный образ — голый alpine с одним бинарником. Разница в размерах — ни хуя себе!
С Python та же история, только там не бинарник, а пакеты из pip:
# Этап 1: Установщик
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Этап 2: Бегун
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local # Перетащили только установленные либы
COPY src/ .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "main.py"]
Итоговые плюсы, от которых сам от себя охуеешь:
- Размер образа. Из жирного хуя в пальто он превращается в субтильного мальчика. Скачивать и разворачивать быстрее.
- Безопасность. Меньше пакетов — меньше дыр. Нет в продакшене
gcc— нечего ему там делать, пидарас шерстяной. - Читаемость. Всё в одном файле. Видно, где собираем, где запускаем. Не нужно городить три отдельных скрипта.
Короче, если не используешь multi-stage — ты распиздяй. Это теперь must have для любого серьёзного Dockerfile. Всё, что нужно для сборки, остаётся за бортом, а в плавание выходит только готовый корабль. Ебушки-воробушки, как же просто и эффективно!
Видео-ответы
▶
▶
▶
▶
▶