Что такое Multi-stage сборка образа?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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, я всегда использую её для всех образов кроме тривиальных.