359afb3a59
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>
155 lines
4.3 KiB
Markdown
155 lines
4.3 KiB
Markdown
# GPU Fan Control stack
|
||
|
||
Sterowanie wentylatorami **RTX 3090 Ti** na headless Ubuntu przez NVML — bez `nvidia-settings` i bez GUI.
|
||
|
||
**Panel webowy** jest w **Server UI** (`http://<host>:8091` → zakładka **GPU Fan**). Ten stack uruchamia tylko **agenta API** na localhost.
|
||
|
||
## Porty
|
||
|
||
| Serwis | Port | Dostęp |
|
||
|--------|------|--------|
|
||
| GPU Fan agent API | **18090** | `127.0.0.1` tylko (systemd, root) |
|
||
| GPU Fan UI | — | Server UI **:8091** (zakładka GPU Fan) |
|
||
|
||
Port **8090** nie jest już używany w produkcji.
|
||
|
||
## Jak to działa
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
browser["Przeglądarka :8091"]
|
||
serverUI["server-ui"]
|
||
agent["fan_daemon.py :18090"]
|
||
nvml["NVML / pynvml"]
|
||
gpu["RTX 3090 Ti"]
|
||
|
||
browser --> serverUI
|
||
serverUI -->|"proxy /api/gpu-fan"| agent
|
||
agent --> nvml
|
||
nvml --> gpu
|
||
```
|
||
|
||
| Element | Opis |
|
||
|---------|------|
|
||
| Agent | `fan_daemon.py` — pętla NVML + API REST |
|
||
| Dev UI | `app.py` — monolit z UI (tylko dev / DRY_RUN) |
|
||
| Logika | `fan_controller.py` — interpolacja krzywej |
|
||
| Konfiguracja | `/etc/gpu-fan/curve.json` |
|
||
| systemd | `gpu-fan.service` (root, auto-restart) |
|
||
|
||
## Wymagania
|
||
|
||
- Sterownik NVIDIA ≥ 520 (testowane: **595-server-open**)
|
||
- Root / sudo (zapis NVML wymaga uprawnień root)
|
||
- Python 3 + venv (instalowane przez `install.sh`)
|
||
- **Server UI** na :8091 (proxy do agenta)
|
||
|
||
## Szybki start
|
||
|
||
```bash
|
||
cd stacks/gpu-fan
|
||
cp ../control-plane/.env.example ../control-plane/.env
|
||
|
||
sudo scripts/install.sh
|
||
sudo systemctl start gpu-fan
|
||
|
||
cd ../server-ui
|
||
sudo scripts/install.sh
|
||
```
|
||
|
||
Panel: `http://<IP-serwera>:8091` → zakładka **GPU Fan**.
|
||
|
||
Po zmianach w kodzie:
|
||
|
||
```bash
|
||
sudo scripts/install.sh && sudo systemctl restart gpu-fan
|
||
cd ../server-ui && sudo scripts/install.sh && sudo systemctl restart server-ui
|
||
```
|
||
|
||
Konfiguracja: produkcja `/opt/control-plane/.env`, dev `stacks/control-plane/.env`.
|
||
|
||
### Klucz API
|
||
|
||
Jeden wspólny `API_KEY` w `/opt/control-plane/.env` — auth panelu Server UI i agenta gpu-fan (proxy `/api/gpu-fan/*`).
|
||
|
||
W panelu Server UI wpisz ten sam klucz w polu **API Key** (lub `?api_key=...` w URL).
|
||
|
||
## Preset max cooling
|
||
|
||
Domyślna krzywa w [`curve.default.json`](curve.default.json):
|
||
|
||
| Temp | Speed |
|
||
|------|-------|
|
||
| 30°C | 50% |
|
||
| 40°C | 65% |
|
||
| 50°C | 80% |
|
||
| 55°C | 90% |
|
||
| 60°C | 100% |
|
||
| 70°C+ | 100% |
|
||
|
||
## Tryby
|
||
|
||
| Tryb | Opis |
|
||
|------|------|
|
||
| `curve` | Krzywa z JSON — interpolacja liniowa |
|
||
| `manual` | Stała prędkość (np. 100% awaryjnie) |
|
||
| `auto` | Oddaje sterowanie driverowi NVIDIA |
|
||
|
||
## API agenta (localhost :18090)
|
||
|
||
| Endpoint | Metoda | Opis |
|
||
|----------|--------|------|
|
||
| `/api/status` | GET | Temperatura, wentylatory, moc, tryb |
|
||
| `/api/curve` | GET/PUT | Odczyt / zapis krzywej |
|
||
| `/api/mode` | POST | `{"mode":"auto\|curve\|manual","speed":100}` |
|
||
| `/api/reload` | POST | Przeładuj `curve.json` (jak `SIGHUP`) |
|
||
|
||
Z LAN używaj proxy Server UI: `/api/gpu-fan/status`, `/api/gpu-fan/curve`, itd.
|
||
|
||
## Ograniczenia NVIDIA
|
||
|
||
- `nvidia-smi` **nie steruje** wentylatorami — tylko odczyt
|
||
- API akceptuje **0%** (= auto) lub **30–100%**
|
||
- Po `systemctl stop gpu-fan` wentylatory wracają do trybu auto drivera
|
||
|
||
## Struktura
|
||
|
||
```
|
||
stacks/gpu-fan/
|
||
├── README.md
|
||
├── fan_daemon.py # produkcja — agent API
|
||
├── app.py # dev — UI + API (opcjonalnie)
|
||
├── fan_controller.py
|
||
├── curve.default.json
|
||
├── requirements.txt
|
||
├── gpu-fan.service
|
||
├── .env.example
|
||
├── static/index.html # referencja UI (wbudowane w server-ui)
|
||
└── scripts/
|
||
├── install.sh
|
||
├── enable-lan.sh # konfiguruje agent + wskazówka :8091
|
||
└── status.sh
|
||
```
|
||
|
||
## Troubleshooting
|
||
|
||
**`Insufficient Permissions`** — uruchom jako root (`sudo systemctl start gpu-fan`).
|
||
|
||
**Panel GPU Fan pusty / 502** — sprawdź agent: `curl -s http://127.0.0.1:18090/api/status -H "X-API-Key: ..."`
|
||
|
||
**Port 18090 zajęty** — `scripts/status.sh` / `sudo scripts/status.sh --cleanup`
|
||
|
||
**Przeładuj krzywą bez restartu:**
|
||
|
||
```bash
|
||
sudo systemctl reload gpu-fan
|
||
```
|
||
|
||
## Dokumentacja
|
||
|
||
| Dokument | Opis |
|
||
|----------|------|
|
||
| [docs/00-START-TUTAJ.md](docs/00-START-TUTAJ.md) | Mapa — zacznij tutaj |
|
||
| [docs/02-OTWIERANIE-UI-W-PRZEGLADARCE.md](docs/02-OTWIERANIE-UI-W-PRZEGLADARCE.md) | Panel w Server UI :8091 |
|
||
| [docs/05-DLACZEGO-NIE-DOCKER.md](docs/05-DLACZEGO-NIE-DOCKER.md) | Dlaczego host, nie Docker |
|