Initial import: bare-metal stacks, Server UI, GPU fan, tutorials.
Infrastructure configs for GMKtec K11 (Docker, vLLM, LocalAI, ComfyUI, control-plane, gpu-fan agent, Server UI with CLI/file explorer/GPU fan curve). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
# Server UI — edycja portów stacków
|
||||
|
||||
**Data:** 2026-07-05
|
||||
**Host:** gmktec-k11
|
||||
**Kontekst:** Linki „Otwórz :PORT” w Server UI brały port z `stacks.yaml`, podczas gdy Docker mapował port z osobnego `stacks/<name>/.env`. Wdrożono jeden source of truth w `.env` stacku + edycję w UI.
|
||||
|
||||
**Powiązane:**
|
||||
- [`stacks/server-ui/`](../stacks/server-ui/)
|
||||
- [`coding-agent/SERVER-UI-ARCHITECTURE-RESEARCH.md`](SERVER-UI-ARCHITECTURE-RESEARCH.md)
|
||||
- [`coding-agent/CONVENTIONS.md`](CONVENTIONS.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive summary
|
||||
|
||||
Server UI odczytuje i zapisuje port hosta w pliku `stacks/<name>/.env` (np. `LOCALAI_PORT=8070`). Karty stacków mają pole numeryczne i przycisk **Zapisz port**; po zapisie uruchamiany jest `docker compose up -d --force-recreate` gdy stack działa. Nowa usługa wymaga tylko wpisu w `stacks.yaml` z polami `port_env`, `port_default`, `port_editable`.
|
||||
|
||||
---
|
||||
|
||||
## 2. As-is / to-be
|
||||
|
||||
| Aspekt | Przed | Po |
|
||||
|--------|-------|-----|
|
||||
| Źródło portu w linku UI | `stacks.yaml` → `ui_port` (statyczny) | `stacks/<name>/.env` → `port_env` |
|
||||
| Edycja portu | ręcznie w `.env` + restart compose | UI + `PATCH /api/stacks/{id}/port` |
|
||||
| Nowa usługa | hardcode w JS | metadane w `stacks.yaml` |
|
||||
| NPMPlus | link :81 | read-only (host network) |
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
yaml[stacks.yaml port_env metadata]
|
||||
env[stack .env]
|
||||
api[Server UI API]
|
||||
ui[Stack card port input]
|
||||
compose[docker compose force-recreate]
|
||||
yaml --> api
|
||||
env --> api
|
||||
api --> ui
|
||||
api -->|PATCH| env
|
||||
env --> compose
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Konfiguracja stacków (`stacks.yaml`)
|
||||
|
||||
| Stack | `port_env` | `port_default` | `port_editable` |
|
||||
|-------|------------|----------------|-----------------|
|
||||
| localai | `LOCALAI_PORT` | 8080 | true |
|
||||
| comfyui | `COMFYUI_PORT` | 8188 | true |
|
||||
| vllm | `VLLM_PORT` | 8000 | true |
|
||||
| npmplus | — | 81 | false |
|
||||
|
||||
**Nowa usługa** — dodaj wpis:
|
||||
|
||||
```yaml
|
||||
- id: myservice
|
||||
name: My Service
|
||||
compose_dir: myservice
|
||||
profile: myservice
|
||||
container: myservice
|
||||
ui_port: 9000 # fallback gdy brak w .env
|
||||
port_env: MYSERVICE_PORT
|
||||
port_default: 9000
|
||||
port_editable: true
|
||||
gpu: false
|
||||
```
|
||||
|
||||
W `docker-compose.yml` stacku: `"${MYSERVICE_PORT:-9000}:9000"`.
|
||||
|
||||
---
|
||||
|
||||
## 4. API
|
||||
|
||||
### `GET /api/stacks`
|
||||
|
||||
Każdy stack zawiera dodatkowo:
|
||||
|
||||
```json
|
||||
{
|
||||
"ui_port": 8070,
|
||||
"port_env": "LOCALAI_PORT",
|
||||
"port_editable": true,
|
||||
"port_default": 8080,
|
||||
"published_port": 8070,
|
||||
"port_pending_restart": false
|
||||
}
|
||||
```
|
||||
|
||||
`port_pending_restart`: kontener działa, ale opublikowany port ≠ wartość w `.env`.
|
||||
|
||||
### `PATCH /api/stacks/{stack_id}/port`
|
||||
|
||||
**Auth:** `X-API-Key` (jak start/stop)
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{ "port": 8070, "recreate": true }
|
||||
```
|
||||
|
||||
**Odpowiedź:**
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"stack_id": "localai",
|
||||
"port": 8070,
|
||||
"port_env": "LOCALAI_PORT",
|
||||
"requires_restart": false,
|
||||
"recreated": true,
|
||||
"running": true
|
||||
}
|
||||
```
|
||||
|
||||
**Błędy:**
|
||||
- `400` — stack bez edycji portu (npmplus)
|
||||
- `409` — port zajęty / poza zakresem 1024–65535
|
||||
- `500` — błąd docker compose
|
||||
|
||||
**Zarezerwowane porty:** 80, 443, 8090 (gpu-fan), 18090 (gpu-fan agent), `SERVER_UI_PORT` (8091).
|
||||
|
||||
---
|
||||
|
||||
## 5. Pliki zmienione
|
||||
|
||||
| Plik | Zmiana |
|
||||
|------|--------|
|
||||
| `stacks/server-ui/stacks.yaml` | `port_env`, `port_default`, `port_editable` |
|
||||
| `stacks/server-ui/compose_runner.py` | read/write `.env`, walidacja, recreate |
|
||||
| `stacks/server-ui/app.py` | `PATCH /api/stacks/{id}/port` |
|
||||
| `stacks/server-ui/static/index.html` | input portu w kartach stacków |
|
||||
|
||||
---
|
||||
|
||||
## 6. Weryfikacja
|
||||
|
||||
```bash
|
||||
cd ~/cursor/ubuntu-bare-metal/stacks/server-ui
|
||||
|
||||
# Lista stacków z portami
|
||||
curl -s http://127.0.0.1:8091/api/stacks | python3 -m json.tool
|
||||
|
||||
# Zmiana portu (wymaga API_KEY z .env)
|
||||
curl -s -X PATCH http://127.0.0.1:8091/api/stacks/localai/port \
|
||||
-H "X-API-Key: $API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"port":8070,"recreate":true}'
|
||||
|
||||
grep LOCALAI_PORT ../localai/.env
|
||||
```
|
||||
|
||||
**UI:** zakładka Stacki → karta LocalAI → pole portu → **Zapisz port** → link „Otwórz” się aktualizuje.
|
||||
|
||||
**Prod:** `sudo scripts/install.sh && sudo systemctl restart server-ui`
|
||||
|
||||
---
|
||||
|
||||
## 7. Uwagi operacyjne
|
||||
|
||||
- Po zmianie `LOCALAI_PORT` zaktualizuj **upstream w NPMPlus** ręcznie (proxy host → nowy port).
|
||||
- `docker compose restart` **nie** zmienia mapowania portów — wymagany recreate (`recreate: true` w API).
|
||||
- NPMPlus (`network_mode: host`) — port 81 tylko do odczytu w UI.
|
||||
|
||||
---
|
||||
|
||||
## 8. Checklist wdrożenia
|
||||
|
||||
- [x] Metadane portów w `stacks.yaml`
|
||||
- [x] Backend: odczyt/zapis `.env`, walidacja, recreate
|
||||
- [x] API `PATCH /port`
|
||||
- [x] UI: input + Zapisz w kartach
|
||||
- [x] NPMPlus read-only
|
||||
- [ ] `install.sh` + restart server-ui na produkcji
|
||||
- [ ] Test zmiany portu LocalAI na hoście
|
||||
Reference in New Issue
Block a user