Как использовать multi-stage Dockerfile?

«Как использовать multi-stage Dockerfile?» — вопрос из категории Devops, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Multi-stage Dockerfile — это мощный инструмент для создания оптимизированных и безопасных Docker-образов. Он позволяет разделить процесс сборки приложения на несколько этапов, используя промежуточные образы для выполнения задач (например, компиляции, установки зависимостей), а затем копируя только необходимые артефакты в финальный, минимальный образ.

Почему это важно?

  • Уменьшение размера образа: Финальный образ не содержит инструментов сборки, временных файлов и ненужных зависимостей.
  • Улучшение безопасности: Меньше компонентов в финальном образе означает меньшую поверхность атаки.
  • Ускорение сборки: Кэширование слоев на разных этапах может ускорить повторные сборки.

Пример для Python-приложения:

Предположим, у нас есть requirements.txt и app.py.

# --- Этап 1: Сборка и установка зависимостей (builder) ---
# Используем более полный образ для установки зависимостей
FROM python:3.9-slim as builder

# Устанавливаем рабочую директорию
WORKDIR /app

# Копируем файл зависимостей
COPY requirements.txt .

# Устанавливаем зависимости в пользовательскую директорию
# Это позволяет легко скопировать их на следующем этапе
RUN pip install --user -r requirements.txt

# --- Этап 2: Финальный образ (production) ---
# Используем минимальный образ для продакшена
FROM python:3.9-slim

# Устанавливаем рабочую директорию
WORKDIR /app

# Копируем установленные пакеты из этапа 'builder'
# /root/.local/lib/python3.9/site-packages - стандартный путь для --user установки в slim-образах
COPY --from=builder /root/.local /root/.local

# Копируем исходный код приложения
COPY . .

# Добавляем пользовательскую директорию с пакетами в PATH
# Это необходимо, чтобы Python мог найти установленные зависимости
ENV PATH="/root/.local/bin:$PATH"

# Команда для запуска приложения
CMD ["python", "app.py"]

Пояснения к примеру:

  1. FROM python:3.9-slim as builder: Первый этап, названный builder, использует python:3.9-slim для установки зависимостей.
  2. RUN pip install --user -r requirements.txt: Зависимости устанавливаются в пользовательскую директорию (/root/.local), чтобы их было легко изолировать и скопировать.
  3. FROM python:3.9-slim: Второй этап начинается с чистого python:3.9-slim образа, который будет финальным.
  4. COPY --from=builder /root/.local /root/.local: Копируем только установленные зависимости из builder этапа в финальный образ.
  5. ENV PATH="/root/.local/bin:$PATH": Обновляем переменную окружения PATH, чтобы исполняемые файлы из установленных пакетов были доступны.

Этот подход значительно уменьшает размер итогового образа, так как он не содержит pip и других инструментов, использованных только на этапе сборки.