Files
gpu-rent/docs/architecture.md
T
Leonid Pershin 2005b00175 Update configuration and documentation for LLM support and local watchdog
- Added `ollama-models.yaml` to .gitignore and implemented logic to copy it in gpu-rent.ps1 and gpu-rent.sh.
- Enhanced env.example to include new variables for LLM runtime options and local watchdog configuration.
- Updated CLI commands to support LLM options during setup and execution, including new flags for Ollama and llama.cpp.
- Improved documentation in cli.md and README.md to reflect changes in LLM integration and local watchdog functionality.
- Adjusted architecture and decisions documentation to clarify the role of LLMs and local watchdog in the system.
2026-08-21 05:29:23 +03:00

176 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Архитектура
## Обзор
```
┌─ локальная машина (Windows / Linux) ─────────────────────────┐
│ gpu-rent CLI │
│ up / stop / status / doctor / hold │
│ tunnel / open — SSH localhost:17801 → VM :7801 │
│ state <repo>/.gpu-rent/state.json │
│ │
│ браузер / MCP / curl API → http://127.0.0.1:17801 │
│ локальный SwarmUI → http://127.0.0.1:7801 (не трогаем)
└───────────────────────────────┬──────────────────────────────┘
│ SSH :22 и OpenStack API
┌─ Selectel, сегмент пула (например ru-7a) ────────────────────┐
│ GPU VM (tag preemptible + gpu-rent) │
│ SwarmUI : 127.0.0.1:7801 │
│ idle-killer: очередь / hold / качалка в UI → delete self │
│ application credential (compute delete/shelve only) │
│ │
│ boot volume (network) ОС + NVIDIA + SwarmUI нативно + snapshot │
│ data volume (network) Models, Output, Data, workflows │
│ floating IP только SSH, удаляется на stop │
└──────────────────────────────────────────────────────────────┘
```
Два сетевых диска. После удаления VM boot-диск снова указывают как `--volume` при create.
Разделение **жизни GPU** и **локального туннеля** — следствие [decisions.md](decisions.md): ноут можно закрыть.
## Слои CLI
| Модуль | Ответственность |
| --- | --- |
| `cli` | Typer: `up`, `setup`, `tunnel`, `open`, `status`, `stop`, `destroy`, `logs`, `ssh`, `doctor`, `hold`, `seed-*`, `push` / `pull-output`, `resize-data`, `watchdog`, `dry-run` |
| `config` / `varsfile` | `.env` + `gpu-rent.vars`, пути |
| `state` | JSON сессии: ids, фаза, timestamps |
| `os_client` / `cloud` / `pools` | openstacksdk, ресурсы, скан пулов |
| `inventory` | Flavors/images, квоты, фоллбек flavor |
| `session` | `cmd_up` / `cmd_stop` / adopt |
| `bootstrap` + `remote/bootstrap.sh` | Идемпотентный first-boot; light без apt |
| `provision` | extensions, autocomplete, civitai seed, push, idle-killer arm, start SwarmUI |
| `doctor` | Preflight без mutating compute |
| `sync_files` | SFTP `Models` / Wildcards / workflows / Output |
| `notify` | Toast/звук при backend Idle |
| `tunnel` | sshtunnel + Nova EXPIRED watchdog |
| `local_watchdog` | Опциональный локальный тик → stop при unclean exit |
| `llm_runtime` / `setup_wizard` | Opt-in Ollama/llama.cpp + `ollama-models.yaml` |
| `idle_killer` / `hold` | systemd на VM + hold-файл |
| `ready` / `snapshot` | Idle backend + boot snapshot |
Каталог сервисов — из Keystone, не из выдуманного `api.selectel.ru/v3/`.
## Два диска
### Boot volume
Сетевой, тот же сегмент, что VM. Первый раз — GPU-optimized образ **без Docker**. `delete_on_termination=false`. Локальный boot запрещён (preemptible сотрёт ОС).
После bootstrap: NVIDIA из образа, `/opt/swarmui` + systemd, unit idle-killer, application credential в `/root/.gpu-rent/` (mode 600).
После **первого** успешного `waiting_ui` + backend Idle: один snapshot boot-диска `gpu-rent-boot-ok` (если ещё нет). Следующий create VM может идти из snapshot, не из сырого GPU-образа. Старый snapshot не плодить каждый `up`.
### Data volume
Второй BDM при create (не attach после ACTIVE). FS один раз, маркер `/mnt/swarm_data/.gpu-rent-ready`. Первый seed: [extensions.md](extensions.md), [autocomplete.md](autocomplete.md), [models.md](models.md), [local-folders.md](local-folders.md).
| На хосте (data volume) | В дереве SwarmUI (`/opt/swarmui`, bind) |
| --- | --- |
| `/mnt/swarm_data/Models` | `/opt/swarmui/Models` |
| `/mnt/swarm_data/Output` | `/opt/swarmui/Output` |
| `/mnt/swarm_data/Data` | `/opt/swarmui/Data` |
| `/mnt/swarm_data/dlbackend` | `/opt/swarmui/dlbackend` |
| `/mnt/swarm_data/Extensions` | `/opt/swarmui/src/Extensions` |
| `/mnt/swarm_data/DLNodes` | `/opt/swarmui/src/BuiltinExtensions/ComfyUIBackend/DLNodes` |
| `/mnt/swarm_data/CustomWorkflows` | `/opt/swarmui/src/BuiltinExtensions/ComfyUIBackend/CustomWorkflows` |
`mkfs` только если нет маркера **и** `blkid` подтвердил пустое устройство по serial/by-id. Не хардкодить `scsi-0Selectel_Volume_…`.
## Стейт-машина
Фазы в `state.json` (код пишет только эти):
```
idle
│ gpu-rent up
provisioning ← create volumes / server
bootstrapping ← SSH + bootstrap + seed (пока не ready)
ready_cloud ← compute жив, idle-killer вооружён
│ gpu-rent tunnel (или up с туннелем)
ready_tunneled ← localhost:17801
│ stop | idle-killer | local-watchdog | destroy
idle
```
Подшаги seed (extensions / autocomplete / models) идут внутри `bootstrapping`, отдельными фазами в state не пишутся. `ready_cloud` ≠ Nova `ACTIVE` (ACTIVE бывает раньше SSH и UI).
На EXPIRED туннель сам делает unshelve → снова `bootstrapping`/`ready_*`.
## Idle-killer (на VM)
Пока очередь SwarmUI пуста дольше **30 минут**, скрипт удаляет **этот** compute через OpenStack (диски не трогать). Открытый браузер без джобы жизнь **не** продлевает.
Killer молчит:
- clone расширений, Civitai-seed, push локальных папок;
- первые **45 минут** после ACTIVE или unshelve;
- пока backend/ComfyUI ещё не Idle;
- пока существует hold: файл `/mnt/swarm_data/.gpu-rent-hold-until` с unix ts (пишет `gpu-rent hold`);
- пока SwarmUI качает модель в UI (Model Downloader / активный download — точный JSON на spike). Нет сигнала — пользователь жмёт `hold`.
`gpu-rent hold` без аргументов = +`IDLE_MINUTES` от сейчас. `--minutes 90` — hold до now+90 мин (заменяет предыдущий, не складывает). `--until` ISO опционально. `hold --clear` снимает.
Потом счётчик 30 минут пустой очереди.
Почему не `shutdown -h now`: у Selectel останов из гостя не обязан снять GPU с биллинга. Нужен API delete/shelve.
Почему не только локальный CLI: ноут спит — процесса нет — GPU продолжает тарифицироваться.
Учётные данные на VM: application credential (или роль без `compute:create`), только delete/shelve. Файл не попадает в Output/Models. Истечение кредов = killer слеп; тогда спасает `gpu-rent status` с ноутбука.
Дефолты: `IDLE_MINUTES=30`, `IDLE_GRACE_MINUTES=45`.
## Watchdog туннеля (на ноутбуке)
Работает только пока открыт туннель:
1. Refresh IAM-токена (TTL 24 ч, как у preemptible).
2. `EXPIRED` → unshelve → переоткрыть туннель.
3. `ERROR` / нет GPU → выход, не бесконечный recreate.
4. Туннель мёртв при ACTIVE → reconnect.
`Ctrl+C` здесь закрывает туннель, **не** вызывает `stop`.
## Teardown (`gpu-rent stop`)
Compute удаляется через OpenStack без SSH. Optional pull Output — только если VM ещё отвечает по SSH:
1. Если `PULL_OUTPUT` и SSH жив — забрать новые файлы в `./Output` (`--no-pull` пропускает).
2. Закрыть туннель этого процесса, если открыт.
3. Удалить compute. Volumes оставить.
4. Дождаться исчезновения сервера.
5. Удалить floating IP (`KEEP_FLOATING_IP=false`).
6. State → `idle`, сохранить volume ids.
`destroy` — то же + диски после `--i-understand-data-loss`.
Reconcile: сервер с тегом `gpu-rent` есть, локального процесса нет — это норма (`ready_cloud`). Сирота = нет тега в state и наоборот; `status` показывает «жив, туннеля нет, idle-killer: …».
## Сеть на VM
- Private net + subnet + router — один раз на пул, переиспользовать.
- SG: ingress TCP/22 с IP оператора. **Не** открывать 7801 наружу.
- SwarmUI: `--host 127.0.0.1 --port 7801` (systemd `swarmui`).
- Туннель: `127.0.0.1:17801``127.0.0.1:7801` на VM.
## Стек
| Слой | Выбор |
| --- | --- |
| Python 3.11+ | openstacksdk, paramiko, sshtunnel, Typer, Rich, dotenv, httpx, pyyaml |
| SSH | paramiko + sshtunnel (Windows без системного `ssh -L`) |
| Конфиг | `<repo>/.env` + `gpu-rent.vars` + runtime в `<repo>/.gpu-rent/` |
| Лицензия | MIT |