Update README and CLI documentation for tunnel functionality
- Enhanced README.md to clarify the `gpu-rent up` command, including default tunnel behavior and options for cloud-only operation. - Updated cli.md to reflect changes in the `gpu-rent up` command, detailing the new `--no-tunnel` option and its implications. - Revised decisions.md to explain the separation of `up` and `tunnel` commands, emphasizing the default tunnel opening after `up`. - Improved doctor.py to provide clearer instructions regarding tunnel creation and cloud-only usage. - Adjusted notify.py to reflect the updated command usage for accessing the SwarmUI.
This commit is contained in:
@@ -13,8 +13,9 @@
|
|||||||
.\gpu-rent.ps1 doctor # preflight
|
.\gpu-rent.ps1 doctor # preflight
|
||||||
.\gpu-rent.ps1 flavors # что выберет фоллбек
|
.\gpu-rent.ps1 flavors # что выберет фоллбек
|
||||||
.\gpu-rent.ps1 dry-run # план без create
|
.\gpu-rent.ps1 dry-run # план без create
|
||||||
.\gpu-rent.ps1 up --yes # GPU + SwarmUI + seed
|
.\gpu-rent.ps1 up --yes # GPU + SwarmUI + seed + туннель :17801
|
||||||
.\gpu-rent.ps1 tunnel # UI на :17801 (Ctrl+C ≠ stop)
|
.\gpu-rent.ps1 up --yes --no-tunnel # только облако
|
||||||
|
.\gpu-rent.ps1 tunnel --open # снова открыть UI, если туннель закрыли
|
||||||
.\gpu-rent.ps1 hold # отложить idle-killer
|
.\gpu-rent.ps1 hold # отложить idle-killer
|
||||||
.\gpu-rent.ps1 stop # гасить compute, диски оставить
|
.\gpu-rent.ps1 stop # гасить compute, диски оставить
|
||||||
```
|
```
|
||||||
@@ -38,8 +39,10 @@ Unix: `./gpu-rent.sh …` (один раз `chmod +x gpu-rent.sh`).
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `doctor` | Keystone, квота GPU, flavor, Civitai, манифесты |
|
| `doctor` | Keystone, квота GPU, flavor, Civitai, манифесты |
|
||||||
| `flavors` | Живой список по `FLAVOR_PREFERENCE` |
|
| `flavors` | Живой список по `FLAVOR_PREFERENCE` |
|
||||||
| `up` / `up --yes` / `up --no-spot` / `up --flavor ID` | Поднять GPU |
|
| `up` / `up --yes` | Поднять GPU + туннель :17801 (браузер). Ctrl+C = туннель off |
|
||||||
| `tunnel` / `tunnel --open` | SSH-проброс; watchdog на EXPIRED |
|
| `up --no-tunnel` | Только облако |
|
||||||
|
| `up --no-spot` / `up --flavor ID` | Обычный тариф / явный flavor |
|
||||||
|
| `tunnel` / `tunnel --open` | Повторный проброс; watchdog на EXPIRED |
|
||||||
| `open` | Браузер на 17801 |
|
| `open` | Браузер на 17801 |
|
||||||
| `hold` / `hold --minutes 90` / `hold --clear` | Пауза idle-killer |
|
| `hold` / `hold --minutes 90` / `hold --clear` | Пауза idle-killer |
|
||||||
| `status` | Nova + диск + killer |
|
| `status` | Nova + диск + killer |
|
||||||
|
|||||||
+3
-2
@@ -8,10 +8,11 @@
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `gpu-rent flavors` | Скан `SCAN_POOLS` (ru-6 multizone…) × `FLAVOR_PREFERENCE`, затем список в текущем `OS_REGION_NAME` |
|
| `gpu-rent flavors` | Скан `SCAN_POOLS` (ru-6 multizone…) × `FLAVOR_PREFERENCE`, затем список в текущем `OS_REGION_NAME` |
|
||||||
| `gpu-rent doctor` | Preflight **без** create: Keystone, квота GPU, flavor в AZ, диски, Civitai token+`.red`, манифесты, SSH-ключ. Код выхода ≠ 0, если сессию нельзя начать |
|
| `gpu-rent doctor` | Preflight **без** create: Keystone, квота GPU, flavor в AZ, диски, Civitai token+`.red`, манифесты, SSH-ключ. Код выхода ≠ 0, если сессию нельзя начать |
|
||||||
| `gpu-rent up` | Preflight → create/unshelve (с фоллбеком flavor) → extensions → autocomplete → Civitai seed → push локальных папок → ждать UI → toast/звук |
|
| `gpu-rent up` / `up --yes` | Preflight → create/unshelve → bootstrap → **туннель** `localhost:17801` + URL панели; Ctrl+C закрывает туннель |
|
||||||
|
| `gpu-rent up --no-tunnel` | Только облако + bootstrap, без локального проброса |
|
||||||
| `gpu-rent up --no-spot` | Обычный (не preemptible) сервер |
|
| `gpu-rent up --no-spot` | Обычный (не preemptible) сервер |
|
||||||
| `gpu-rent up --flavor … --yes` | Без вопросов. `--flavor` бьёт список фоллбека. `--yes` без `--flavor` берёт первый доступный из `FLAVOR_PREFERENCE` |
|
| `gpu-rent up --flavor … --yes` | Без вопросов. `--flavor` бьёт список фоллбека. `--yes` без `--flavor` берёт первый доступный из `FLAVOR_PREFERENCE` |
|
||||||
| `gpu-rent tunnel` | SSH-проброс `localhost:17801` → VM `:7801`. Блокируется. Ctrl+C = закрыть туннель, GPU **оставить** |
|
| `gpu-rent tunnel` | Повторный SSH-проброс, если `up --no-tunnel` или туннель уже закрыли. Ctrl+C = закрыть туннель, GPU **оставить** |
|
||||||
| `gpu-rent tunnel --open` | Туннель + сразу открыть браузер на 17801 |
|
| `gpu-rent tunnel --open` | Туннель + сразу открыть браузер на 17801 |
|
||||||
| `gpu-rent open` | Открыть браузер на `http://127.0.0.1:17801`. Туннель уже должен слушать порт |
|
| `gpu-rent open` | Открыть браузер на `http://127.0.0.1:17801`. Туннель уже должен слушать порт |
|
||||||
| `gpu-rent status` | State + Nova + диск used/free + ₽/час + сколько до 24 ч preempt + killer/hold. Туннель не обязателен |
|
| `gpu-rent status` | State + Nova + диск used/free + ₽/час + сколько до 24 ч preempt + killer/hold. Туннель не обязателен |
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
| Floating IP | `KEEP_FLOATING_IP=false`: выделить на `up`, удалить на `stop` |
|
| Floating IP | `KEEP_FLOATING_IP=false`: выделить на `up`, удалить на `stop` |
|
||||||
| Idle-killer | 30 минут пустой очереди генерации. Открытый браузер не продлевает жизнь |
|
| Idle-killer | 30 минут пустой очереди генерации. Открытый браузер не продлевает жизнь |
|
||||||
| Льгота после boot | Killer молчит во время clone/seed/push, hold, качалки в UI SwarmUI, пока backend не Idle, и 45 мин после ACTIVE/unshelve |
|
| Льгота после boot | Killer молчит во время clone/seed/push, hold, качалки в UI SwarmUI, пока backend не Idle, и 45 мин после ACTIVE/unshelve |
|
||||||
| `up` / `tunnel` | Разделены: `up` только облако, `tunnel` отдельно. Ctrl+C на туннеле не удаляет VM |
|
| `up` / `tunnel` | `up` по умолчанию после ready открывает туннель `:17801`, печатает URL и ждёт. `--no-tunnel` — только облако. Ctrl+C на туннеле GPU не гасит (`stop` отдельно). Команда `tunnel` остаётся для повторного входа |
|
||||||
| Data-диск | Старт **100 GB**, рост через resize вверх (вниз Selectel не умеет) |
|
| Data-диск | Старт **100 GB**, рост через resize вверх (вниз Selectel не умеет) |
|
||||||
| SSH | CLI генерирует `<repo>/.gpu-rent/id_ed25519` без passphrase и сам регистрирует keypair |
|
| SSH | CLI генерирует `<repo>/.gpu-rent/id_ed25519` без passphrase и сам регистрирует keypair |
|
||||||
| Локальные файлы | Всё в корне репозитория: `.env`, `models.yaml`, `extensions.yaml`; runtime (`state.json`, lock, SSH) в `<repo>/.gpu-rent/`. Не `%USERPROFILE%\.gpu-rent` |
|
| Локальные файлы | Всё в корне репозитория: `.env`, `models.yaml`, `extensions.yaml`; runtime (`state.json`, lock, SSH) в `<repo>/.gpu-rent/`. Не `%USERPROFILE%\.gpu-rent` |
|
||||||
|
|||||||
+34
-2
@@ -75,6 +75,7 @@ def _print_checks(checks) -> int:
|
|||||||
_print_next_steps(failed)
|
_print_next_steps(failed)
|
||||||
return 1
|
return 1
|
||||||
console.print("\n[green]Можно идти дальше.[/green] Дальше: gpu-rent up --yes")
|
console.print("\n[green]Можно идти дальше.[/green] Дальше: gpu-rent up --yes")
|
||||||
|
console.print(" (туннель :17801 по умолчанию; только облако: --no-tunnel)")
|
||||||
console.print("Чеклист spike: docs/spike-notes.md")
|
console.print("Чеклист spike: docs/spike-notes.md")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -290,8 +291,18 @@ def up(
|
|||||||
flavor: Optional[str] = typer.Option(None, "--flavor", help="Flavor id, без фоллбека"),
|
flavor: Optional[str] = typer.Option(None, "--flavor", help="Flavor id, без фоллбека"),
|
||||||
yes: bool = typer.Option(False, "--yes", help="Без вопросов"),
|
yes: bool = typer.Option(False, "--yes", help="Без вопросов"),
|
||||||
adopt: bool = typer.Option(False, "--adopt", help="Подхватить тег gpu-rent без state"),
|
adopt: bool = typer.Option(False, "--adopt", help="Подхватить тег gpu-rent без state"),
|
||||||
|
no_tunnel: bool = typer.Option(
|
||||||
|
False,
|
||||||
|
"--no-tunnel",
|
||||||
|
help="Только облако + bootstrap, без локального туннеля",
|
||||||
|
),
|
||||||
|
open_browser: bool = typer.Option(
|
||||||
|
True,
|
||||||
|
"--open/--no-open",
|
||||||
|
help="После туннеля открыть браузер на 17801 (по умолчанию да)",
|
||||||
|
),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create/unshelve GPU и bootstrap SwarmUI (без Docker)."""
|
"""Create/unshelve GPU, bootstrap SwarmUI, по умолчанию туннель на :17801."""
|
||||||
try:
|
try:
|
||||||
checks = run_doctor()
|
checks = run_doctor()
|
||||||
code = _print_checks(checks)
|
code = _print_checks(checks)
|
||||||
@@ -302,7 +313,7 @@ def up(
|
|||||||
def confirm(msg: str) -> bool:
|
def confirm(msg: str) -> bool:
|
||||||
return typer.confirm(msg)
|
return typer.confirm(msg)
|
||||||
|
|
||||||
cmd_up(
|
state = cmd_up(
|
||||||
cfg,
|
cfg,
|
||||||
no_spot=no_spot,
|
no_spot=no_spot,
|
||||||
flavor=flavor,
|
flavor=flavor,
|
||||||
@@ -311,6 +322,27 @@ def up(
|
|||||||
confirm=confirm,
|
confirm=confirm,
|
||||||
log=lambda m: console.print(m),
|
log=lambda m: console.print(m),
|
||||||
)
|
)
|
||||||
|
if no_tunnel:
|
||||||
|
console.print(
|
||||||
|
f"[bold]готово[/bold] (без туннеля). "
|
||||||
|
f"UI: gpu-rent tunnel --open | stop: gpu-rent stop"
|
||||||
|
)
|
||||||
|
if state.floating_ip:
|
||||||
|
console.print(f"FIP {state.floating_ip}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not state.floating_ip:
|
||||||
|
raise GpuRentError("нет floating IP после up — туннель не открыть")
|
||||||
|
console.print(
|
||||||
|
f"[bold]панель[/bold] http://127.0.0.1:{cfg.swarmui_local_port} "
|
||||||
|
"(Ctrl+C = закрыть туннель, GPU жив → gpu-rent stop)"
|
||||||
|
)
|
||||||
|
run_tunnel(
|
||||||
|
cfg,
|
||||||
|
state.floating_ip,
|
||||||
|
open_browser=open_browser,
|
||||||
|
log=lambda m: console.print(m),
|
||||||
|
)
|
||||||
except GpuRentError as exc:
|
except GpuRentError as exc:
|
||||||
_die(exc)
|
_die(exc)
|
||||||
|
|
||||||
|
|||||||
@@ -363,8 +363,8 @@ def dry_run_plan(checks: list[Check]) -> list[str]:
|
|||||||
f"idle-killer: {cfg.idle_minutes} мин пустой очереди, льгота {cfg.idle_grace_minutes} мин",
|
f"idle-killer: {cfg.idle_minutes} мин пустой очереди, льгота {cfg.idle_grace_minutes} мин",
|
||||||
"₽: в API нет — смотри панель; диск 24/7 даже после stop",
|
"₽: в API нет — смотри панель; диск 24/7 даже после stop",
|
||||||
f"туннель: localhost:{cfg.swarmui_local_port} -> VM :7801",
|
f"туннель: localhost:{cfg.swarmui_local_port} -> VM :7801",
|
||||||
"gpu-rent up --yes создаст сеть/диски/compute и поставит SwarmUI (если doctor зелёный и квота GPU > 0)",
|
"gpu-rent up --yes создаст GPU + SwarmUI и откроет туннель :17801 (Ctrl+C не гасит GPU)",
|
||||||
"после up: gpu-rent tunnel (Ctrl+C не гасит GPU)",
|
"только облако без туннеля: gpu-rent up --yes --no-tunnel",
|
||||||
]
|
]
|
||||||
flavor = next((c.detail for c in checks if c.name == "flavor" and c.ok), None)
|
flavor = next((c.detail for c in checks if c.name == "flavor" and c.ok), None)
|
||||||
if flavor:
|
if flavor:
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ def print_mcp_snippet(cfg: Config, log: Log) -> None:
|
|||||||
log("}")
|
log("}")
|
||||||
log("")
|
log("")
|
||||||
log(f"SwarmUI на VM: 127.0.0.1:7801 (только через туннель)")
|
log(f"SwarmUI на VM: 127.0.0.1:7801 (только через туннель)")
|
||||||
log(f"Локально: gpu-rent tunnel")
|
log(f"Локально: уже в up (или gpu-rent tunnel)")
|
||||||
log(f"Браузер: gpu-rent open → http://127.0.0.1:{port}")
|
log(f"Браузер: gpu-rent open → http://127.0.0.1:{port}")
|
||||||
log(f"API: http://127.0.0.1:{port}/API/")
|
log(f"API: http://127.0.0.1:{port}/API/")
|
||||||
log(f"MCP: http://127.0.0.1:{port}/mcp")
|
log(f"MCP: http://127.0.0.1:{port}/mcp")
|
||||||
|
|||||||
Reference in New Issue
Block a user