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>
8.5 KiB
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, 3–7 punktów) |
manual |
Stała prędkość 30–100% |
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 wserver-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ł:
# 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-smidziałasudo scripts/install.shz katalogustacks/gpu-fansudo scripts/enable-lan.shjeśli dostęp z LANsudo systemctl enable --now gpu-fancurl -s http://127.0.0.1:18090/api/status -H "X-API-Key: $(grep ^API_KEY= /opt/control-plane/.env | cut -d= -f2)"→ JSON ztemperature_c
Po zmianie kodu
sudo scripts/install.sh && sudo systemctl restart gpu-fan
Diagnostyka
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.shi 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 |