Введение
Экспортировать зависимости python в докер — задача, кажущаяся тривиальной, но часто приводящая к раздуванию образов и медленным сборкам. Классический подход с копированием requirements.txt игнорирует возможности кэширования слоёв. Разберём проверенные методы оптимизации процесса.
Проблемы классического подхода
Типичный Dockerfile содержит уязвимую структуру:
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
Любое изменение исходного кода сбрасывает кэш команды RUN pip install. Образы также накапливают лишние утилиты сборки, что критично для финальных стадий развёртывания.
Оптимизация через BuildKit
Используйте двухэтапный процесс. Активация BuildKit через DOCKER_BUILDKIT=1 открывает доступ к продвинутому кэшированию.
FROM python:3.11-slim AS builder
RUN pip install --no-cache-dir --prefix=/install uv
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --target=/install
FROM python:3.11-slim
COPY --from=builder /install /usr/local
COPY . /app
WORKDIR /app
CMD ["python", "main.py"]
Инструмент uv ускоряет установку в десятки раз благодаря параллельной загрузке. Флаг —frozen жёстко фиксирует версии, исключая дрейф зависимостей.
Сравнение методов
| Метод | Время сборки | Размер | Кэш |
|---|---|---|---|
| pip + requirements.txt | Высокое | Среднее | Низкое |
| uv + pyproject.toml | Низкое | Минимальное | Высокое |
| Мультистейдж | Оптимальное | Минимальное | Максимальное |
Практические рекомендации
Разделяйте установку пакетов и копирование кода. Используйте slim-образы для снижения поверхности атаки. Настройте BuildKit в CI/CD. Избегайте установки build-essential без крайней необходимости.
Вопрос-ответ (FAQ)
Зачем использовать двухэтапную сборку?
Она отделяет среду сборки от выполнения. В финальный образ попадают только бинарники, что снижает размер и исключает лишние утилиты.
Как кэшировать зависимости при изменении кода?
Размещайте RUN pip install или uv sync до COPY . .. Кэш переиспользуется, если файлы версий не изменены.
Можно ли использовать requirements.txt с uv?
Да, но не рекомендуется. uv требует pyproject.toml и uv.lock для детерминированных сборок. requirements.txt не фиксирует транзитивные зависимости точно.