Dockerfile
1Dockerfile: создаём свой образ2Слои и кэш: быстрая сборка образов3Multi-stage builds: маленькие продакшн-образы← вы здесь
Урок 3~9 минут

Multi-stage builds: маленькие продакшн-образы

Multi-stage build — одна из самых мощных возможностей Docker. Позволяет собирать приложение в одном образе и запускать в другом, намного меньшем.

Проблема

dockerfile
FROM golang:1.22        # ~800MB с инструментами сборки
 
WORKDIR /app
COPY . .
RUN go build -o server .
 
CMD ["./server"]

Итог: образ весит ~800MB. А в нём нужен только бинарник server (~10MB).

Решение: multi-stage

dockerfile
# Стадия 1: сборка
FROM golang:1.22 AS builder
 
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
 
COPY . .
RUN CGO_ENABLED=0 go build -o server .
 
# Стадия 2: финальный образ
FROM scratch
 
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
 
EXPOSE 8080
CMD ["/server"]

Итог: образ ~15MB. Инструменты сборки остались только в промежуточном образе.

Попробуй в симуляции

Node.js: dev vs production

dockerfile
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
 
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
 
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
 
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json .
 
CMD ["node", "dist/index.js"]

devDependencies (TypeScript, Jest, ESLint) в финальный образ не попадают.

Именованные стадии

dockerfile
FROM node:20 AS build-stage
# ...
 
FROM nginx:alpine AS prod-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html

Копировать можно из любой стадии: --from=build-stage или --from=0 (по индексу).

Целевая стадия

bash
# Собрать только до конкретной стадии (полезно для тестирования)
docker build --target builder -t app:builder .
docker build --target runner -t app:latest .

Размеры сравним

ОбразРазмер
golang:1.22 (без multi-stage)~850MB
golang:1.22-alpine~330MB
FROM scratch (multi-stage)~10-20MB
node:20 (без multi-stage)~1.1GB
node:20-alpine (prod deps)~150MB
nginx + static (SPA)~25MB

Alpine vs slim vs scratch

  • ubuntu:22.04 — полноценный ubuntu, ~80MB
  • debian:bookworm-slim — минимальный debian, ~75MB
  • alpine:3.19 — минимальный linux, ~7MB, musl libc
  • scratch — пустой, 0MB, только статически скомпилированные бинарники

В следующем модуле — Docker Compose для многоконтейнерных приложений.

Multi-stage: собираем в тяжёлом образе с инструментами, копируем результат в лёгкий. Go бинарник 50MB → образ 15MB.
Multi-stage build: размер образа
ОБРАЗ (один Dockerfile)
golang:1.22 base — 350 MB
Build tools (gcc, etc.) — 280 MB
Go modules (go mod download) — 120 MB
Source code — 2 MB
go build -o server — 15 MB
~767 MB — go toolchain в продакшне
⚠️ Go компилятор, source code, все build tools — всё попало в продакшн образ
# Dockerfile
FROM golang:1.22 AS builder
WORKDIR /app && COPY . . && go build -o server .
FROM scratch
COPY --from=builder /app/server /server
CMD ["/server"]
🎯
Миссия 1 из 3
Зачем нужен multi-stage build?