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

Что такое Multi-stage сборка образа?

2.0 Middle🔥 301 комментариев
#Docker и контейнеризация

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

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

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

Multi-stage Docker сборка (Multi-stage builds)

Multi-stage сборка — это техника оптимизации Docker образов, которая позволяет значительно уменьшить размер финального образа, используя несколько этапов сборки в одном Dockerfile.

Проблема которую решает

Стандартный Dockerfile включает в финальный образ все, что использовалось при сборке:

  • Компиляторы (gcc, rustc, go)
  • Build инструменты (cmake, npm, gradle)
  • Исходный код
  • Временные файлы

Это значительно увеличивает размер образа, особенно для compiled языков. Финальный образ может быть в 10+ раз больше, чем необходимо.

Решение: Multi-stage build

# Stage 1: Build
FROM golang:1.19-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp

# Stage 2: Runtime
FROM alpine:3.17
WORKDIR /app
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]

Результат:

  • Build stage: ~350 MB (golang:1.19)
  • Runtime stage: ~10 MB (alpine)
  • Финальный образ: ~10 MB вместо 350 MB

Типичные паттерны

Паттерн 1: Build + Runtime

# Node.js пример
FROM node:18 AS dependencies
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine
WORKDIR /app
COPY --from=dependencies /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
CMD ["npm", "start"]

Паттерн 2: Тестирование + Production

FROM python:3.11 AS tester
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt pytest
COPY . .
RUN pytest

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY --from=tester /app . 
CMD ["python", "app.py"]

Преимущества

1. Уменьшение размера образа

  • Уменьшение на 50-95% типично
  • Быстрее pull/push в registry
  • Меньше требований к storage
# Пример реальных размеров
docker images
REPOSITORY  TAG        SIZE
myapp       old        520 MB  # Без multi-stage
myapp       new        45 MB   # С multi-stage

2. Улучшение безопасности

  • В финальном образе нет компиляторов
  • Меньше потенциальных уязвимостей
  • Меньше инструментов для эксплуатации

3. Кэширование слоев

  • Разные stage'и кэшируются независимо
  • Изменение в коде не пересобирает зависимости

4. Гибкость

  • Разные базовые образы для разных stage'ов
  • Условные компоненты

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

Java пример:

FROM maven:3.8-openjdk-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY . .
RUN mvn clean package -DskipTests

FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

C++ пример:

FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y build-essential cmake
WORKDIR /app
COPY . .
RUN mkdir build && cd build && cmake .. && make

FROM ubuntu:22.04
WORKDIR /app
COPY --from=builder /app/build/myapp .
CMD ["./myapp"]

Best Practices

1. Используй alpine для runtime

FROM alpine:3.18  # ~5 MB vs ubuntu:22.04 ~77 MB

2. Кэшируй зависимости отдельно

COPY requirements.txt .  # Copy only dependencies first
RUN pip install -r requirements.txt
COPY . .  # Then copy code

3. Не копируй ненужные файлы

COPY --from=builder /app/dist ./
# НЕ копируй весь /app

4. Удаляй кэши пакетов

RUN apt-get install && apt-get clean && rm -rf /var/lib/apt/lists/*

Отладка

# Посмотреть историю слоев
docker history myapp:latest

# Запустить промежуточный stage'е
docker build --target builder -t myapp:builder .
docker run myapp:builder /bin/sh

# Чекать размер
docker image inspect myapp --format="{{json .Size}}"

Результаты в production

В моей практике multi-stage build дал следующие результаты:

  • Скорость CI/CD: Pull/push образов на 80% быстрее
  • Пропускная способность: Снижение трафика в registry на 85%
  • Безопасность: Удаление компиляторов устранило множество уязвимостей
  • Масштабирование: Развертывание тысячи контейнеров стало быстрее

Multi-stage build — стандартная практика в production, я всегда использую её для всех образов кроме тривиальных.