api и worker компилируются Nuitka (--mode=standalone) в builder-стадии; в финальном образе — только скомпилированный бинарник и системные библиотеки, без исходников, pip и build-инструментов. api/runtime — debian:bookworm-slim без Python вообще; worker/runtime — python:3.12-slim-bookworm, но Python там нужен только на шаг установки Chrome. db.cli объединён с сервером в один бинарник (entry_api.bin dbcli ...). Заодно убрано 51 неиспользуемый пакет из requirements.txt (camoufox, PySide6, moz*- стек и др., подтверждено графом зависимостей) — он давал больше веса, чем сама компиляция. make build offline=1 ставит python-зависимости из wheels/ без PyPI. make test-browser адаптирован под новую сборку: pytest не может подключиться к internals скомпилированного бинарника, поэтому гоняется против отдельной стадии test (Chrome из runtime + исходники как обычный интерпретируемый Python). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
59 lines
3.1 KiB
Docker
59 lines
3.1 KiB
Docker
# Сервис api (#78): принимает задачи и отдаёт результаты. Без Chrome — лёгкий образ.
|
|
#
|
|
# builder: компилирует src/ (через entry_api.py) в самодостаточный standalone-бинарник Nuitka —
|
|
# в финальный образ не попадают ни исходники .py, ни gcc/pip, ни сам requirements-api.txt.
|
|
FROM python:3.12-slim-bookworm AS builder
|
|
|
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
PIP_NO_CACHE_DIR=1 \
|
|
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
|
|
# build-essential (gcc + libc6-dev — заголовки Python.h тянут stdlib.h/limits.h) — компилятор для
|
|
# сгенерированного Nuitka C-кода; patchelf — правит RPATH бинарника в standalone-режиме;
|
|
# ccache — ускоряет повторные сборки при пересборке образа
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends build-essential patchelf ccache \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# OFFLINE=1: ставить зависимости только из wheels/ (make wheels), без обращения к PyPI — см. docs/Deployment.md
|
|
ARG OFFLINE=0
|
|
WORKDIR /build
|
|
COPY requirements-api.txt requirements-build.txt ./
|
|
COPY wheels/ ./wheels/
|
|
RUN set -e; \
|
|
if [ "$OFFLINE" = "1" ]; then PIP_OPTS="--no-index --find-links=./wheels"; else PIP_OPTS=""; fi; \
|
|
pip install $PIP_OPTS -r requirements-api.txt -r requirements-build.txt
|
|
|
|
COPY src/main.py src/entry_api.py ./src/
|
|
COPY src/tasks/ ./src/tasks/
|
|
COPY src/db/ ./src/db/
|
|
COPY src/api/__init__.py src/api/schemas.py ./src/api/
|
|
|
|
# standalone: entry_api.dist/ — изолированная папка со своим Python-рантаймом и всеми пакетами, которые
|
|
# реально нужны entry_api.py (uvicorn, fastapi, db, tasks, api.schemas); world.actors/api.actions сюда не
|
|
# попадают — entry_api.py их не импортирует. --include-package на первом месте — на случай отложенного
|
|
# импорта, который статический анализ Nuitka мог не увидеть
|
|
RUN python -m nuitka --mode=standalone \
|
|
--include-package=api --include-package=db --include-package=tasks \
|
|
--output-dir=/build/dist \
|
|
src/entry_api.py
|
|
|
|
# runtime: без Python, pip и исходников — только то, что нужно скомпилированному бинарнику
|
|
FROM debian:bookworm-slim AS runtime
|
|
|
|
# libpq5 — asyncpg/SQLAlchemy ходят в Postgres через системную libpq, Nuitka её не компилирует, а
|
|
# подключает динамически
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends libpq5 ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
&& useradd --create-home --uid 1000 app
|
|
|
|
WORKDIR /app
|
|
COPY --from=builder --chown=app:app /build/dist/entry_api.dist/ ./
|
|
|
|
USER app
|
|
EXPOSE 8000
|
|
|
|
# dbcli — админ-CLI клиентов и ключей (ранее `python -m db.cli`): docker compose exec api ./entry_api.bin dbcli ...
|
|
CMD ["./entry_api.bin"]
|