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
+17
-6
@@ -47,7 +47,7 @@ make key-list # клиенты: начало ключа, акти
|
||||
make key-revoke id=3 # отозвать
|
||||
```
|
||||
|
||||
На сервере без make: `docker compose exec api python -m db.cli create acme` (и `list`, `revoke <id>`, `stats`).
|
||||
На сервере без make: `docker compose exec api ./entry_api.bin dbcli create acme` (и `list`, `revoke <id>`, `stats`).
|
||||
|
||||
## Статистика использования
|
||||
|
||||
@@ -70,17 +70,28 @@ make stats days=7
|
||||
|
||||
## Что внутри образа worker
|
||||
|
||||
Сборка двухстадийная (`Dockerfile`): `builder` компилирует `src/` (через `entry_worker.py`) в самодостаточный
|
||||
standalone-бинарник Nuitka, `runtime` берёт из него только готовую папку `entry_worker.dist/` — исходники `.py`,
|
||||
`requirements.txt`, gcc и pip в финальный образ не попадают.
|
||||
|
||||
| Компонент | Зачем |
|
||||
|---|---|
|
||||
| `python:3.12-slim-bookworm` | базовый образ, Python той же версии, что и в `.venv` |
|
||||
| `requirements.txt` | ставится из PyPI (папка `wheels/` в образ не попадает — она под Ubuntu Noble и неполная) |
|
||||
| Google Chrome stable (`patchright install --with-deps chrome`) | сессия запускается с `real_chrome=True` → channel `chrome` |
|
||||
| `entry_worker.bin` (standalone, builder) | скомпилированный Nuitka код `src/` + его Python-зависимости; оборачивает `dramatiq worker.actors --processes 1 --threads N` |
|
||||
| `python:3.12-slim-bookworm` (runtime) | базовый образ — Python тут нужен только на шаге установки Chrome (`patchright install`), сам бинарник от него не зависит |
|
||||
| Google Chrome stable (`patchright install --with-deps chrome`) | сессия запускается с `real_chrome=True` → channel `chrome`; после установки пакет `patchright` из runtime удаляется |
|
||||
| Xvfb (`xvfb-run`) | браузер работает в headful-режиме (`headless=False`), нужен виртуальный дисплей 1920x1080x24 |
|
||||
| `tini` (ENTRYPOINT, PID 1) | пробрасывает сигналы и подбирает осиротевшие процессы Chrome/Xvfb — без него копятся зомби-процессы |
|
||||
| пользователь `app` (uid 1000) | Chrome не запускается от root без `--no-sandbox` |
|
||||
|
||||
Рабочая директория — `/app/src`. Воркер — один процесс dramatiq (`--processes 1`: открытые окна живут в его памяти),
|
||||
потоков `WORKER_THREADS` (по умолчанию `2 × BROWSER_SLOTS`).
|
||||
`make build offline=1` ставит python-зависимости builder-стадии только из `wheels/` (`make wheels`), без обращения
|
||||
к PyPI — установку самого Chrome (apt + скачивание) это не затрагивает, сеть для неё нужна всегда. Wheels, собранные
|
||||
`pip wheel`, переносимы между дистрибутивами, только если для пакета есть готовый `manylinux`-wheel на PyPI; если
|
||||
для какого-то пакета его нет и pip собирает колесо из исходников на хосте — используйте для `make wheels` машину
|
||||
или контейнер на той же базе, что и образ (`python:3.12-slim-bookworm`), иначе колесо может не завестись в сборке.
|
||||
|
||||
Рабочая директория — `/app`. Воркер — один процесс dramatiq (`--processes 1`: открытые окна живут в его памяти),
|
||||
потоков `WORKER_THREADS` (по умолчанию `2 × BROWSER_SLOTS`) — читает `entry_worker.py` сам, в `CMD` эти флаги больше
|
||||
не передаются.
|
||||
|
||||
## Данные и volume
|
||||
|
||||
|
||||
Reference in new issue
Block a user