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

8.5 KiB
Raw Permalink Blame History

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/.envsetup-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ł:

# 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

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.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