03 · Платформа: DevOps, k8s, сеть, хранилище3.1 · Контейнеризация3.1.2средний

Dockerfile: сборка образа и multi-stage

Зачем это нужно

docker run из чужого образа — это потребление. В MLOps вы создаёте образы: inference API, worker обучения, утилита валидации данных. Dockerfile — декларативный рецепт сборки, который лежит в Git рядом с кодом. Хороший Dockerfile ускоряет CI, уменьшает образ и снижает риск «случайно затащили секрет или dev-зависимость в прод».

Плохой Dockerfile — частая причина долгих пайплайнов и уязвимостей: образ на 3 ГБ с Jupyter и gcc в продакшене inference.

Основные идеи

Базовые инструкции. Типичная последовательность:

  • FROM — базовый образ (например, python:3.11-slim).

  • WORKDIR — рабочая директория внутри контейнера.

  • COPY / ADD — копирование файлов с хоста (предпочитайте COPY).

  • RUN — команда при сборке (установка пакетов, компиляция).

  • ENV — переменные окружения.

  • EXPOSE — документирует порт (не открывает его сам по себе).

  • CMD / ENTRYPOINT — команда при запуске контейнера.

Порядок слоёв = скорость CI. Сначала файлы, которые меняются редко:

FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Multi-stage build. Для C++ или сборки wheel иногда нужны компилятор и dev-заголовки — в runtime они не нужны. Multi-stage: первый stage собирает бинарник, второй копирует только результат:

` FROM python:3.11 AS builder WORKDIR /app COPY requirements.txt . RUN pip wheel --no-cache-dir -r requirements.txt -w /wheels

FROM python:3.11-slim WORKDIR /app COPY --from=builder /wheels /wheels RUN pip install --no-cache-dir /wheels/* COPY . . CMD ["python", "-m", "app"] `

Итоговый образ меньше и без gcc, build-essential.

.dockerignore. Как .gitignore: исключает .git, __pycache__, .venv, большие датасеты. Иначе они попадут в контекст сборки и замедлят docker build.

Безопасность и практика. Не запускайте приложение от root без необходимости; не копируйте секреты через ARG/ENV в образ; используйте конкретные теги базового образа (3.11-slim, не latest). Для ML: модель можно копировать в образ (малые модели) или монтировать том / качать из S3 при старте (крупные модели).

Как это выглядит на практике

Задача: упаковать сервис классификации с FastAPI.

  1. Создайте requirements.txt с fastapi, uvicorn, scikit-learn.

  2. Напишите Dockerfile по шаблону выше.

  3. Соберите: docker build -t spam-classifier:1.0.0 .

  4. Проверьте размер: docker images spam-classifier

  5. Запустите с пробросом порта и проверьте /predict.

В Jenkins (модуль 3.2) тот же Dockerfile выполнится на agent: docker builddocker push registry.company/spam-classifier:${BUILD_NUMBER}. Изменение одной строки в app.py пересоберёт только последние слои — пайплайн станет быстрее.

Если inference на C++ (libtorch), первый stage компилирует .so, второй содержит только runtime-библиотеки — образ для GPU-сервера не раздувается инструментами сборки.

Что сделать после занятия

  • Напишите Dockerfile для учебного Python-сервиса с healthcheck-эндпоинтом.

  • Добавьте .dockerignore и сравните время сборки до и после (с большой папкой data/ в проекте).

  • Перепишите Dockerfile в multi-stage вариант, если у вас есть этап установки dev-зависимостей — покажите разницу в размере образа.

Официальные материалы