Files
tomasz-syn-grzegorza 359afb3a59 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>
2026-07-05 12:02:04 +00:00

229 lines
8.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GPU Fan — Docker vs host (raport techniczny)
**Data:** 2026-07-04
**Stack:** `stacks/gpu-fan/`
**Host docelowy:** gmktec-k11, RTX 3090 Ti, Ubuntu headless
---
## 1. Executive summary
**GPU Fan musi działać na hoście jako usługa systemd (root), nie w Dockerze.**
Aplikacja steruje wentylatorami karty NVIDIA przez zapis do NVML (`nvmlDeviceSetFanSpeed_v2`, `nvmlDeviceSetFanControlPolicy`). Na kartach GeForce wymaga to uprawnień root i bezpośredniego dostępu do sterownika hosta. Repo nie zawiera Dockerfile ani compose dla tego stacku — jedyny wspierany model to `sudo scripts/install.sh``/opt/gpu-fan` + `gpu-fan.service`.
Docker jest teoretycznie możliwy (privileged container, host network, mount `/dev/nvidia*`), ale kruchy, nieutrzymywany i niezgodny z architekturą ubuntu-bare-metal (gpu-fan jako daemon sprzętowy obok workloadów AI w kontenerach).
---
## 2. Co robi aplikacja
| Komponent | Plik | Rola |
|-----------|------|------|
| Pętla sterowania | `fan_controller.py` | Odczyt temp/mocy, interpolacja krzywej, zapis prędkości wentylatorów |
| Web UI + API | `app.py` | FastAPI na porcie **8090**, wątek daemon NVML |
| UI statyczne | `static/index.html` | Wykres krzywej, status live, edycja trybu |
| Krzywa | `/etc/gpu-fan/curve.json` | Mapowanie temp °C → speed % |
### Tryby pracy
| Tryb | Zachowanie |
|------|------------|
| `curve` | Prędkość z krzywej JSON (interpolacja liniowa, 37 punktów) |
| `manual` | Stała prędkość 30100% |
| `auto` | Przywraca politykę drivera NVIDIA (`NVML_FAN_POLICY_TEMPERATURE_CONTINOUS_SW`) |
### API (port 8090)
| Endpoint | Metoda | Uwagi |
|----------|--------|-------|
| `/` | GET | Web UI |
| `/api/status` | GET | Metryki GPU + tryb |
| `/api/curve` | GET/PUT | Odczyt/zapis krzywej |
| `/api/mode` | POST | Zmiana trybu |
| `/api/reload` | POST | Przeładowanie `curve.json` (jak SIGHUP) |
Nagłówek `X-API-Key` wymagany gdy `GPU_FAN_HOST` ≠ localhost (domyślnie LAN bind `0.0.0.0`).
### Shutdown
Przy `SIGTERM` / `SIGINT` kontroler wywołuje `_restore_auto_policy()` przed `nvmlShutdown()` — wentylatory nie zostają w trybie manual po zatrzymaniu usługi.
---
## 3. Zależności sprzętowe i software
| Zależność | Wymagana | Uwagi |
|-----------|----------|-------|
| NVIDIA driver ≥ 520 | Tak | Testowane: 595-server-open |
| `nvidia-ml-py` (pynvml) | Tak | Jedyny interfejs sterowania w kodzie |
| `nvidia-smi` | Nie w kodzie | Tylko weryfikacja w dokumentacji; **nie ustawia** wentylatorów |
| Root (euid 0) | Tak | `app.py` kończy się błędem bez root (chyba że `DRY_RUN=true`) |
| `nvidia-persistenced` | Zalecane | `gpu-fan.service` After=/Wants= |
| IPMI | Nie | Brak referencji w kodzie |
| D-Bus | Nie | Brak referencji |
| X11 / nvidia-settings | Nie | Headless — celowo unikane |
| Python 3 + venv | Tak | FastAPI, uvicorn |
### Ścieżki produkcyjne
| Ścieżka | Zawartość |
|---------|-----------|
| `/opt/gpu-fan/` | Kod aplikacji (rsync z repo przez `install.sh`) |
| `/opt/control-plane/.env` | `API_KEY`, `GPU_FAN_API_*`, `CURVE_PATH`, … |
| `/etc/gpu-fan/curve.json` | Krzywa temp → speed |
| `/etc/systemd/system/gpu-fan.service` | Unit systemd |
**Uwaga:** `stacks/control-plane/.env` w repo ≠ `/opt/control-plane/.env``setup-control-plane-env.sh` migruje i synchronizuje.
---
## 4. Obecny model wdrożenia
```
repo stacks/gpu-fan/
│ sudo scripts/install.sh
/opt/gpu-fan/ ← kod + .venv + .env
/etc/gpu-fan/curve.json
/etc/systemd/system/gpu-fan.service
│ systemctl enable --now gpu-fan
Proces root: python app.py
├── wątek: fan_controller.run_loop() (co POLL_INTERVAL s)
└── uvicorn: 0.0.0.0:8090
```
Skrypty pomocnicze:
| Skrypt | Cel |
|--------|-----|
| `scripts/install.sh` | Instalacja produkcyjna |
| `scripts/enable-lan.sh` | `GPU_FAN_HOST=0.0.0.0`, API_KEY, restart |
| `scripts/start.sh` | Foreground debug (wymaga stop systemd) |
| `scripts/status.sh` | Diagnostyka portu/procesu |
| `scripts/self-test.sh` | Test krzywej, NVML read, API dry-run |
---
## 5. Analiza Docker — dlaczego nie
### Brak artefaktów w repo
- Brak `Dockerfile`, `compose.yaml`, profilu w `server-ui/stacks.yaml`
- Inne stacki GPU (ComfyUI, LocalAI, vLLM) używają Docker; gpu-fan jest wyjątkiem celowym
### Blokery techniczne
| Bloker | Szczegóły |
|--------|-----------|
| NVML write na GeForce | `nvmlDeviceSetFanSpeed_v2` wymaga root; kontenery GPU (`NVIDIA_DRIVER_CAPABILITIES=compute,utility`) nie gwarantują zapisu fan policy |
| Coupling do host driver | Wersja NVML w kontenerze musi pasować do kernel drivera hosta |
| Lifecycle | `docker kill` / crash kontenera może pominąć `_restore_auto_policy()` → wentylatory w manual |
| `nvidia-persistenced` | Daemon na hoście; kontener nie zarządza persystencją GPU |
| Privileged + host network | Minimalny „Docker” wyglądałby jak host install z dodatkową warstwą — bez korzyści |
### Hipotetyczny kontener (nie implementować)
Gdyby ktoś eksperymentował:
```yaml
# NIE WDRAŻAĆ — tylko dokumentacja ryzyka
privileged: true
network_mode: host
user: root
pid: host # opcjonalnie, nadal ryzykowne
volumes:
- /etc/gpu-fan:/etc/gpu-fan
devices:
- /dev/nvidia0
- /dev/nvidiactl
- /dev/nvidia-uvm
```
Nawet wtedy sukces nie jest gwarantowany na RTX 3090 Ti; repo nie będzie tego utrzymywać.
---
## 6. Współistnienie z Docker AI stacks
```
┌─────────────────────────────────────────────────┐
│ Host (gmktec-k11) │
│ │
│ gpu-fan.service (root, :8090) ──NVML──► GPU │
│ │
│ ┌─────────────┐ ┌──────────┐ ┌──────────┐ │
│ │ comfyui │ │ localai │ │ vllm │ │
│ │ :8188 │ │ :8070 │ │ :8000 │ │
│ └─────────────┘ └──────────┘ └──────────┘ │
│ Docker containers (GPU compute) │
└─────────────────────────────────────────────────┘
```
- ComfyUI/LocalAI obciążają GPU → temperatura rośnie → gpu-fan reaguje krzywą
- Zatrzymaj gpu-fan **nie** jest wymagane przed startem kontenerów AI
- Polityka GPU w Server UI (jeden duży workload) dotyczy LLM/SD, nie gpu-fan
- Firewall (NPMPlus): port 8090 nie powinien być publiczny; LAN + API key
Źródło: `manual-tutorial/06-gpu-fan-control.md` — „gpu-fan.service na hoście (NVML, root)”.
---
## 7. Checklist operacyjny (coding-agent)
### Instalacja / upgrade
- [ ] `nvidia-smi` działa
- [ ] `sudo scripts/install.sh` z katalogu `stacks/gpu-fan`
- [ ] `sudo scripts/enable-lan.sh` jeśli dostęp z LAN
- [ ] `sudo systemctl enable --now gpu-fan`
- [ ] `curl -s http://127.0.0.1:18090/api/status -H "X-API-Key: $(grep ^API_KEY= /opt/control-plane/.env | cut -d= -f2)"` → JSON z `temperature_c`
### Po zmianie kodu
```bash
sudo scripts/install.sh && sudo systemctl restart gpu-fan
```
### Diagnostyka
```bash
systemctl status gpu-fan
journalctl -u gpu-fan -f
scripts/status.sh
sudo scripts/status.sh --cleanup # tylko gdy port zajęty przez osierocony proces
```
### Czego nie robić
- Nie uruchamiać `start.sh` i systemd jednocześnie (port 8090)
- Nie pakować gpu-fan do Docker bez nowego ADR i testów na sprzęcie
- Nie edytować tylko `stacks/control-plane/.env` — produkcja czyta `/opt/control-plane/.env`
---
## 8. Rekomendacja
| Decyzja | Uzasadnienie |
|---------|--------------|
| **Zostaw na hoście (systemd)** | Wspierane, przetestowane, bezpieczny shutdown, zgodne z tutorial 06 |
| **Nie dodawaj Docker** | Brak wartości, wysokie ryzyko, duplikacja root access |
| **Dokumentacja użytkownika** | `docs/` — kroki instalacji i troubleshooting |
| **Ten raport** | `coding-agent/DOCKER-VS-HOST-REPORT.md` — odniesienie dla agentów |
---
## 9. Pliki źródłowe (indeks)
| Plik | Kluczowe fragmenty |
|------|-------------------|
| `app.py:161-164` | Wymóg root |
| `fan_controller.py:250-279` | NVML fan policy + speed write |
| `fan_controller.py:335-343` | Shutdown → auto policy |
| `gpu-fan.service` | User=root, After=nvidia-persistenced |
| `scripts/install.sh` | rsync → /opt/gpu-fan |
| `requirements.txt` | fastapi, uvicorn, nvidia-ml-py |