Files
gpu-rent/docs/architecture.md
T
2026-08-21 02:42:48 +03:00

10 KiB
Raw Blame History

Архитектура

Обзор

┌─ локальная машина (Windows / Linux) ─────────────────────────┐
│  gpu-rent CLI                                                 │
│    up / stop / status / doctor / hold                         │
│    tunnel / open          — SSH localhost:17801 → VM :7801    │
│    state ~/.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: ноут можно закрыть.

Слои CLI

Модуль Ответственность
cli Typer: up, tunnel, open, status, stop, destroy, logs, ssh, doctor, hold, seed-*, push-models, pull-output, resize-data, dry-run
config .env, валидация, пути к ключам
state JSON сессии: ids, фаза, timestamps
os_client openstacksdk, refresh IAM-токена
inventory Flavors/images в сегменте, квоты, фоллбек flavor
bootstrap Идемпотентный first-boot; после успеха — snapshot boot volume
doctor Preflight без mutating compute
civitai_seed Манифест + Civitai API на .red
models_push SFTP ./Models, ./Wildcards, ./CustomWorkflows
output_pull Опциональный SFTP с VM Output/
git_seed Clone extensions.yaml
autocomplete_seed Word-list + Settings.fds
notify Toast/звук при backend Idle
tunnel paramiko / sshtunnel, порт 17801
watchdog EXPIRED → unshelve, пока туннель жив
idle_killer systemd на VM + hold-файл + «качалка занята»
reconcile Сироты по state и тегу gpu-rent

Каталог сервисов — из 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, autocomplete.md, models.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_….

Стейт-машина

 idle
   │ gpu-rent up
   ▼
 provisioning  →  bootstrapping  →  seeding_extensions  →  seeding_autocomplete  →  seeding_models  →  waiting_ui
   │
   ▼
 ready_cloud          ← compute жив, idle-killer вооружён
   │
   │ gpu-rent tunnel (опционально, пока ноут онлайн)
   ▼
 ready_tunneled       ← localhost:17801
   │
   │ хостер: EXPIRED
   ▼
 restoring (unshelve) → ready_cloud / ready_tunneled
   │
   │ stop | idle-killer | destroy
   ▼
 stopping → idle

ready_cloud ≠ Nova ACTIVE. ACTIVE бывает раньше SSH и UI.

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 — абсолютное продление. --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:17801127.0.0.1:7801 на VM.

Стек

Слой Выбор
Python 3.11+ openstacksdk, paramiko, Typer, Rich, questionary, dotenv
SSH paramiko + sshtunnel (Windows без системного ssh -L)
Конфиг %USERPROFILE%\.gpu-rent\.env
Лицензия MIT