3.1.2 · блок 3
Dockerfile: сборка образа и multi-stage
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 build → docker 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-зависимостей — покажите разницу в размере образа.