Гайды

Многостадийные Docker-образы (multi-stage)

Несколько FROM, Python и Node примеры, кэш BuildKit, distroless и чек-лист перед релизом.

~8 мин чтения

Многостадийные Docker-образы (multi-stage)

Multi-stage build — несколько директив FROM в одном Dockerfile: на промежуточных стадиях ставят компиляторы и dev-зависимости, в финальный образ копируют только артефакты. Меньше размер, меньше CVE, быстрее pull. База — Docker: контейнеризация.

В начале Dockerfile имеет смысл указать # syntax=docker/dockerfile:1 — включает актуальные фичи BuildKit на стороне билдера.


1. Пример Python

dockerfile
FROM python:3.12-slim AS builder
WORKDIR /build
RUN pip install poetry
COPY pyproject.toml poetry.lock ./
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt

FROM python:3.12-slim AS runtime
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
COPY --from=builder /wheels /wheels
RUN pip install --no-cache /wheels/*
COPY . .
USER nobody
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Стадия builder не попадает в финальный образ (кроме явно скопированного).


2. Node (сборка фронта)

dockerfile
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine AS runtime
COPY --from=build /app/dist /usr/share/nginx/html

3. Кэш BuildKit

--mount=type=cache для npm/pip ускоряет CI при включённом BuildKit (DOCKER_BUILDKIT=1).

COPY --link (BuildKit) позволяет параллелить слои и уменьшает инвалидацию кэша при изменении порядка COPY — удобно в больших репозиториях.

Сборка только одной стадии для CI-линта: docker build --target builder . — не тратите время на финальный runtime-слой.


4. SBOM и сканирование

После сборки прогоняте docker scout / Trivy / Grype по финальному образу; multi-stage уменьшает поверхность. Подпись образа (cosign) — для supply chain.


5. Платформы и воспроизводимость

ARG для версий языка и зависимостей; --platform в CI при кросс-сборке (arm64/amd64). Для одинакового результата на разных машинах комбинируйте digest-пин базового образа и зафиксированный lockfile зависимостей.


6. distroless / scratch

Для Go-бинарников финальная стадия gcr.io/distroless/static или scratch + копирование статического ELF — минимальный attack surface.


7. Чек-лист

  • Имена стадий (AS builder) для читаемости.
  • Не копировать .git и тестовые фикстуры в runtime.
  • Проверять размер и docker history перед релизом.
  • .dockerignore, чтобы не тащить node_modules и артефакты в контекст.
  • Пин базовых образов по digest при жёсткой воспроизводимости.

Дальше: Compose · тег Docker