← Назад к вопросам

Где полезна multistage сборка Docker?

2.0 Middle🔥 171 комментариев
#DevOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Многоступенчатая (Multistage) сборка Docker

Multistage сборка — это техника оптимизации Docker образов, позволяющая значительно уменьшить их размер. Она особенно полезна для Python, Go, Java и других языков компиляции.

Проблема без Multistage

Обычный Dockerfile содержит всё в одном образе:

# ❌ Неправильно — всё в одном образе
FROM python:3.11

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Установим build tools для сборки зависимостей
RUN apt-get update && apt-get install -y \
    build-essential \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

COPY . .
CMD ["python", "app.py"]

Проблемы:

  • Build tools (gcc, make, postgresql-client) остаются в образе
  • Кэш pip может быть большим
  • Финальный образ весит 800 МБ - 1 ГБ
  • Медленная загрузка и развёртывание

Решение: Multistage сборка

Идея: Использовать один образ для сборки, другой для выполнения.

# ✅ Правильно — multistage сборка

# STAGE 1: Builder
FROM python:3.11 as builder

WORKDIR /app
COPY requirements.txt .

# Установим зависимости в виртуальное окружение
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --no-cache-dir -r requirements.txt

# STAGE 2: Runtime
FROM python:3.11-slim  # Меньше base image

WORKDIR /app

# Копируем только виртуальное окружение из builder
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# Копируем только исходный код (без dev зависимостей)
COPY . .

CMD ["python", "app.py"]

Результат:

  • Builder образ (временный, не в финал): 1.2 ГБ
  • Runtime образ (финальный): 200-400 МБ ✓

Как работает Multistage

# STAGE 1: builder
FROM golang:1.21 as builder
WORKDIR /app
COPY . .
RUN go build -o app .  # Компилируем

# STAGE 2: runtime
FROM scratch  # Ультра-минималистичный образ (0 МБ база)
COPY --from=builder /app/app /app
CMD ["/app"]

При сборке:

  1. Создаётся временный образ builder
  2. Выполняется вся работа (сборка, установка, компиляция)
  3. Создаётся финальный образ
  4. Копируются только нужные артефакты из builder
  5. Временный образ удаляется

Практические примеры

1. Python приложение с зависимостями

FROM python:3.11 as builder

WORKDIR /tmp
COPY requirements.txt .

# Используем venv для лучшей совместимости
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --no-cache-dir -r requirements.txt

# Удалим лишнее из venv
RUN find /opt/venv -type d -name __pycache__ -exec rm -rf {} +
RUN find /opt/venv -type f -name "*.pyc" -delete

# Runtime stage
FROM python:3.11-slim

WORKDIR /app
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY . .

EXPOSE 8000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]

2. Node.js приложение

FROM node:20 as builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# Runtime
FROM node:20-alpine  # Меньше база

WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .

EXPOSE 3000
CMD ["node", "server.js"]

3. Компиляция Go кода

FROM golang:1.21 as builder

WORKDIR /build
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

# Минималистичный runtime
FROM scratch
COPY --from=builder /build/app /app
EXPOSE 8000
CMD ["/app"]

4. Java приложение

FROM maven:3.9 as builder

WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src src
RUN mvn clean package -DskipTests

# Runtime
FROM eclipse-temurin:21-jdk-alpine
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
CMD ["java", "-jar", "app.jar"]

Сравнение размеров

# Одноступенчатый Dockerfile для Flask приложения
$ docker build -f Dockerfile.single -t flask:single .
$ docker image ls flask:single
FLASK    SINGLE   123abc123   456 MB  # ❌ Большой

# Multistage Dockerfile
$ docker build -f Dockerfile.multi -t flask:multi .
$ docker image ls flask:multi
FLASK    MULTI    789def789   125 MB  # ✅ Меньше на 73%

Оптимизация размера дальше

# Используйте alpine версии (очень маленькие)
FROM python:3.11-alpine as builder

# Очищайте кэш и лишние файлы
RUN pip install --no-cache-dir ...
RUN rm -rf /var/cache/apt/*

# Удаляйте документацию
RUN find /opt/venv -name "*.dist-info" -type d -exec rm -rf {} +

Продвинутые техники

Named stages для сложных проектов

FROM python:3.11 as base
RUN apt-get update && apt-get install -y build-essential

FROM base as builder
RUN pip install -r requirements-dev.txt

FROM base as runtime
RUN pip install -r requirements.txt
COPY --from=builder /opt/venv /opt/venv

FROM runtime as production
# Дополнительная оптимизация для prod
RUN strip /opt/venv/lib/python3.11/*.so

Условная сборка

ARG BUILD_ENV=production

FROM python:3.11 as builder-dev
COPY requirements-dev.txt .
RUN pip install -r requirements-dev.txt

FROM python:3.11 as builder-prod
COPY requirements.txt .
RUN pip install -r requirements.txt

FROM python:3.11-slim as runtime
COPY --from=builder-${BUILD_ENV} /opt/venv /opt/venv

Использование: docker build --build-arg BUILD_ENV=dev .

Когда использовать Multistage

Используйте когда:

  • Финальное приложение меньше, чем сборочные артефакты
  • Есть build tools, которые не нужны в runtime
  • Нужно минимизировать размер образа
  • Применяете в микросервисах и Kubernetes

Не нужно если:

  • Финальный образ всё равно будет большой
  • Используется single-purpose минималистичный образ

Практические советы

  1. Используйте -slim и -alpine варианты
  2. Кэшируйте слои правильно — меняющийся код в конце
  3. Удаляйте временные файлы
  4. Не копируйте лишнее
  5. Используйте .dockerignore

Multistage сборка — это стандарт современного Docker контейнеризма и должна использоваться во всех production приложениях.