Большинство разработчиков используют Docker как «виртуалку в коробке». Продвинутый уровень начинается, когда ты начинаешь мыслить слоями, кешем и размером образа.
Главное правило - многоступенчатые сборки (multi-stage builds).
Зачем это нужно:
Ты разделяешь процесс сборки и запуска.
В одном образе у тебя компиляторы, dev-зависимости, инструменты сборки.
Во втором - только чистый рантайм и готовый артефакт.
В итоге:
- образ меньше в разы
- меньше уязвимостей
- быстрее деплой
- быстрее pull на серверах
Как правильно мыслить:
1. Build stage - всё тяжёлое
Здесь ты устанавливаешь build-essential, gcc, node, go, poetry, всё что нужно для сборки.
2. Runtime stage - только то, что нужно приложению в работе
Никаких компиляторов. Никаких dev-зависимостей.
3. Кеш слоёв - твой главный ускоритель
Файлы зависимостей копируются раньше кода. Тогда при изменении кода Docker не пересобирает всё.
4. Не запускай контейнеры от root
Создай пользователя внутри контейнера. Это реальный прирост безопасности.
5. Используй конкретные версии образов
Не python:latest, а python:3.12.2-slim. Иначе однажды всё сломается без твоего участия.
# Stage 1 - сборка
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --prefix=/install --no-cache-dir -r requirements.txt
COPY . .
# Stage 2 - минимальный рантайм
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /install /usr/local
COPY --from=builder /app .
RUN useradd -m appuser
USER appuser
CMD ["python", "app.py"]