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

Что такое Multi-stage builds в Docker?

1.8 Middle🔥 182 комментариев
#MLOps и инфраструктура

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

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

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

Multi-stage builds в Docker

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

Проблема: однозвёздный build

# Плохо: всё в одном образе
FROM python:3.11

WORKDIR /app
COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

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

# Размер: ~800MB
# В образе: Python, pip, build tools, source код — всё

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

# Stage 1: Builder
FROM python:3.11 as builder

WORKDIR /app
COPY requirements.txt .

RUN pip install --user --no-cache-dir -r requirements.txt

# Stage 2: Runtime
FROM python:3.11-slim

WORKDIR /app

# Копируем только необходимые файлы из builder
COPY --from=builder /root/.local /root/.local
COPY . .

ENV PATH=/root/.local/bin:$PATH

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

# Размер: ~200MB (уменьшился в 4 раза!)

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

Фаза 1 (Builder)
┌─────────────────────────────────┐
│ FROM python:3.11                │
│ INSTALL pip, build tools        │  ← всё это
│ COPY requirements.txt           │
│ RUN pip install ...             │
│ COPY source code                │     временно
└─────────────────────────────────┘
         ↓ (удаляется)

Фаза 2 (Runtime)
┌─────────────────────────────────┐
│ FROM python:3.11-slim           │
│ COPY --from=builder /root/.local │  ← копируем только
│ COPY source code                │     установленные
│ CMD ["python", "main.py"]       │     зависимости
└─────────────────────────────────┘
         ↓
    Финальный образ (~200MB)

Практический пример: Go приложение

# Stage 1: Compilation
FROM golang:1.21 as builder

WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 go build -o app main.go

# Stage 2: Runtime
FROM alpine:latest

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

CMD ["./app"]

# Builder: ~800MB (golang компилятор, исходный код)
# Runtime: ~5MB (только бинарник + alpine)

Практический пример: Node.js

# Stage 1: Dependencies
FROM node:18 as dependencies

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

# Stage 2: Build (если есть TypeScript/bundling)
FROM node:18 as builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 3: Runtime
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 .

EXPOSE 3000
CMD ["node", "dist/index.js"]

# dependencies: ~400MB
# builder: ~900MB
# runtime: ~150MB (только production deps + built code)

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

1. Размер образа: ↓ 50-80% (удаляются build tools)
2. Скорость pull: быстрее скачивается
3. Безопасность: меньше потенциальных уязвимостей
4. Чистота: builder инструменты не в production

Named stages

FROM node:18 as dev-stage
RUN npm install -g nodemon

FROM node:18 as test-stage
COPY --from=dev-stage /app /app
RUN npm run test

FROM node:18-alpine as prod
COPY --from=test-stage /app/dist ./dist
CMD ["node", "dist/index.js"]

# Строим конкретный stage:
# docker build --target prod -t myapp:latest .

Условное копирование (Docker BuildKit)

# Требует: DOCKER_BUILDKIT=1
FROM golang:1.21 as builder

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go build -o app main.go

# Кэшируется между builds, экономит время

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

# Без multi-stage
$ docker build -t app:v1 .
$ docker images app:v1
# app:v1  1.2GB

# С multi-stage
$ docker build --target prod -t app:v2 .
$ docker images app:v2
# app:v2  250MB  (в 5 раз меньше!)

Best Practices

# 1. Используй Alpine для runtime (если возможно)
FROM python:3.11-alpine

# 2. Раздели builder и runtime
FROM golang:1.21 as builder
# ... compile ...
FROM alpine:latest
COPY --from=builder /app/binary .

# 3. Минимизируй слои в runtime
FROM alpine
RUN apk add --no-cache curl ca-certificates
COPY --from=builder /app/binary .

# 4. Используй BuildKit для кэширования
export DOCKER_BUILDKIT=1
docker build .

Резюме

Multi-stage builds:

  • Уменьшают размер образа на 50-90%
  • Разделяют build и runtime слои
  • Улучшают безопасность (меньше инструментов в production)
  • Синтаксис: COPY --from=stage_name /path .
  • Essential для production Docker образов