Делал ли multi-stage Docker файлы
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Multi-stage Docker файлы (мой опыт)
Да, активно использую multi-stage Dockerfile в production проектах. Это один из важных паттернов для оптимизации размера образов и времени сборки.
Что такое multi-stage
Это техника, где в одном Dockerfile используется несколько FROM инструкций. Каждый "stage" может копировать файлы из предыдущих stage, но финальный образ содержит только то, что нужно для production.
Проблема, которую решает
Обычный Dockerfile содержит всё — зависимости для сборки, инструменты разработки, всё это увеличивает размер образа:
# ❌ Без multi-stage: 900 МБ
FROM python:3.11
RUN apt-get update && apt-get install build-essential
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
В production нам не нужны компилятор и инструменты сборки. С multi-stage оставляю только нужное.
Пример 1: Python приложение
# Multi-stage Dockerfile
FROM python:3.11 as builder
# Stage 1: сборка
WORKDIR /build
RUN apt-get update && apt-get install -y build-essential
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 2: production
FROM python:3.11-slim
WORKDIR /app
# Копирую только установленные пакеты из builder
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
Результат:
- Builder stage: 900 МБ (выбрасывается)
- Final image: 150 МБ (то что остаётся)
- Экономия: 750 МБ!
Пример 2: Node.js + Python (микросервис)
Использовал такой паттерн для сервиса, где фронтенд собирается Node, но запускается Python беком:
# Stage 1: сборка фронтенда
FROM node:18 as frontend-builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: сборка Python приложения
FROM python:3.11 as backend-builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 3: финальный image
FROM python:3.11-slim
WORKDIR /app
# Копирую собранный фронтенд
COPY --from=frontend-builder /app/dist ./static
# Копирую Python зависимости
COPY --from=backend-builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app.wsgi"]
Пример 3: Django приложение с collectstatic
Это реальный случай из моего опыта:
# Stage 1: сборка
FROM python:3.11 as builder
WORKDIR /build
RUN apt-get update && apt-get install -y \\
build-essential \\
postgresql-client
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 2: production
FROM python:3.11-slim
WORKDIR /app
# Зависимости для runtime (например, postgresql-client)
RUN apt-get update && apt-get install -y \\
postgresql-client \\
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
# Собираю статику
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "--workers", "4", "config.wsgi:application"]
Практические советы
1. Используй slim образы для финального stage
# ✓ Хорошо: 150 МБ
FROM python:3.11-slim
# ✗ Плохо: 900 МБ
FROM python:3.11
2. Кешируй слои
# ✓ requirements сначала (меняется редко)
COPY requirements.txt .
RUN pip install --user -r requirements.txt
COPY . . # Код меняется часто
# ✗ Плохо: кеш сбросится при изменении кода
COPY . .
RUN pip install --user -r requirements.txt
3. Минимизируй размер
# ✓ Удаляй кеш пакетов
RUN pip install --no-cache-dir -r requirements.txt
# ✓ Очищай apt кеш
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# ✗ Плохо: оставляешь мусор
RUN apt-get install curl
Команды для проверки
# Размер образа
docker images | grep myapp
# myapp latest a1b2c3d4 15 hours ago 150MB
# История слоёв
docker history myapp:latest
# Размер каждого слоя
docker inspect myapp:latest | grep Size
Когда использую multi-stage
✓ Production приложения — критична минимизация размера ✓ Микросервисы — экономия место на реестре образов ✓ CI/CD пайплайны — быстрая загрузка и развертывание ✓ Сложная сборка — несколько языков (Node + Python)
Когда не нужен
✗ Локальная разработка (размер не критичен) ✗ Очень простые приложения (нет смысла усложнять)
Реальный выигрыш в проектах
В моём последнем проекте (Django + React):
- Было: 950 МБ (всё в одном образе)
- Стало: 180 МБ (multi-stage)
- Экономия: 80% меньше трафика на реестр
- Развертывание ускорилось в 5 раз (меньше скачивать)