feat(docker): многоступенчатая сборка с Nuitka и офлайн-режим
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>
This commit is contained in:
1 parent
f21483489a
commit
0a4da80ca9
12 files changed
+218
-100
No files matched your search
+45
-11
@@ -1,24 +1,58 @@
|
||||
# Сервис api (#78): принимает задачи и отдаёт результаты. Без Chrome — лёгкий образ.
|
||||
FROM python:3.12-slim-bookworm
|
||||
#
|
||||
# builder: компилирует src/ (через entry_api.py) в самодостаточный standalone-бинарник Nuitka —
|
||||
# в финальный образ не попадают ни исходники .py, ни gcc/pip, ни сам requirements-api.txt.
|
||||
FROM python:3.12-slim-bookworm AS builder
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PIP_NO_CACHE_DIR=1 \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
|
||||
WORKDIR /app
|
||||
# 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/*
|
||||
|
||||
COPY requirements-api.txt .
|
||||
RUN pip install -r requirements-api.txt \
|
||||
# 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
|
||||
|
||||
COPY --chown=app:app src/main.py ./src/
|
||||
COPY --chown=app:app src/tasks/ ./src/tasks/
|
||||
COPY --chown=app:app src/db/ ./src/db/
|
||||
COPY --chown=app:app src/api/__init__.py src/api/schemas.py ./src/api/
|
||||
WORKDIR /app
|
||||
COPY --from=builder --chown=app:app /build/dist/entry_api.dist/ ./
|
||||
|
||||
USER app
|
||||
WORKDIR /app/src
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
# dbcli — админ-CLI клиентов и ключей (ранее `python -m db.cli`): docker compose exec api ./entry_api.bin dbcli ...
|
||||
CMD ["./entry_api.bin"]
|
||||
Reference in new issue
Block a user