__main__.py как исполняемый zip-архив — деплой без интерпретатора в scratch-образыДолгое время деплой Python-сервисов в Docker означал обязательную установку интерпретатора, даже
slim-образы весят 50-100+ МБ. Для микросервисов это расточительно и увеличивает время развертывания. PEP 738, реализованный в Python 3.12+, меняет подход, позволяя использовать zipapp для создания исполняемых архивов.Как это работает
PEP 738 разрешает исполнять zip-архив, содержащий
__main__.pypython app.zip. В основе лежит класс zipimport, который теперь поддерживает загрузку кода без распаковки. Для деплоя в scratch-образ нужно скомпилировать Python в статический бинарник.* Упакуйте приложение с зависимостями:
# project/
# __main__.py
# app/
# vendor/
python -m zipapp project -o app.zip
* Используйте
python-build-standalone или nuitka для получения статического бинарника без внешних зависимостей.* Итоговый Dockerfile:
FROM scratch
COPY static-python /python
COPY app.zip /
ENTRYPOINT ["/python", "/app.zip"]
Production-пример: HTTP-микросервис
Рассмотрим микросервис на FastAPI:
# __main__.py
import uvicorn
from app.main import app
uvicorn.run(app, host="0.0.0.0", port=8000)
Сборка:
python -m zipapp project -o app.zip
# Статический бинарник Python ~5-8 МБ
FROM python:3.12-slim AS builder
COPY app.zip .
FROM scratch
COPY --from=builder /python /python
COPY --from=builder /app.zip /
ENTRYPOINT ["/python", "/app.zip"]
Итоговый образ весит 10-20 МБ вместо 100+ МБ. Это напрямую ускоряет деплой в Kubernetes и уменьшает трафик при пуле образов.
Типичная ошибка и ограничения
* Ошибка: Попытка включить нативные C-расширения вроде
psutil или cryptography в архив. Они не работают без /usr/lib — нужна статическая сборка этих библиотек.* Предупреждение: Не все библиотеки совместимы. Например,
pandas или numpy могут требовать системных .so-файлов. Выход — использовать manylinux-совместимые wheels или статические билды.Практический совет и trade-offs
Для сервисов на
asyncio с простыми зависимостями (HTTP-клиенты, JSON, SQLAlchemy без C-ускорений) этот подход идеален. Но для CLI-утилит или Lambda-функций он уже стандарт. Главный trade-off: уменьшение размера образа на 80% за счет невозможности использовать системные утилиты и сложность отладки (нет bash, curl). Для observability используйте только exec-форму ENTRYPOINT.Вывод: PEP 738 и
zipapp позволяют сократить размер Docker-образов для Python-микросервисов до 10-20 МБ, жертвуя гибкостью системного окружения ради производительности деплоя и безопасности scratch-образов.