Files
gpu-rent/docs/architecture.md
T
Leonid Pershin f8f8dcc93e Update documentation to clarify GPU control commands
- Revised README, architecture, CLI, and other documentation to specify that both `Ctrl+C` and `Ctrl+D` now stop the GPU while preserving disk data, correcting previous inaccuracies.
- Enhanced access card and setup instructions to reflect the updated command behavior for better user understanding.
- Updated tests to ensure the new command behaviors are validated and documented correctly, improving overall clarity in GPU management.
2026-08-21 20:12:03 +03:00

11 KiB
Raw Blame History

Архитектура

Обзор

┌─ локальная машина (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 / LLM busy → delete this server │
│    app cred: DELETE/GET только этот server_id (fail closed)   │
│    optional: Ollama :11434 (туннель 17811)                    │
│                                                               │
│  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 / term / prompts Typer + цветной лог + нумерованные меню
config / varsfile .env + gpu-rent.vars, пути
state JSON сессии: ids, фаза, timestamps
os_client / cloud / pools openstacksdk, ресурсы, скан пулов
inventory / ux Flavors, квоты; preview / ServerPlan (flavor/disk/spot)
session cmd_up / cmd_stop / adopt
bootstrap + remote/bootstrap.sh Идемпотентный first-boot; light без apt
provision extensions, autocomplete, civitai seed, LLM, push, idle-killer arm, start SwarmUI
capture Инвентарь VM → merge ссылок в локальные манифесты
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 + ollama-models.yaml
idle_killer / hold systemd на VM + hold-файл
ready / snapshot Idle backend + boot snapshot
access_card URL / MCP panel после ready

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

Remount bind’ов — только после systemctl stop swarmui и обычного umount. umount -l на живом Comfy позже опустошает вкладку Models (веса на data 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 и Ctrl+D вызывают 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, sshtunnel, Typer, Rich, dotenv, httpx, pyyaml
SSH paramiko + sshtunnel (Windows без системного ssh -L)
Конфиг <repo>/.env + gpu-rent.vars + runtime в <repo>/.gpu-rent/
Лицензия MIT