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,356 @@
|
||||
# 06 — Sterowanie wentylatorami GPU
|
||||
|
||||
> **Cel rozdziału:** skonfigurować sterowanie wentylatorami RTX 3090 Ti na headless serwerze — krzywa temp → prędkość, web UI w sieci lokalnej, usługa systemd.
|
||||
|
||||
**Szacowany czas:** 15–20 minut
|
||||
|
||||
**Wymagania:** ukończony rozdział [02 — Sterowniki NVIDIA](02-nvidia-driver.md) (`nvidia-smi` działa)
|
||||
|
||||
---
|
||||
|
||||
## Spis treści
|
||||
|
||||
1. [Dlaczego własny stack](#1-dlaczego-własny-stack)
|
||||
2. [Weryfikacja punktu startowego](#2-weryfikacja-punktu-startowego)
|
||||
3. [Instalacja](#3-instalacja)
|
||||
4. [Web UI w sieci lokalnej](#4-web-ui-w-sieci-lokalnej)
|
||||
5. [Krzywa max cooling](#5-krzywa-max-cooling)
|
||||
6. [Zarządzanie usługą](#6-zarządzanie-usługą)
|
||||
7. [Weryfikacja pod obciążeniem](#7-weryfikacja-pod-obciążeniem)
|
||||
8. [Troubleshooting](#8-troubleshooting)
|
||||
9. [Następny krok](#9-następny-krok)
|
||||
|
||||
---
|
||||
|
||||
## 1. Dlaczego własny stack
|
||||
|
||||
Na headless Ubuntu **nie działają** narzędzia oparte na `nvidia-settings` + CoolBits (wymagają display servera).
|
||||
|
||||
Od sterownika NVIDIA **520+** sterowanie wentylatorami GeForce jest dostępne przez **NVML** — działa bez monitora i bez X11.
|
||||
|
||||
Stack [`stacks/gpu-fan/`](../stacks/gpu-fan/):
|
||||
|
||||
- daemon NVML (Python + `pynvml`)
|
||||
- web UI do edycji krzywej
|
||||
- preset agresywny pod długie obciążenie LocalAI / vLLM
|
||||
|
||||
`nvidia-smi` pokazuje tylko odczyty — **nie ustawia** prędkości wentylatorów.
|
||||
|
||||
---
|
||||
|
||||
## 2. Weryfikacja punktu startowego
|
||||
|
||||
```bash
|
||||
nvidia-smi --query-gpu=name,driver_version,temperature.gpu,fan.speed --format=csv,noheader
|
||||
|
||||
# Oczekiwane:
|
||||
# NVIDIA GeForce RTX 3090 Ti, 595.x, <temp>, <fan> %
|
||||
```
|
||||
|
||||
```bash
|
||||
python3 -c "import pynvml; pynvml.nvmlInit(); h=pynvml.nvmlDeviceGetHandleByIndex(0); print(pynvml.nvmlDeviceGetName(h)); pynvml.nvmlShutdown()"
|
||||
```
|
||||
|
||||
Jeśli `ModuleNotFoundError: pynvml` — `install.sh` doinstaluje zależności. Możesz też:
|
||||
|
||||
```bash
|
||||
sudo apt install -y python3-pynvml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Instalacja
|
||||
|
||||
Z katalogu repozytorium na serwerze:
|
||||
|
||||
```bash
|
||||
cd ~/cursor/ubuntu-bare-metal/stacks/gpu-fan
|
||||
|
||||
cp .env.example .env
|
||||
# opcjonalnie: edytuj GPU_FAN_PORT, API_KEY
|
||||
|
||||
sudo scripts/install.sh
|
||||
sudo scripts/enable-lan.sh
|
||||
sudo systemctl status gpu-fan
|
||||
```
|
||||
|
||||
**Co robi `install.sh`:**
|
||||
|
||||
| Krok | Efekt |
|
||||
|------|-------|
|
||||
| `apt install python3-venv` | Środowisko Python |
|
||||
| Kopiuje pliki do `/opt/gpu-fan` | Kod aplikacji |
|
||||
| Tworzy `/etc/gpu-fan/curve.json` | Domyślna krzywa max cooling |
|
||||
| `systemctl enable gpu-fan` | Start przy bootcie |
|
||||
|
||||
Logi:
|
||||
|
||||
```bash
|
||||
journalctl -u gpu-fan -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Web UI w sieci lokalnej
|
||||
|
||||
Domyślnie UI nasłuchuje na **0.0.0.0:8090** — dostępne z każdego urządzenia w LAN.
|
||||
|
||||
```bash
|
||||
# IP serwera
|
||||
hostname -I | awk '{print $1}'
|
||||
|
||||
# API key
|
||||
grep ^API_KEY= /opt/control-plane/.env
|
||||
```
|
||||
|
||||
W przeglądarce na laptopie / telefonie w tej samej sieci:
|
||||
|
||||
```
|
||||
http://192.168.100.5:8090/?api_key=TWÓJ_KLUCZ_Z_.env
|
||||
```
|
||||
|
||||
Klucz można też podać w promptcie UI przy pierwszym wejściu (bez `?api_key=` w URL).
|
||||
|
||||
### Tylko localhost (opcjonalnie)
|
||||
|
||||
W `/opt/control-plane/.env`:
|
||||
|
||||
```bash
|
||||
GPU_FAN_HOST=127.0.0.1
|
||||
API_KEY=
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl restart gpu-fan
|
||||
```
|
||||
|
||||
Dostęp przez SSH tunnel:
|
||||
|
||||
```bash
|
||||
ssh -L 8090:127.0.0.1:8090 tomasz-syn-grzegorza@gmktec-k11
|
||||
```
|
||||
|
||||
Otwórz: **http://localhost:8090**
|
||||
|
||||
### Funkcje UI
|
||||
|
||||
- Wykres krzywej — przeciąganie punktów; podziałka temperatury (°C) i prędkości (%), siatka pomocnicza i linijki z kreskami na zewnętrznych krawędziach osi
|
||||
- Tabela temp / speed
|
||||
- Status live: temperatura, wentylatory, moc, wykorzystanie GPU
|
||||
- **Zapisz krzywą** — zapis do `/etc/gpu-fan/curve.json`
|
||||
- **Tryb auto** — oddaje sterowanie driverowi NVIDIA
|
||||
- **Manual 100%** — awaryjne pełne obroty
|
||||
|
||||
### API key
|
||||
|
||||
Przy dostępie z LAN **API_KEY jest wymagany** (generowany przy `install.sh` lub ustaw ręcznie w `.env`):
|
||||
|
||||
```bash
|
||||
sudo nano /opt/control-plane/.env
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl restart gpu-fan
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Krzywa max cooling
|
||||
|
||||
Domyślny plik `/etc/gpu-fan/curve.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"30": 50,
|
||||
"40": 65,
|
||||
"50": 80,
|
||||
"55": 90,
|
||||
"60": 100,
|
||||
"70": 100
|
||||
}
|
||||
```
|
||||
|
||||
Edycja ręczna:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/gpu-fan/curve.json
|
||||
sudo systemctl reload gpu-fan
|
||||
```
|
||||
|
||||
### Ograniczenia API NVIDIA
|
||||
|
||||
| Wartość | Znaczenie |
|
||||
|---------|-----------|
|
||||
| 0% | Oddaj sterowanie driverowi (auto) |
|
||||
| 1–29% | **Niedozwolone** przez API |
|
||||
| 30–100% | Dozwolone w trybie manual |
|
||||
|
||||
RTX 3090 Ti w trybie **auto** może mieć **0 RPM** przy niskiej temperaturze — to normalne zachowanie karty.
|
||||
|
||||
---
|
||||
|
||||
## 6. Zarządzanie usługą
|
||||
|
||||
```bash
|
||||
sudo systemctl start gpu-fan # start
|
||||
sudo systemctl stop gpu-fan # stop + przywrócenie auto
|
||||
sudo systemctl restart gpu-fan # restart
|
||||
sudo systemctl reload gpu-fan # przeładuj curve.json (SIGHUP)
|
||||
```
|
||||
|
||||
Test API z serwera:
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:8090/api/status | python3 -m json.tool
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://127.0.0.1:8090/api/mode \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"mode":"manual","speed":100}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://127.0.0.1:8090/api/mode \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"mode":"auto"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Weryfikacja pod obciążeniem
|
||||
|
||||
### 7.1 Idle
|
||||
|
||||
```bash
|
||||
watch -n2 'curl -s http://127.0.0.1:8090/api/status | python3 -m json.tool'
|
||||
```
|
||||
|
||||
W trybie `curve` przy ~40°C oczekuj target_speed zgodnego z krzywą (np. ~50–65%).
|
||||
|
||||
### 7.2 Obciążenie GPU
|
||||
|
||||
Uruchom inference (LocalAI lub vLLM), np.:
|
||||
|
||||
```bash
|
||||
# LocalAI (jeśli działa)
|
||||
curl -s http://localhost:8070/v1/models
|
||||
|
||||
# lub krótki stress (opcjonalnie, wymaga cuda w kontenerze)
|
||||
# docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi dmon -s puc -d 1 -c 30
|
||||
```
|
||||
|
||||
Obserwuj w UI lub przez API:
|
||||
|
||||
- `temperature_c` rośnie pod loadem
|
||||
- `target_speed_pct` podąża za krzywą
|
||||
- `fan_speeds_pct` dążą do `target_speed_pct`
|
||||
|
||||
### 7.3 Graceful shutdown
|
||||
|
||||
```bash
|
||||
sudo systemctl stop gpu-fan
|
||||
nvidia-smi --query-gpu=fan.speed --format=csv,noheader
|
||||
```
|
||||
|
||||
Po stopie usługi wentylatory powinny wrócić do polityki drivera (auto).
|
||||
|
||||
### Checklist
|
||||
|
||||
- [ ] `systemctl status gpu-fan` — active (running)
|
||||
- [ ] Web UI dostępne z LAN (`http://<ip>:8090`)
|
||||
- [ ] Zapis krzywej w UI działa
|
||||
- [ ] Pod loadem temp rośnie, wentylatory przyspieszają
|
||||
- [ ] Po `stop` — tryb auto drivera
|
||||
|
||||
---
|
||||
|
||||
## 8. Troubleshooting
|
||||
|
||||
### 8.1 `Insufficient Permissions`
|
||||
|
||||
Sterowanie wentylatorami wymaga **root**. Uruchamiaj przez systemd lub `sudo scripts/start.sh`.
|
||||
|
||||
### 8.2 `Failed to initialize NVML: Driver/library version mismatch`
|
||||
|
||||
Po aktualizacji kernela lub sterownika:
|
||||
|
||||
```bash
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
### 8.3 Wentylatory nie schodzą poniżej 30%
|
||||
|
||||
To ograniczenie API NVIDIA w trybie manual — nie błąd aplikacji. Dla ciszy przy idle użyj **Tryb auto** w UI.
|
||||
|
||||
### 8.4 Port 8090 zajęty / `address already in use`
|
||||
|
||||
**Nie zmieniaj portu na 8091, 8092…** — to tylko maskuje problem. Przy kolejnym podwójnym starcie następny port też będzie zajęty.
|
||||
|
||||
Diagnostyka:
|
||||
|
||||
```bash
|
||||
cd ~/cursor/ubuntu-bare-metal/stacks/gpu-fan
|
||||
scripts/status.sh
|
||||
sudo ss -tlnp | grep -E ':809[0-9]'
|
||||
jobs -l # zawieszone Ctrl+Z w tej sesji SSH
|
||||
```
|
||||
|
||||
Czyszczenie:
|
||||
|
||||
```bash
|
||||
sudo scripts/status.sh --cleanup
|
||||
sudo systemctl start gpu-fan
|
||||
```
|
||||
|
||||
Typowe przyczyny:
|
||||
|
||||
| Objaw | Przyczyna | Rozwiązanie |
|
||||
|-------|-----------|-------------|
|
||||
| Błąd po `systemctl restart` + `start.sh` | Dwie instancje | Używaj **albo** systemd **albo** `start.sh` |
|
||||
| `[n]+ Stopped start.sh` w terminalu | Ctrl+Z zamiast Ctrl+C | `kill %n` lub `sudo scripts/status.sh --cleanup` |
|
||||
| Port zajęty po reboot | `gpu-fan.service` włączone (`enable`) | Normalne — nie uruchamiaj drugiej kopii |
|
||||
| Zmiana portu w repo `.env` bez efektu | Produkcja czyta `/opt/control-plane/.env` | Edytuj `/opt/control-plane/.env` lub uruchom `setup-control-plane-env.sh` |
|
||||
|
||||
Po zmianach w kodzie UI (np. monitoring GPU):
|
||||
|
||||
```bash
|
||||
sudo scripts/install.sh && sudo systemctl restart gpu-fan
|
||||
```
|
||||
|
||||
Foreground debug (tylko gdy systemd zatrzymany):
|
||||
|
||||
```bash
|
||||
sudo systemctl stop gpu-fan
|
||||
sudo scripts/start.sh
|
||||
# Zakończ: Ctrl+C (nie Ctrl+Z!)
|
||||
```
|
||||
|
||||
### 8.5 Krzywa odrzucona (400)
|
||||
|
||||
- 3–7 punktów
|
||||
- temperatury rosnąco, unikalne
|
||||
- prędkość: 0 lub 30–100
|
||||
|
||||
---
|
||||
|
||||
## 9. Następny krok
|
||||
|
||||
Po przejściu checklisty:
|
||||
|
||||
1. Zostaw `gpu-fan` włączony przy workloadach AI (LocalAI, ComfyUI, vLLM).
|
||||
2. Rozdział **07 — ComfyUI stack** — generowanie obrazów w Dockerze.
|
||||
3. Rozważ `API_KEY` przed ewentualnym wystawieniem portu w rozdziale firewall (08).
|
||||
|
||||
Powrót do roadmapy: [README.md](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Podsumowanie
|
||||
|
||||
Po ukończeniu rozdziału:
|
||||
|
||||
- Działa `gpu-fan.service` na hoście (NVML, root)
|
||||
- Krzywa w `/etc/gpu-fan/curve.json`
|
||||
- Web UI na **0.0.0.0:8090** (dostęp z sieci lokalnej, z API key)
|
||||
- Stop usługi przywraca auto drivera NVIDIA
|
||||
Reference in New Issue
Block a user