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:
tomasz-syn-grzegorza
2026-07-05 12:02:04 +00:00
commit 359afb3a59
153 changed files with 18169 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
# 00 — Wymagania i konwencje
> Przeczytaj ten rozdział przed rozpoczęciem pracy. Nie wymaga wykonywania komend na serwerze.
## Cel
Ustalenie wspólnego kontekstu: jaki sprzęt konfigurujemy, jakie są wymagania wstępne i jak czytać kolejne rozdziały tutoriala.
## Sprzęt i system
| Parametr | Wartość |
|----------|---------|
| Hostname | `gmktec-k11` |
| System | Ubuntu 26.04 LTS (`resolute`) |
| Kernel | 7.0.x (aktualizowany przez `apt upgrade`) |
| GPU do AI | NVIDIA GeForce RTX 3090 Ti |
| Użytkownik | `tomasz-syn-grzegorza` (grupa `sudo`) |
## Wymagania wstępne
- Dostęp SSH lub fizyczna konsola do serwera
- Użytkownik z uprawnieniami `sudo`
- Stabilne połączenie internetowe
- Czysta instalacja Ubuntu minimized (bez wcześniejszej konfiguracji serwera)
**Ubuntu minimized** — nie ma edytorów (`nano`/`vim`), `rsync`, `parted`, `jq`. Doinstalowujemy je w rozdziale [03b — Narzędzia bazowe](03b-system-tools.md) przed konfiguracją dysku i vLLM.
## Konwencje w tutorialu
### Język
- **Opisy i wyjaśnienia** — po polsku
- **Komendy, nazwy pakietów, ścieżki, zmienne** — po angielsku (jak w systemie Linux)
### Format komend
```bash
# komentarz — wyjaśnienie co robi komenda
sudo apt update
```
- Komendy z prefiksem `sudo` wymagają uprawnień administratora
- `$USER` oznacza aktualnie zalogowanego użytkownika — nie zamieniaj ręcznie
- Bloki oznaczone **Opcjonalnie** możesz pominąć przy pierwszym przejściu
### Oznaczenia w tekście
| Oznaczenie | Znaczenie |
|------------|-----------|
| **Weryfikacja** | Sprawdź wynik przed przejściem dalej |
| **Troubleshooting** | Rozwiązanie typowych problemów |
| **Uwaga** | Ważna informacja — przeczytaj przed wykonaniem |
| **Następny krok** | Link do kolejnego rozdziału |
### Kolejność rozdziałów
Nie pomijaj rozdziałów i nie zmieniaj kolejności. Każdy etap buduje na poprzednim:
1. Aktualizacja systemu + Docker CE
2. Sterowniki NVIDIA
3. NVIDIA Container Toolkit (GPU w kontenerach)
4. vLLM
5. ComfyUI
6. Firewall i hardening
## Czego NIE instalujemy w kroku 01
W pierwszym rozdziale **świadomie pomijamy**:
- Sterowniki NVIDIA (`nvidia-driver-*`)
- NVIDIA Container Toolkit (`nvidia-ctk`)
- vLLM, ComfyUI i jakiekolwiek compose stacki
- Konfigurację firewalla
Te elementy pojawią się w kolejnych rozdziałach we właściwej kolejności.
## Przydatne komendy diagnostyczne (bez zmian w systemie)
Możesz je uruchomić teraz, żeby potwierdzić punkt startowy:
```bash
# wersja systemu
lsb_release -a
# kernel i architektura
uname -a
# miejsce na dysku
df -h /
# pamięć RAM
free -h
# uprawnienia sudo
groups
# czy Docker jest już zainstalowany (powinno być puste)
which docker
docker --version 2>/dev/null || echo "Docker not installed"
# GPU wykryte przez PCI (sterownik może jeszcze nie być zainstalowany)
lspci | grep -i nvidia
```
Oczekiwany stan przed rozdziałem 01:
- Ubuntu 26.04 LTS
- Użytkownik w grupie `sudo`
- Docker **nie** zainstalowany
- `nvidia-smi` **niedostępne** (to normalne — sterownik w rozdziale 02)
## Następny krok
→ [01 — Aktualizacja systemu i instalacja Docker CE](01-system-update-and-docker.md)
@@ -0,0 +1,474 @@
# 01 — Aktualizacja systemu i instalacja Docker CE
> **Cel rozdziału:** zaktualizować świeży Ubuntu 26.04 LTS i zainstalować Docker Engine z oficjalnego repozytorium Docker Inc. (nie `docker.io` z Ubuntu).
**Szacowany czas:** 1020 minut (zależy od liczby pakietów do aktualizacji)
**Wymagania:** rozdział [00 — Wymagania i konwencje](00-prerequisites.md)
---
## Spis treści
1. [Weryfikacja punktu startowego](#1-weryfikacja-punktu-startowego)
2. [Aktualizacja systemu](#2-aktualizacja-systemu)
3. [Instalacja Docker CE](#3-instalacja-docker-ce)
4. [Konfiguracja post-install](#4-konfiguracja-post-install)
5. [Weryfikacja](#5-weryfikacja)
6. [Troubleshooting](#6-troubleshooting)
7. [Czego nie robimy w tym kroku](#7-czego-nie-robimy-w-tym-kroku)
8. [Następny krok](#8-następny-krok)
---
## 1. Weryfikacja punktu startowego
Przed jakimikolwiek zmianami potwierdź stan systemu. Te komendy **nic nie modyfikują**.
```bash
# wersja Ubuntu — oczekiwane: 26.04, codename: resolute
lsb_release -a
# kernel
uname -r
# wolne miejsce na dysku głównym (minimum ~5 GB na upgrade + Docker)
df -h /
# uprawnienia sudo
groups | grep -q sudo && echo "sudo: OK" || echo "sudo: BRAK — wymagane!"
# Docker nie powinien być jeszcze zainstalowany
docker --version 2>/dev/null || echo "Docker: not installed (expected)"
# GPU widoczne w PCI (sterownik jeszcze niepotrzebny)
lspci | grep -i "nvidia"
```
**Oczekiwany wynik:**
- Ubuntu 26.04 LTS (`resolute`)
- Użytkownik w grupie `sudo`
- Docker niezainstalowany
- NVIDIA RTX 3090 Ti widoczna w `lspci`
**Uwaga:** `nvidia-smi` nie działa na tym etapie — to normalne. Sterowniki instalujemy w rozdziale 02.
---
## 2. Aktualizacja systemu
### 2.1 Aktualizacja list pakietów i upgrade
```bash
sudo apt update
sudo apt upgrade -y
```
Pierwszy pełny upgrade na świeżej instalacji może pobrać setki pakietów — poczekaj na zakończenie.
### 2.2 Instalacja pakietów bazowych
Te pakiety są potrzebne do dodania repozytorium Docker i dalszej konfiguracji serwera:
```bash
sudo apt install -y \
ca-certificates \
curl \
gnupg \
lsb-release \
apt-transport-https \
software-properties-common
```
| Pakiet | Po co |
|--------|-------|
| `ca-certificates` | Weryfikacja certyfikatów HTTPS (repo Docker) |
| `curl` | Pobieranie kluczy GPG i plików z internetu |
| `gnupg` | Weryfikacja podpisów pakietów |
| `lsb-release` | Odczyt wersji Ubuntu (codename `resolute`) |
| `apt-transport-https` | Obsługa repozytoriów HTTPS przez apt |
| `software-properties-common` | Narzędzia do zarządzania repozytoriami |
### 2.3 Sprawdzenie, czy wymagany jest restart
```bash
# jeśli plik istnieje — kernel lub libc wymagają restartu
test -f /var/run/reboot-required && cat /var/run/reboot-required || echo "Restart not required"
```
Jeśli restart jest wymagany:
```bash
sudo reboot
```
Po restarcie zaloguj się ponownie i wróć do tego rozdziału od sekcji 3.
**Uwaga:** Na tym systemie `unattended-upgrades` jest domyślnie aktywny — to dobrze dla bezpieczeństwa. Pierwszy pełny upgrade wykonujemy jednak ręcznie, żeby mieć kontrolę nad procesem.
---
## 3. Instalacja Docker CE
Instalujemy Docker z **oficjalnego repozytorium Docker Inc.**, nie z pakietu `docker.io` dostępnego w repozytoriach Ubuntu. Oficjalne repo daje:
- najnowsze wersje Engine,
- plugin `docker compose` (v2),
- plugin `docker-buildx`,
- bezpośrednią ścieżkę aktualizacji (`apt upgrade`).
Dokumentacja: [Install Docker Engine on Ubuntu](https://docs.docker.com/engine/install/ubuntu/)
### 3.1 Usunięcie konfliktowych pakietów
Jeśli wcześniej nic nie instalowałeś, ten krok nic nie usunie — ale warto go wykonać dla czystości:
```bash
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt remove -y $pkg 2>/dev/null
done
```
### 3.2 Dodanie oficjalnego klucza GPG Docker
```bash
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
```
### 3.3 Dodanie repozytorium Docker (format DEB822)
```bash
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
```
Na Ubuntu 26.04 LTS pole `Suites` powinno wskazywać na `resolute`. Sprawdź:
```bash
grep Suites /etc/apt/sources.list.d/docker.sources
# oczekiwane: Suites: resolute
```
### 3.4 Instalacja pakietów Docker
```bash
sudo apt update
sudo apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
```
| Pakiet | Rola |
|--------|------|
| `docker-ce` | Docker Engine (daemon `dockerd`) |
| `docker-ce-cli` | CLI (`docker` command) |
| `containerd.io` | Niskopoziomowy runtime kontenerów |
| `docker-buildx-plugin` | Nowoczesny builder obrazów (BuildKit) |
| `docker-compose-plugin` | `docker compose` — zarządzanie wieloma kontenerami |
---
## 4. Konfiguracja post-install
### 4.1 Włączenie i uruchomienie usługi Docker
```bash
sudo systemctl enable --now docker
```
Sprawdź status:
```bash
sudo systemctl status docker --no-pager
```
Oczekiwane: `Active: active (running)`
### 4.2 Dodanie użytkownika do grupy `docker`
Bez tego każda komenda `docker` wymaga `sudo`:
```bash
sudo usermod -aG docker $USER
```
**Ważne:** Grupa `docker` zostanie aktywna dopiero po ponownym zalogowaniu. Masz dwie opcje:
**Opcja A — re-logowanie (zalecane):**
```bash
# wyloguj się i zaloguj ponownie przez SSH
exit
```
**Opcja B — tymczasowa aktywacja grupy (bez wylogowania):**
```bash
newgrp docker
```
### 4.3 Konfiguracja rotacji logów
Kontenery vLLM i ComfyUI generują dużo logów. Bez rotacji dysk szybko się zapełni.
```bash
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
}
}
EOF
sudo systemctl restart docker
```
To ogranicza logi każdego kontenera do 3 plików po 50 MB (max ~150 MB na kontener).
### 4.4 Opcjonalnie: live-restore
Jeśli chcesz, żeby kontenery działały podczas restartu daemona Docker (np. przy aktualizacji):
```bash
sudo tee /etc/docker/daemon.json <<'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
},
"live-restore": true
}
EOF
sudo systemctl restart docker
```
**Kompromis:** `live-restore` utrudnia debugowanie i może maskować problemy z daemonem. Na serwerze produkcyjnym zwykle warto — na etapie konfiguracji możesz pominąć.
---
## 5. Weryfikacja
Wykonaj wszystkie punkty. Nie przechodź do rozdziału 02, dopóki każdy nie przejdzie.
### 5.1 Wersje Docker i Compose
```bash
docker --version
docker compose version
```
Oczekiwane: Docker version 29.x (lub nowszy), Compose v2.x jako plugin.
### 5.2 Test hello-world
```bash
docker run --rm hello-world
```
Oczekiwane: komunikat `Hello from Docker!` i `status code: 0`.
Jeśli dostajesz `permission denied` — patrz [Troubleshooting §6.1](#61-permission-denied-na-varrundockersock).
### 5.3 Status usługi
```bash
sudo systemctl is-active docker
sudo systemctl is-enabled docker
```
Oczekiwane: `active` i `enabled`.
### 5.4 Informacje o daemonie
```bash
docker info 2>/dev/null | grep -E 'Server Version|Storage Driver|Cgroup Driver|Logging Driver'
```
Oczekiwane m.in.:
- `Storage Driver: overlay2`
- `Logging Driver: json-file`
### 5.5 Test bez sudo (po re-logowaniu / newgrp)
```bash
docker ps
```
Oczekiwane: pusta lista kontenerów, **bez** błędu uprawnień.
### Checklist
- [ ] `docker --version` działa
- [ ] `docker compose version` działa
- [ ] `docker run --rm hello-world` zakończone sukcesem
- [ ] `systemctl status docker` → active (running)
- [ ] `docker ps` działa bez `sudo`
- [ ] `/etc/docker/daemon.json` istnieje z rotacją logów
---
## 6. Troubleshooting
### 6.1 Permission denied na `/var/run/docker.sock`
```
permission denied while trying to connect to the Docker daemon socket
```
**Przyczyna:** Użytkownik nie jest w grupie `docker` lub nie zalogował się ponownie po `usermod`.
**Rozwiązanie:**
```bash
# sprawdź grupy
groups
# jeśli brak "docker":
sudo usermod -aG docker $USER
newgrp docker # lub wyloguj się i zaloguj ponownie
```
### 6.2 `docker-ce has no installation candidate`
**Przyczyna:** Błędny codename w `/etc/apt/sources.list.d/docker.sources`.
**Rozwiązanie:**
```bash
grep Suites /etc/apt/sources.list.d/docker.sources
# musi być: Suites: resolute
# jeśli inny — usuń i dodaj repo ponownie (sekcja 3.3)
sudo rm /etc/apt/sources.list.d/docker.sources
# ... powtórz kroki 3.2 i 3.3
```
### 6.3 Konflikt z `docker.io`
**Objaw:** apt instaluje `docker.io` zamiast `docker-ce`, lub oba się gryzą.
**Rozwiązanie:**
```bash
sudo apt remove -y docker.io docker-doc docker-compose docker-compose-v2
sudo apt autoremove -y
# powtórz sekcję 3.4
```
### 6.4 Błąd pobierania klucza GPG
```
curl: (6) Could not resolve host: download.docker.com
```
**Przyczyna:** Brak internetu lub problem DNS.
**Rozwiązanie:**
```bash
# test połączenia
ping -c 3 download.docker.com
ping -c 3 8.8.8.8
# sprawdź DNS
cat /etc/resolv.conf
```
### 6.5 Daemon nie startuje po `daemon.json`
**Objaw:** `systemctl status docker` → failed.
**Przyczyna:** Błędny JSON w `/etc/docker/daemon.json`.
**Rozwiązanie:**
```bash
# walidacja JSON
python3 -m json.tool /etc/docker/daemon.json
# jeśli błąd składni — przywróć minimalną konfigurację:
sudo tee /etc/docker/daemon.json <<'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
}
}
EOF
sudo systemctl restart docker
```
### 6.6 `hello-world` — image pull failed
```bash
# test dostępu do Docker Hub
docker pull hello-world
# sprawdź logi daemona
sudo journalctl -u docker --no-pager -n 50
```
---
## 7. Czego nie robimy w tym kroku
Świadomie **pomijamy** — pojawią się w kolejnych rozdziałach:
| Element | Rozdział |
|---------|----------|
| Sterowniki NVIDIA (`nvidia-driver-*`) | 02 |
| `nvidia-smi`, CUDA toolkit | 02 |
| NVIDIA Container Toolkit (`nvidia-ctk`) | 03 |
| GPU w kontenerach (`--gpus all`) | 03 |
| vLLM | 04 |
| ComfyUI | 05 |
| UFW / firewall / fail2ban | 06 |
| Katalog `/data` na modele | później |
Docker zainstalowany w tym rozdziale **nie ma dostępu do GPU** — to zamierzone. Najpierw fundament, potem warstwy.
---
## 8. Następny krok
Po przejściu checklisty z sekcji 5:
1. Zgłoś w rozmowie z Cursorem, że krok 01 jest gotowy (lub opisz problemy z Troubleshooting).
2. Przejdź do rozdziału [**02 — Sterowniki NVIDIA**](02-nvidia-driver.md).
---
## Podsumowanie wykonanych zmian
Po ukończeniu tego rozdziału na serwerze powinno być:
- Zaktualizowany system Ubuntu 26.04 LTS
- Zainstalowany Docker CE z oficjalnego repo
- Pluginy `docker compose` i `docker-buildx`
- Użytkownik w grupie `docker`
- Skonfigurowana rotacja logów w `/etc/docker/daemon.json`
- Działający test `hello-world`
+367
View File
@@ -0,0 +1,367 @@
# 02 — Sterowniki NVIDIA
> **Cel rozdziału:** zainstalować sterownik NVIDIA dla RTX 3090 Ti na headless serwerze Ubuntu 26.04, tak aby `nvidia-smi` działało na hoście przed konfiguracją GPU w Dockerze.
**Szacowany czas:** 1530 minut (zależy od pobierania pakietów i ewentualnego DKMS)
**Wymagania:** ukończony rozdział [01 — Aktualizacja systemu i Docker CE](01-system-update-and-docker.md)
---
## Spis treści
1. [Weryfikacja punktu startowego](#1-weryfikacja-punktu-startowego)
2. [Wybór sterownika](#2-wybór-sterownika)
3. [Instalacja sterownika](#3-instalacja-sterownika)
4. [Restart i pierwsze uruchomienie](#4-restart-i-pierwsze-uruchomienie)
5. [Konfiguracja serwerowa (opcjonalna)](#5-konfiguracja-serwerowa-opcjonalna)
6. [Weryfikacja](#6-weryfikacja)
7. [Troubleshooting](#7-troubleshooting)
8. [Czego nie robimy w tym kroku](#8-czego-nie-robimy-w-tym-kroku)
9. [Następny krok](#9-następny-krok)
---
## 1. Weryfikacja punktu startowego
```bash
# Docker z rozdziału 01 — musi działać
docker --version
docker ps
# GPU widoczne w PCI
lspci | grep -i "nvidia"
# nvidia-smi jeszcze nie działa — to normalne
nvidia-smi 2>/dev/null || echo "nvidia-smi: not available (expected)"
# lista dostępnych sterowników
sudo ubuntu-drivers devices
```
**Oczekiwany wynik:**
- RTX 3090 Ti (`GA102`) widoczna w `lspci`
- `nvidia-smi` niedostępne
- `ubuntu-drivers` pokazuje m.in. `nvidia-driver-595-open` jako **recommended**
Sprawdź też Secure Boot (wpływa na DKMS):
```bash
mokutil --sb-state 2>/dev/null || echo "mokutil not available"
```
Na tym serwerze Secure Boot jest wyłączony — nie będzie promptu MOK przy instalacji.
---
## 2. Wybór sterownika
Dla **headless serwera AI** (vLLM + ComfyUI, bez monitora) rekomendujemy wariant **server + open kernel modules**:
| Wariant | Pakiet | Kiedy użyć |
|---------|--------|------------|
| **Rekomendowany** | `nvidia-driver-595-server-open` | Serwer compute, bez GUI, nowoczesne moduły open |
| Alternatywa | `nvidia-driver-595-open` | Jeśli server-open sprawia problemy |
| Nie używamy | `nouveau` | Sterownik open-source — za wolny do AI |
**Dlaczego server-open, a nie desktop `595-open`?**
- Wariant **server** nie ciągnie zbędnych zależności od display managera
- Wariant **open** to aktualna rekomendacja Ubuntu 26.04 dla nowoczesnych GPU
- Sterownik pochodzi z repozytorium Ubuntu (`restricted`) — aktualizuje się przez `apt upgrade` i przeżywa upgrade kernela (DKMS / prebuilt modules)
**Uwaga:** Na hoście **nie instalujemy** pełnego CUDA Toolkit. Kontenery vLLM/ComfyUI dostarczą własne biblioteki CUDA — w rozdziale 03 dodamy tylko NVIDIA Container Toolkit.
**Dual GPU:** W tym systemie jest też iGPU AMD (HawkPoint). Do workloadów AI używamy wyłącznie NVIDIA:
```bash
# zapisz na później — używane w compose stackach
export CUDA_VISIBLE_DEVICES=0
```
---
## 3. Instalacja sterownika
### 3.1 Pakiety pomocnicze
```bash
sudo apt update
sudo apt install -y ubuntu-drivers-common
```
### 3.2 Instalacja sterownika server-open (rekomendowana)
```bash
sudo ubuntu-drivers install --gpgpu nvidia:595-server-open
```
Flaga `--gpgpu` filtruje sterowniki pod obciążenia compute (bez GUI).
Jeśli powyższa komenda zgłosi brak pakietu, użyj bezpośredniej instalacji apt:
```bash
sudo apt install -y nvidia-driver-595-server-open
```
### 3.3 Narzędzia monitorowania (`nvidia-smi`)
Na serwerach headless pakiet `nvidia-utils` czasem nie jest dołączany automatycznie:
```bash
sudo apt install -y nvidia-utils-595-server
```
### 3.4 Alternatywa — sterownik desktop recommended
Jeśli wolisz iść ścieżką „recommended” z `ubuntu-drivers devices`:
```bash
sudo ubuntu-drivers install nvidia:595-open
sudo apt install -y nvidia-utils-595
```
Ta ścieżka też zadziała — ale dla serwera AI preferujemy wariant z sekcji 3.2.
### 3.5 Sprawdzenie zainstalowanych pakietów
```bash
dpkg -l | grep -i nvidia | grep -v linux-firmware
```
Oczekiwane m.in.: `nvidia-driver-595-server-open`, `nvidia-utils-595-server`.
---
## 4. Restart i pierwsze uruchomienie
Sterownik NVIDIA ładuje się do jądra dopiero po restarcie:
```bash
sudo reboot
```
Po restarcie zaloguj się ponownie przez SSH i wróć do sekcji 6 (Weryfikacja).
---
## 5. Konfiguracja serwerowa (opcjonalna)
Te kroki możesz wykonać po pierwszym udanym `nvidia-smi`.
### 5.1 Persistence mode
Zmniejsza opóźnienie przy pierwszym uruchomieniu workloadu GPU (kontenery startują szybciej):
```bash
# włącz persistence mode
sudo nvidia-smi -pm 1
# sprawdź
nvidia-smi | grep -i persistence
```
Aby włączać przy każdym bootcie, utwórz systemd service (opcjonalnie):
```bash
sudo tee /etc/systemd/system/nvidia-persistenced.service <<'EOF'
[Unit]
Description=NVIDIA Persistence Daemon
After=nvidia-persistenced.socket
[Service]
Type=forking
ExecStart=/usr/bin/nvidia-persistenced --user nvidia-persistenced
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now nvidia-persistenced 2>/dev/null || true
```
**Uwaga:** Na Ubuntu 26.04 daemon może już być zarządzany przez pakiet sterownika — jeśli `nvidia-persistenced` działa, nie twórz duplikatu.
### 5.2 Limit mocy GPU (opcjonalnie)
RTX 3090 Ti domyślnie pobiera dużo energii. Na serwerze domowym możesz ograniczyć TDP:
```bash
# sprawdź aktualny limit (450W max dla 3090 Ti)
nvidia-smi -q -d POWER | grep -E "Power Limit|Power Draw"
# przykład: limit 350W (wartość w mW) — dostosuj do swojego PSU
# sudo nvidia-smi -pl 350
```
Pomiń ten krok, jeśli zależy Ci na maksymalnej wydajności inference.
---
## 6. Weryfikacja
Wykonaj wszystkie punkty po restarcie.
### 6.1 `nvidia-smi`
```bash
nvidia-smi
```
Oczekiwane:
- GPU: **NVIDIA GeForce RTX 3090 Ti**
- Driver Version: **595.x**
- CUDA Version: wyświetlona (np. 12.x) — to wersja wspierana przez sterownik, nie osobna instalacja CUDA
- Brak błędów `NVIDIA-SMI has failed`
### 6.2 Wersja modułu jądra
```bash
cat /proc/driver/nvidia/version
```
### 6.3 Pełna lista GPU
```bash
nvidia-smi -L
```
Oczekiwane: jedna karta NVIDIA (GPU 0). iGPU AMD nie pojawia się w `nvidia-smi` — to prawidłowe.
### 6.4 Test obciążenia (krótki)
```bash
nvidia-smi dmon -s pucvmet -d 1 -c 3
```
Powinieneś zobaczyć odczyty temperatury, mocy i wykorzystania GPU.
### 6.5 Docker nadal działa
```bash
docker run --rm hello-world
```
Sterownik NVIDIA nie powinien zakłócić Dockera z rozdziału 01.
### Checklist
- [ ] `nvidia-smi` działa bez błędów
- [ ] Widoczna RTX 3090 Ti (24 GB VRAM)
- [ ] Driver Version 595.x
- [ ] `cat /proc/driver/nvidia/version` zwraca wersję
- [ ] Docker nadal działa (`hello-world` OK)
- [ ] (Opcjonalnie) persistence mode włączony
---
## 7. Troubleshooting
### 7.1 `NVIDIA-SMI has failed` po restarcie
**Przyczyna:** Moduł jądra nie załadowany lub konflikt z `nouveau`.
**Diagnostyka:**
```bash
lsmod | grep -E 'nvidia|nouveau'
dmesg | grep -i nvidia | tail -20
```
**Rozwiązanie:**
```bash
# nouveau powinien być wyłączony — jeśli załadowany:
cat /etc/modprobe.d/blacklist-nvidia-nouveau.conf 2>/dev/null
# przeinstaluj sterownik
sudo apt install --reinstall nvidia-driver-595-server-open
sudo reboot
```
### 7.2 DKMS — błąd kompilacji modułu
**Objaw:** Instalacja kończy się błędem DKMS.
**Rozwiązanie:**
```bash
# upewnij się, że masz nagłówki kernela
sudo apt install -y linux-headers-$(uname -r) build-essential dkms
# ponów instalację
sudo apt install --reinstall nvidia-driver-595-server-open
```
### 7.3 Secure Boot — moduł niepodpisany
**Objaw:** Po restarcie brak `nvidia` w `lsmod`, Secure Boot enabled.
Na tym serwerze Secure Boot jest wyłączony. Jeśli włączysz go później:
```bash
mokutil --sb-state
# wymagana rejestracja klucza MOK po instalacji sterownika
sudo reboot # → menu MOK enrollment
```
### 7.4 `ubuntu-drivers install` — GUI nie działa
Na Ubuntu 26.04 zakładka „Additional Drivers” w GUI może być pusta — to znany problem. **Używaj wyłącznie CLI** (ten rozdział).
### 7.5 Po aktualizacji kernela — `nvidia-smi` przestaje działać
Po `apt upgrade` z nowym kernelem wymagany restart:
```bash
test -f /var/run/reboot-required && echo "Reboot required" || echo "OK"
sudo reboot
```
Ubuntu 26.04 na tym sprzęcie używa prebuilt modules (`linux-modules-nvidia-*`) — zwykle nie wymaga ręcznej rekompilacji DKMS.
### 7.6 Zła karta GPU używana przez aplikację
Jeśli w przyszłości pojawi się druga karta NVIDIA, wymuszaj:
```bash
export CUDA_VISIBLE_DEVICES=0
```
Dla RTX 3090 Ti jako jedynej karty NVIDIA w systemie domyślnie jest `GPU 0`.
---
## 8. Czego nie robimy w tym kroku
| Element | Rozdział |
|---------|----------|
| NVIDIA Container Toolkit (`nvidia-ctk`) | 03 |
| GPU w kontenerach Docker (`--gpus all`) | 03 |
| CUDA Toolkit na hoście | niepotrzebne — CUDA w kontenerach |
| vLLM | 04 |
| ComfyUI | 05 |
| Firewall | 06 |
---
## 9. Następny krok
Po przejściu checklisty z sekcji 6:
1. Zgłoś w rozmowie z Cursorem, że krok 02 jest gotowy (lub opisz problemy).
2. Przejdź do rozdziału [**03 — NVIDIA Container Toolkit**](03-nvidia-container-toolkit.md).
---
## Podsumowanie wykonanych zmian
Po ukończeniu tego rozdziału na serwerze powinno być:
- Zainstalowany sterownik `nvidia-driver-595-server-open` (lub `595-open`)
- Działające `nvidia-smi` z RTX 3090 Ti
- Narzędzia `nvidia-utils-595-server`
- Docker z rozdziału 01 nadal sprawny
- (Opcjonalnie) włączony persistence mode
@@ -0,0 +1,362 @@
# 03 — NVIDIA Container Toolkit
> **Cel rozdziału:** skonfigurować Docker tak, aby kontenery miały dostęp do GPU NVIDIA (RTX 3090 Ti) — fundament pod vLLM i ComfyUI.
**Szacowany czas:** 1015 minut
**Wymagania:** ukończone rozdziały [01](01-system-update-and-docker.md) i [02](02-nvidia-driver.md)
---
## Spis treści
1. [Weryfikacja punktu startowego](#1-weryfikacja-punktu-startowego)
2. [Co robi NVIDIA Container Toolkit](#2-co-robi-nvidia-container-toolkit)
3. [Instalacja](#3-instalacja)
4. [Konfiguracja runtime Docker](#4-konfiguracja-runtime-docker)
5. [Test GPU w kontenerze](#5-test-gpu-w-kontenerze)
6. [Składnia GPU dla Compose (podgląd)](#6-składnia-gpu-dla-compose-podgląd)
7. [Weryfikacja](#7-weryfikacja)
8. [Troubleshooting](#8-troubleshooting)
9. [Czego nie robimy w tym kroku](#9-czego-nie-robimy-w-tym-kroku)
10. [Następny krok](#10-następny-krok)
---
## 1. Weryfikacja punktu startowego
```bash
# sterownik NVIDIA z rozdziału 02
nvidia-smi
# Docker z rozdziału 01
docker --version
docker ps
# toolkit jeszcze niezainstalowany
which nvidia-ctk 2>/dev/null || echo "nvidia-ctk: not installed (expected)"
```
**Oczekiwany wynik:**
- `nvidia-smi` pokazuje RTX 3090 Ti, driver 595.x
- Docker działa (`docker ps` bez błędów)
- `nvidia-ctk` niedostępne
---
## 2. Co robi NVIDIA Container Toolkit
Bez tego pakietu Docker **nie widzi GPU** — kontener uruchomi się, ale bez akceleracji CUDA.
Toolkit dostarcza:
| Komponent | Rola |
|-----------|------|
| `nvidia-container-toolkit` | Integracja GPU z container runtime |
| `nvidia-ctk` | CLI do konfiguracji (Docker, containerd) |
| `libnvidia-container` | Biblioteka montująca sterownik i urządzenia GPU do kontenera |
**Jak to działa:**
```mermaid
flowchart LR
host["Host: nvidia-driver + nvidia-smi"]
docker["Docker Engine"]
toolkit["NVIDIA Container Toolkit"]
container["Kontener vLLM / ComfyUI"]
host --> toolkit
docker --> toolkit
toolkit --> container
```
Kontener **nie potrzebuje** własnego sterownika NVIDIA — dziedziczy go z hosta przez toolkit. Obraz musi mieć tylko biblioteki CUDA kompatybilne z wersją sterownika.
**Uwaga:** Nie instalujemy przestarzałego `nvidia-docker2` — został zastąpiony przez Container Toolkit.
---
## 3. Instalacja
### 3.1 Dodanie repozytorium NVIDIA
```bash
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
| sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
| sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
```
### 3.2 Instalacja pakietu
```bash
sudo apt update
sudo apt install -y nvidia-container-toolkit
```
### 3.3 Sprawdzenie wersji
```bash
nvidia-ctk --version
dpkg -l | grep nvidia-container
```
---
## 4. Konfiguracja runtime Docker
Toolkit musi zarejestrować runtime NVIDIA w Dockerze:
```bash
sudo nvidia-ctk runtime configure --runtime=docker
```
Ta komenda modyfikuje `/etc/docker/daemon.json` — dodaje konfigurację runtime `nvidia`, **zachowując** istniejące ustawienia (np. rotację logów z rozdziału 01).
Sprawdź wynik:
```bash
cat /etc/docker/daemon.json
```
Oczekiwana struktura (przykład — Twoja może wyglądać nieco inaczej):
```json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
},
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
}
}
```
Zrestartuj Docker:
```bash
sudo systemctl restart docker
```
Sprawdź, że daemon wstał:
```bash
sudo systemctl status docker --no-pager
```
---
## 5. Test GPU w kontenerze
### 5.1 Podstawowy test — `nvidia-smi` w kontenerze
```bash
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
```
**Oczekiwany wynik:**
- Ten sam GPU: NVIDIA GeForce RTX 3090 Ti
- Driver Version: 595.x (z hosta)
- Brak błędów `could not select device driver`
Pierwsze uruchomienie pobierze obraz CUDA (~100200 MB) — to normalne.
### 5.2 Test z jednym GPU (explicit)
Na tym serwerze jest jedna karta NVIDIA, ale warto od razu testować jawne przypisanie:
```bash
docker run --rm --gpus '"device=0"' nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi -L
```
Oczekiwane: `GPU 0: NVIDIA GeForce RTX 3090 Ti`
### 5.3 Test bez GPU (kontrolny)
```bash
docker run --rm nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
```
Oczekiwane: błąd — kontener bez `--gpus` nie widzi GPU. To potwierdza, że GPU nie jest przypadkowo dostępne dla każdego kontenera.
---
## 6. Składnia GPU dla Compose (podgląd)
W rozdziałach 04 (vLLM) i 05 (ComfyUI) użyjemy `docker compose` z GPU. Podgląd składni:
```yaml
services:
vllm:
image: vllm/vllm-openai:latest
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
```
Alternatywnie (prostsza składnia, działa w Compose v2):
```yaml
services:
comfyui:
image: yanwk/comfyui-boot:latest
gpus: all
```
Na razie **nie twórz** tych plików — to tylko podgląd na przyszłość.
---
## 7. Weryfikacja
### Checklist
- [ ] `nvidia-ctk --version` zwraca wersję
- [ ] `/etc/docker/daemon.json` zawiera runtime `nvidia`
- [ ] `docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi` działa
- [ ] W kontenerze widać RTX 3090 Ti (24 GB)
- [ ] `docker run` **bez** `--gpus` nie widzi GPU (kontrolny test)
- [ ] Docker z rozdziału 01 nadal działa (`hello-world` OK)
### Szybki test końcowy
```bash
docker run --rm hello-world
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
```
---
## 8. Troubleshooting
### 8.1 `could not select device driver "" with capabilities: [[gpu]]`
**Przyczyna:** Runtime NVIDIA nie skonfigurowany lub Docker nie zrestartowany.
**Rozwiązanie:**
```bash
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
docker info | grep -i nvidia
```
### 8.2 `nvidia-smi` działa na hoście, ale nie w kontenerze
**Diagnostyka:**
```bash
# na hoście
nvidia-smi
# sprawdź runtime w docker info
docker info 2>/dev/null | grep -A5 -i runtime
# logi toolkit
sudo journalctl -u docker --no-pager -n 30
```
**Rozwiązanie:**
```bash
sudo apt install --reinstall nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```
### 8.3 Konflikt w `daemon.json`
**Objaw:** `systemctl restart docker` → failed po edycji `daemon.json`.
**Rozwiązanie:**
```bash
# walidacja JSON
python3 -m json.tool /etc/docker/daemon.json
# jeśli błąd składni — przywróć minimalną konfigurację i skonfiguruj ponownie
sudo tee /etc/docker/daemon.json <<'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
}
}
EOF
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```
### 8.4 `apt update` — konflikt Signed-By
**Objaw:** Błąd repozytorium przy `apt update` po dodaniu NVIDIA repo.
**Rozwiązanie:**
```bash
# usuń i dodaj repo ponownie (sekcja 3.1)
sudo rm /etc/apt/sources.list.d/nvidia-container-toolkit.list
# ... powtórz kroki 3.1 i 3.2
```
### 8.5 Obraz CUDA — `pull` failed / timeout
```bash
# test połączenia z registry
docker pull nvidia/cuda:12.6.0-base-ubuntu24.04
# alternatywny lekki obraz testowy
docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi
```
### 8.6 `CUDA Version` w kontenerze vs na hoście
Na hoście `nvidia-smi` może pokazywać CUDA 13.2, a obraz testowy CUDA 12.6 — to **normalne**. Kontener używa sterownika hosta; wersja CUDA w obrazie to maksymalna wersja bibliotek w kontenerze, nie sterownik.
---
## 9. Czego nie robimy w tym kroku
| Element | Rozdział |
|---------|----------|
| vLLM | 04 |
| ComfyUI | 05 |
| Pobieranie modeli LLM | 04 |
| CUDA Toolkit na hoście | niepotrzebne |
| Firewall | 06 |
| Katalog `/data` na modele | później |
---
## 10. Następny krok
Po przejściu checklisty z sekcji 7:
1. Zgłoś w rozmowie z Cursorem, że krok 03 jest gotowy (lub opisz problemy).
2. Przejdź do rozdziału [**03b — Narzędzia bazowe**](03b-system-tools.md), a następnie [**04 — Dysk + vLLM**](04-vllm-stack.md).
---
## Podsumowanie wykonanych zmian
Po ukończeniu tego rozdziału na serwerze powinno być:
- Zainstalowany `nvidia-container-toolkit`
- Skonfigurowany runtime NVIDIA w Dockerze
- Działający `docker run --gpus all` z widoczną RTX 3090 Ti
- Gotowa infrastruktura pod vLLM i ComfyUI w kontenerach
+283
View File
@@ -0,0 +1,283 @@
# 03b — Narzędzia bazowe (Ubuntu minimized)
> **Cel rozdziału:** doinstalować minimalny zestaw narzędzi systemowych na Ubuntu minimized — tylko to, co potrzebne na **hoście**. vLLM, ComfyUI i CUDA działają w Dockerze, nie na systemie.
**Szacowany czas:** 5 minut
**Wymagania:** ukończony rozdział [01 — Docker CE](01-system-update-and-docker.md)
**Kiedy wykonać:** przed rozdziałem [04 — dysk + vLLM](04-vllm-stack.md). Można zrobić teraz (kroki 0103 już ukończone).
---
## Spis treści
1. [Filozofia: host vs Docker](#1-filozofia-host-vs-docker)
2. [Co już masz po krokach 0103](#2-co-już-masz-po-krokach-0103)
3. [Instalacja pakietów bazowych](#3-instalacja-pakietów-bazowych)
4. [Python na hoście — co i czego nie](#4-python-na-hoście--co-i-czego-nie)
5. [Git i repozytorium konfiguracyjne](#5-git-i-repozytorium-konfiguracyjne)
6. [Weryfikacja](#6-weryfikacja)
7. [Opcjonalne narzędzia](#7-opcjonalne-narzędzia)
8. [Czego świadomie NIE instalujemy na hoście](#8-czego-świadomie-nie-instalujemy-na-hoście)
9. [Następny krok](#9-następny-krok)
---
## 1. Filozofia: host vs Docker
Ubuntu **minimized** to świadomie odchudzona instalacja — bez edytorów, bez wielu narzędzi deweloperskich, bez GUI. Na serwerze AI trzymamy się zasady:
| Warstwa | Co tam żyje | Przykłady |
|---------|-------------|-----------|
| **Host (128 GB `/`)** | System, Docker, sterowniki, konfiguracja | `git`, `python3`, `nano`, `rsync`, `parted` |
| **Docker (`/data/docker`)** | Obrazy i kontenery | vLLM, ComfyUI, CUDA runtime |
| **Dane (`/data/apps`)** | Modele, checkpointy, cache | Hugging Face, ComfyUI models |
```mermaid
flowchart TB
host["Host Ubuntu minimized"]
docker["Docker Engine"]
vllm["Kontener vLLM — Python + PyTorch + CUDA"]
comfy["Kontener ComfyUI — Python + torch"]
host --> docker
docker --> vllm
docker --> comfy
```
**Nie instalujemy PyTorch, CUDA Toolkit ani vLLM na hoście** — wszystko to jest w kontenerach. Host dostaje tylko narzędzia administracyjne.
---
## 2. Co już masz po krokach 0103
Sprawdź aktualny stan:
```bash
for cmd in git python3 curl wget docker nvidia-smi; do
printf "%-12s " "$cmd"
command -v $cmd 2>/dev/null || echo "BRAK"
done
python3 --version
git --version
```
Na typowym stanie po rozdziałach 0103:
| Narzędzie | Status | Skąd |
|-----------|--------|------|
| `git` | zazwyczaj jest | zależność systemowa / automatyczna |
| `python3` | jest (minimalny) | preinstalowany na Ubuntu |
| `curl`, `wget` | są | rozdział 01 |
| `docker` | jest | rozdział 01 |
| `nvidia-smi` | jest | rozdział 02 |
| `nano`, `vim` | **brak** | minimized |
| `rsync` | **brak** | potrzebny do migracji Docker → `/data` |
| `parted` | **brak** | potrzebny do partycjonowania dysku 1 TB |
| `jq` | **brak** | wygodne testy API vLLM |
| `pip3` | **brak** | celowo — patrz sekcja 4 |
---
## 3. Instalacja pakietów bazowych
Jedna komenda — zestaw dla administracji serwerem i kolejnych rozdziałów tutoriala:
```bash
sudo apt update
sudo apt install -y \
git \
python3 \
python3-venv \
nano \
vim \
jq \
rsync \
parted \
e2fsprogs \
util-linux \
htop \
tmux \
tree \
unzip \
zip \
pciutils \
usbutils \
net-tools \
smartmontools
```
### Po co który pakiet
| Pakiet | Po co na tym serwerze |
|--------|----------------------|
| `git` | Wersjonowanie `ubuntu-bare-metal`, klonowanie configów |
| `python3` | `python3 -m json.tool`, skrypty admin (stdlib) |
| `python3-venv` | Izolowane środowiska Python — jeśli kiedyś własny skrypt |
| `nano` / `vim` | Edycja `.env`, `fstab`, `daemon.json` |
| `jq` | Parsowanie JSON z API vLLM (`curl ... \| jq`) |
| `rsync` | Migracja `/var/lib/docker``/data/docker` (rozdział 04) |
| `parted` | Partycjonowanie dysku 1 TB (rozdział 04) |
| `e2fsprogs` | `mkfs.ext4`, `fsck` — formatowanie `/data` |
| `util-linux` | `lsblk`, `blkid`, `mount` — diagnostyka dysków |
| `htop` | Monitorowanie CPU/RAM |
| `tmux` | Sesje SSH — proces nie ginie po rozłączeniu |
| `tree` | Podgląd struktury `/data` |
| `pciutils` | `lspci` — diagnostyka GPU |
| `smartmontools` | `smartctl` — zdrowie dysków (opcjonalnie, ale przydatne) |
---
## 4. Python na hoście — co i czego nie
### Co mamy
Ubuntu 26.04 minimized dostarcza **Python 3.14** (minimalny) — wystarczy do:
```bash
# formatowanie JSON z API
curl -s http://localhost:8000/v1/models | python3 -m json.tool
# walidacja daemon.json
python3 -m json.tool /etc/docker/daemon.json
```
### Czego NIE robimy na hoście
```bash
# NIE instaluj tego na hoście:
# pip install torch vllm transformers
# apt install nvidia-cuda-toolkit
```
Ubuntu 26.04 blokuje też `pip install` do systemowego Pythona (PEP 668 — „externally managed environment”). To **dobre** — chroni system przed bałaganem.
Jeśli kiedyś potrzebujesz własnego skryptu Python na hoście:
```bash
python3 -m venv ~/venv
source ~/venv/bin/activate
pip install requests # tylko w venv, nie globalnie
deactivate
```
Dla vLLM i ComfyUI — **nie potrzebujesz** venv na hoście.
---
## 5. Git i repozytorium konfiguracyjne
### 5.1 Inicjalizacja repo (jeśli jeszcze nie zrobione)
Repozytorium konfiguracyjne trzymamy na dysku **systemowym** (lekki tekst), nie na `/data`:
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal
git init
git add README.md manual-tutorial/ stacks/
git status
```
**Nie commituj** plików `.env` z tokenami — tylko `.env.example`.
Opcjonalnie `.gitignore`:
```bash
cat > .gitignore <<'EOF'
.env
*.log
__pycache__/
.venv/
EOF
```
### 5.2 Podstawowa konfiguracja git (opcjonalnie)
```bash
git config --global user.name "Twoje Imię"
git config --global user.email "twoj@email.com"
```
Bez tego `git commit` zapyta o autora przy pierwszym commicie.
---
## 6. Weryfikacja
```bash
# pakiety kluczowe
for cmd in git python3 nano vim jq rsync parted lsblk blkid htop tmux; do
printf "%-12s " "$cmd"
command -v $cmd 2>/dev/null || echo "BRAK"
done
# wersje
python3 --version
git --version
jq --version
# test jq
echo '{"status":"ok"}' | jq .
# test rsync
rsync --version | head -1
# test parted
parted --version | head -1
```
### Checklist
- [ ] `nano` lub `vim` działa
- [ ] `jq` formatuje JSON
- [ ] `rsync` dostępny (rozdział 04 — migracja Docker)
- [ ] `parted` i `lsblk` dostępne (rozdział 04 — dysk 1 TB)
- [ ] `git status` w katalogu `ubuntu-bare-metal` działa
---
## 7. Opcjonalne narzędzia
Instaluj tylko jeśli potrzebujesz:
```bash
# kompilacja czegoś ze źródeł (zwykle niepotrzebne na tym serwerze)
# sudo apt install -y build-essential
# monitorowanie GPU w czasie rzeczywistym (wygodniejsze niż watch nvidia-smi)
# sudo apt install -y nvtop
# sieć — ss jest nowocześniejszy niż netstat
ss -tlnp
# synchronizacja czasu (zwykle już działa)
timedatectl status
```
---
## 8. Czego świadomie NIE instalujemy na hoście
| Pakiet / narzędzie | Dlaczego nie |
|--------------------|--------------|
| `nvidia-cuda-toolkit` | CUDA jest w kontenerach Docker |
| `python3-pip` (globalnie) | PEP 668; używaj `venv` lub `jq` |
| `torch`, `vllm`, `transformers` (pip) | Działają w kontenerze vLLM |
| `nodejs`, `npm` | ComfyUI w Dockerze |
| `docker.io` (Ubuntu) | Mamy `docker-ce` z rozdziału 01 |
| GUI / desktop | Serwer headless |
| `snap` pakiety | Niepotrzebna złożoność na serwerze |
---
## 9. Następny krok
→ [04 — Dysk danych 1 TB + vLLM stack](04-vllm-stack.md)
Kolejność:
1. Ten rozdział (03b) — narzędzia bazowe
2. Rozdział 04 część A — dysk 1 TB + migracja Docker
3. Rozdział 04 część B — uruchomienie vLLM
+773
View File
@@ -0,0 +1,773 @@
# 04 — Dysk danych 1 TB + vLLM stack
> **Cel rozdziału:** dodać dysk 1 TB jako `/data` (aplikacje, modele, Docker), a na dysku systemowym 128 GB zostawić wyłącznie Ubuntu. Następnie uruchomić vLLM z mountami na `/data`.
**Szacowany czas:**
- Dysk 1 TB + migracja Docker: 2040 minut
- Pierwsze uruchomienie vLLM: 2060 minut (pobieranie obrazu i modelu)
**Wymagania:** ukończone rozdziały [01](01-system-update-and-docker.md)[03](03-nvidia-container-toolkit.md) oraz [03b — Narzędzia bazowe](03b-system-tools.md)
---
## Spis treści
**Część A — dysk danych**
1. [Architektura dysków](#1-architektura-dysków)
2. [Wykrycie i partycjonowanie dysku 1 TB](#2-wykrycie-i-partycjonowanie-dysku-1-tb)
3. [Montowanie `/data` i wpis w fstab](#3-montowanie-data-i-wpis-w-fstab)
4. [Struktura katalogów na `/data`](#4-struktura-katalogów-na-data)
5. [Przeniesienie Docker data-root na `/data`](#5-przeniesienie-docker-data-root-na-data)
**Część B — vLLM**
6. [Jak działa vLLM (bez UI)](#6-jak-działa-vllm-bez-ui)
7. [Mapowanie ustawień z LM Studio](#7-mapowanie-ustawień-z-lm-studio)
8. [Struktura plików stacku](#8-struktura-plików-stacku)
9. [Przygotowanie stacku (bez modelu)](#9-przygotowanie-stacku-bez-modelu)
10. [Wybór modelu i start](#10-wybór-modelu-i-start)
11. [Test API](#11-test-api)
12. [Tuning po starcie (jeśli OOM)](#12-tuning-po-starcie-jeśli-oom)
13. [Zmiana modelu](#13-zmiana-modelu)
14. [Zarządzanie stackiem](#14-zarządzanie-stackiem)
15. [Weryfikacja](#15-weryfikacja)
16. [Troubleshooting](#16-troubleshooting)
17. [Czego nie robimy w tym kroku](#17-czego-nie-robimy-w-tym-kroku)
18. [Następny krok](#18-następny-krok)
---
# Część A — Dysk danych 1 TB
## 1. Architektura dysków
| Dysk | Rozmiar | Mount | Przeznaczenie |
|------|---------|-------|---------------|
| NVMe systemowy | 128 GB (`nvme1n1`) | `/` | Ubuntu, konfiguracja, repo tutoriala |
| Dysk danych | 1 TB (`nvme0n1`) | `/data` | Docker, modele LLM, ComfyUI, cache |
```mermaid
flowchart TB
subgraph systemDisk ["128GB NVMe — /"]
os["Ubuntu 26.04"]
etc["/etc /boot"]
home["/home"]
repo["cursor/ubuntu-bare-metal"]
end
subgraph dataDisk ["1TB — /data"]
docker["/data/docker — Docker images/volumes"]
vllm["/data/apps/vllm/huggingface"]
comfyui["/data/apps/comfyui/*"]
end
docker --> vllm
docker --> comfyui
```
**Zasada:** Na dysku systemowym nie trzymamy modeli ani obrazów Docker. Wszystko ciężkie idzie na `/data`.
**Uwaga:** Fizycznie zamontuj dysk 1 TB w GMKtec K11 przed wykonaniem sekcji 2. Po podłączeniu zrób reboot lub rescann PCI/NVMe.
---
## 2. Wykrycie i partycjonowanie dysku 1 TB
### 2.1 Wykrycie nowego dysku
```bash
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,MODEL
```
Oczekiwany układ **po** podłączeniu dysku 1 TB na GMKtec K11:
```
nvme1n1 119G # dysk SYSTEMOWY — NIE DOTYKAĆ
├─nvme1n1p1 1G /boot/efi
└─nvme1n1p2 118G /
nvme0n1 931G # dysk DANYCH 1 TB — ten partycjonujemy
```
**Uwaga:** Na tym modelu GMKtec K11 numeracja bywa odwrotna niż intuicyjnie — `nvme0n1` to 1 TB, `nvme1n1` to 128 GB systemu. Zawsze weryfikuj po `SIZE` i `MOUNTPOINT`, nie po numerze.
**KRYTYCZNE:** Partycjonuj wyłącznie dysk ~1 TB **bez** mountpointu `/`. Nigdy `nvme1n1`.
Zapisz nazwę urządzenia:
```bash
# GMKtec K11 — dysk DANYCH 1 TB (sprawdź lsblk!)
export DATA_DISK=/dev/nvme0n1
export DATA_PART=/dev/nvme0n1p1
echo "DATA_DISK=$DATA_DISK"
echo "DATA_PART=$DATA_PART"
lsblk $DATA_DISK
# weryfikacja: DATA_DISK nie może mieć mountpoint /
lsblk -n -o MOUNTPOINT $DATA_DISK | grep -q '^/$' && echo "BŁĄD: to dysk systemowy!" && exit 1
```
### Szybka instalacja (skrypt)
Jeśli partycja `nvme0n1p1` już istnieje (lub po ręcznym parted), uruchom w **swoim terminalu SSH** (wymaga hasła sudo):
```bash
sudo bash /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/scripts/setup-data-disk.sh
```
Skrypt: formatuje `nvme0n1p1`, montuje `/data`, fstab, katalogi, migracja Docker → `/data/docker`.
---
### 2.2 Partycjonowanie ręczne (jeśli bez skryptu)
Partycja: `/dev/nvme0n1p1` (na GMKtec K11).
```bash
# OBOWIĄZKOWO ustaw obie zmienne przed każdą komendą!
export DATA_DISK=/dev/nvme0n1
export DATA_PART=/dev/nvme0n1p1
# sprawdź jeszcze raz przed zapisem!
lsblk $DATA_DISK
echo "Partycja: $DATA_PART"
sudo parted -s $DATA_DISK mklabel gpt
sudo parted -s $DATA_DISK mkpart primary ext4 0% 100%
sudo partprobe $DATA_DISK
sleep 2
lsblk $DATA_DISK
```
### 2.3 Formatowanie ext4
```bash
sudo mkfs.ext4 -L data1tb $DATA_PART
```
---
## 3. Montowanie `/data` i wpis w fstab
### 3.1 Pobranie UUID (stabilniejsze niż /dev/sdX)
```bash
sudo blkid $DATA_PART
```
Zapisz UUID, np. `UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`.
### 3.2 Montowanie tymczasowe i test
```bash
sudo mkdir -p /data
sudo mount $DATA_PART /data
df -h /data
```
Oczekiwane: ~1 TB dostępne na `/data`.
### 3.3 Wpis w `/etc/fstab` (montowanie przy bootcie)
```bash
# zamień YOUR-UUID na rzeczywisty UUID z blkid
echo 'UUID=YOUR-UUID /data ext4 defaults,noatime 0 2' | sudo tee -a /etc/fstab
```
**Lepiej edytować ręcznie** — sprawdź składnię:
```bash
sudo nano /etc/fstab
```
Dodaj linię (przykład):
```
UUID=a1b2c3d4-e5f6-7890-abcd-ef1234567890 /data ext4 defaults,noatime 0 2
```
Test fstab (montuje wszystko bez rebootu):
```bash
sudo umount /data
sudo mount -a
df -h /data
```
Jeśli `mount -a` nie zwraca błędu — fstab jest poprawny.
---
## 4. Struktura katalogów na `/data`
```bash
# Docker data-root (własność root)
sudo mkdir -p /data/docker
# Katalogi aplikacji (własność użytkownika — łatwiejszy dostęp)
sudo mkdir -p /data/apps/vllm/huggingface
sudo mkdir -p /data/apps/gguf/{qwen3.6-27b,gemma-4-12b}
sudo mkdir -p /data/apps/localai/{models,backends,configuration,images,data}
sudo mkdir -p /data/apps/comfyui/{models,input,output,custom_nodes}
sudo chown -R $USER:$USER /data/apps
```
Docelowa struktura:
```
/data/
├── docker/ # Docker data-root (obrazy, warstwy, volumes)
└── apps/
├── vllm/
│ └── huggingface/ # cache modeli Hugging Face (AWQ)
├── gguf/ # przyszłe GGUF (llama.cpp)
│ ├── qwen3.6-27b/
│ └── gemma-4-12b/
└── comfyui/ # przygotowane pod rozdział 05
├── models/
├── input/
├── output/
└── custom_nodes/
```
Sprawdź:
```bash
tree -L 3 /data 2>/dev/null || find /data -maxdepth 3 -type d
df -h / /data
```
---
## 5. Przeniesienie Docker data-root na `/data`
Domyślnie Docker trzyma dane w `/var/lib/docker` na dysku systemowym. Przenosimy na `/data/docker`.
### 5.1 Zatrzymanie Docker
```bash
sudo systemctl stop docker
sudo systemctl stop docker.socket 2>/dev/null || true
```
Upewnij się, że nie ma uruchomionych kontenerów:
```bash
docker ps # powinno być puste lub błąd „cannot connect” — OK
```
### 5.2 Kopia istniejących danych Docker
Jeśli już pobierałeś obrazy (np. `hello-world`, `nvidia/cuda`):
```bash
sudo rsync -aHAX --progress /var/lib/docker/ /data/docker/
```
Jeśli `/var/lib/docker` jest pusty lub mało znaczący:
```bash
sudo mkdir -p /data/docker
```
### 5.3 Aktualizacja `/etc/docker/daemon.json`
```bash
sudo python3 -c "
import json
from pathlib import Path
p = Path('/etc/docker/daemon.json')
cfg = json.loads(p.read_text()) if p.exists() else {}
cfg['data-root'] = '/data/docker'
p.write_text(json.dumps(cfg, indent=2) + '\n')
print(p.read_text())
"
```
Oczekiwany fragment:
```json
{
"data-root": "/data/docker",
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
},
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
}
}
```
### 5.4 Uruchomienie Docker i weryfikacja
```bash
sudo systemctl start docker
docker info | grep "Docker Root Dir"
```
Oczekiwane: `Docker Root Dir: /data/docker`
```bash
docker run --rm hello-world
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
```
### 5.5 Opcjonalnie: zwolnienie miejsca na dysku systemowym
**Dopiero po potwierdzeniu**, że Docker działa z nowego data-root:
```bash
# UWAGA: nieodwracalne — usuwa stare dane Dockera z dysku systemowego
sudo rm -rf /var/lib/docker
```
Sprawdź, że dysk systemowy ma więcej wolnego miejsca:
```bash
df -h /
df -h /data
```
### Checklist — część A (dysk)
- [ ] Dysk 1 TB widoczny w `lsblk`
- [ ] Partycja sformatowana ext4
- [ ] `/data` zamontowany, ~1 TB wolne
- [ ] Wpis w `/etc/fstab` (UUID)
- [ ] `mount -a` bez błędów
- [ ] Katalogi `/data/docker` i `/data/apps/*` utworzone
- [ ] `Docker Root Dir: /data/docker`
- [ ] `hello-world` i test GPU w Dockerze działają
**Nie przechodź do vLLM, dopóki checklista części A nie jest ukończona.**
---
# Część B — vLLM stack
## 6. Jak działa vLLM (bez UI)
vLLM to **serwer API** — nie ma panelu administracyjnego jak LM Studio.
| LM Studio | vLLM na serwerze |
|-----------|------------------|
| Panel UI, suwaki | Plik `.env` + profile + skrypty |
| GGUF Q4 (lmstudio-community) | **Nie w vLLM** — przyszły stack [`stacks/llamacpp/`](../stacks/llamacpp/); interim: AWQ z HF |
| Hugging Face AWQ | Kontener Docker `vllm/vllm-openai` |
| Lokalny chat | HTTP API OpenAI (`/v1/chat/completions`) |
Konfiguracja = zmienne w `.env` przekazywane jako flagi `vllm serve`. Test: `curl` + `jq` lub klient OpenAI.
**Model nie jest pobierany przy instalacji stacku** — katalog `models.catalog.yaml` + `download-model.sh` na żądanie. `VLLM_MODEL` ustawiasz przez profil dopiero gdy jesteś gotowy.
### GGUF z lmstudio-community — nie działa w standardowym vLLM
Linki typu `lmstudio-community/Qwen3.6-27B-GGUF` to pliki **`.gguf`**. Obraz `vllm/vllm-openai` ich nie obsługuje (wymagałby eksperymentalnego `vllm-gguf-plugin` lub osobnego hosta).
| Co chcesz | Co robisz |
|-----------|-----------|
| Q4 jak w LM Studio (GGUF) | `download-model.sh <id-gguf>``/data/apps/gguf/` → później `stacks/llamacpp/` |
| Q4-odpowiednik **teraz** na vLLM | `download-model.sh qwen3.6-27b-awq-vllm` + profil AWQ |
---
## 7. Mapowanie ustawień z LM Studio
Jeśli testowałeś Qwen3.6-27B na Windows (LM Studio / Ollama):
| LM Studio / Ollama | vLLM (`.env` / flagi) |
|--------------------|----------------------|
| Model GGUF Q4 (lmstudio) | Katalog `runtime: llamacpp`**nie** ten stack vLLM |
| Odpowiednik Q4 na vLLM (interim) | `VLLM_MODEL=Qwen/Qwen3.6-27B-Instruct-AWQ`, `QUANTIZATION=awq` |
| K Cache Q4_0 | `KV_CACHE_DTYPE=fp8` |
| V Cache Q4_0 | j.w. — vLLM **nie ma** `Q4_0` (format GGUF/llama.cpp) |
| Context 128K | `MAX_MODEL_LEN=131072` |
| 1 wątek | `MAX_NUM_SEQS=1` |
| GPU layers max | `GPU_MEMORY_UTILIZATION=0.95` |
Alternatywa KV cache (więcej miejsca, bliżej Q4): `KV_CACHE_DTYPE=turboquant_k8v4` — testuj po udanym starcie z `fp8`.
> Później porównamy z kopią ustawień LM Studio na Windows i doprecyzujemy parametry.
---
## 8. Struktura plików stacku
```
stacks/vllm/
├── README.md
├── models.catalog.yaml # GGUF + vLLM AWQ, bez auto-pobierania
├── docker-compose.yml
├── .env.example
├── profiles/
│ ├── _template.env
│ └── qwen3.6-27b-awq-128k.env
└── scripts/
├── list-models.sh
├── download-model.sh
├── switch-model.sh
├── start.sh
└── vllm-entrypoint.sh
```
Dane na dysku 1 TB:
```
/data/apps/vllm/huggingface/ ← cache AWQ (Hugging Face)
/data/apps/gguf/ ← przyszłe GGUF (tworzone przez skrypty)
/data/docker/ ← obrazy Docker (vLLM ~10 GB)
```
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/vllm
```
### Kluczowe elementy `docker-compose.yml`
| Element | Po co |
|---------|-------|
| `profiles: [vllm]` | Serwis nie startuje przypadkowo bez `--profile vllm` |
| `ipc: host` | Shared memory — wymagane przez PyTorch |
| `vllm-entrypoint.sh` | Buduje flagi z `.env` (`QUANTIZATION`, `VLLM_EXTRA_ARGS`) |
| `QUANTIZATION` | Opcjonalne — puste = model pełnej precyzji |
| `VLLM_EXTRA_ARGS` | Flagi per profil (Qwen: `--reasoning-parser qwen3`) |
Domyślne flagi w profilu Qwen (przekazywane przez `VLLM_EXTRA_ARGS`):
| Flaga | Po co |
|-------|-------|
| `--language-model-only` | Bez vision encoder — więcej VRAM na KV cache |
| `--enforce-eager` | Mniej overhead CUDA graphs na 24 GB |
| `--max-num-seqs 1` | Jedna sekwencja naraz (jak 1 wątek w LM Studio) |
| `--kv-cache-dtype fp8` | Kompresja KV cache (`KV_CACHE_DTYPE`) |
| `--max-model-len 131072` | Okno kontekstu 128K (`MAX_MODEL_LEN`) |
---
## 9. Przygotowanie stacku (bez modelu)
### 9.1 Utwórz `.env` z szablonu
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/vllm
cp .env.example .env
cat .env
```
Oczekiwane — `VLLM_MODEL` **pusty**:
```env
DATA_ROOT=/data
VLLM_MODEL=
SERVED_MODEL_NAME=qwen3.6-27b
MAX_MODEL_LEN=131072
MAX_NUM_SEQS=1
GPU_MEMORY_UTILIZATION=0.95
KV_CACHE_DTYPE=fp8
QUANTIZATION=awq
VLLM_EXTRA_ARGS=--language-model-only --enforce-eager --reasoning-parser qwen3
```
Na tym etapie **nic nie pobierasz** — stack jest gotowy do konfiguracji.
### 9.2 Katalog modeli
```bash
./scripts/list-models.sh
```
Pokazuje wpisy z `models.catalog.yaml` i czy pliki są już na dysku (`ON DISK`).
### 9.3 Sprawdź katalogi cache
```bash
mkdir -p /data/apps/vllm/huggingface
df -h /data
```
---
## 10. Wybór modelu i start
### 10.1 Pobierz model (on demand)
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/vllm
# vLLM interim — AWQ (~15 GB) do cache HF
./scripts/download-model.sh qwen3.6-27b-awq-vllm
```
GGUF (na później, pod llama.cpp):
```bash
# ./scripts/download-model.sh qwen3.6-27b-q4-gguf
# ./scripts/download-model.sh gemma-4-12b-q4-gguf
```
### 10.2 Preset Qwen3.6-27B AWQ @ 128K
```bash
./scripts/switch-model.sh qwen3.6-27b-awq-128k
```
Alternatywa — ręcznie:
```bash
cp profiles/qwen3.6-27b-awq-128k.env .env
```
### 10.3 Uruchomienie
```bash
./scripts/start.sh
# lub profil w jednej komendzie:
# ./scripts/start.sh qwen3.6-27b-awq-128k
```
Skrypt sprawdza: `VLLM_MODEL` ustawiony, brak `.gguf`, `/data` zamontowany, Docker działa.
Alternatywa ręczna:
```bash
docker compose --profile vllm pull
docker compose --profile vllm up -d
```
### 10.4 Pierwszy start — czego się spodziewać
1. Pobranie obrazu `vllm/vllm-openai` (~812 GB) → `/data/docker`
2. Pobranie modelu AWQ (~15 GB) → `/data/apps/vllm/huggingface`
3. Ładowanie wag do VRAM — **1030+ minut**
```bash
docker compose --profile vllm logs -f vllm
```
Szukaj:
```
INFO: Uvicorn running on http://0.0.0.0:8000
```
### 10.5 Monitorowanie
```bash
# terminal 1
watch -n 1 nvidia-smi
# terminal 2
watch -n 5 'df -h /data; du -sh /data/apps/vllm/huggingface 2>/dev/null'
```
---
## 11. Test API
Użyj `SERVED_MODEL_NAME` z `.env` (domyślnie `qwen3.6-27b-awq` w presecie).
### 11.1 Lista modeli
```bash
curl -s http://localhost:8000/v1/models | jq .
```
### 11.2 Health check
```bash
curl -s http://localhost:8000/health
```
### 11.3 Chat completion
```bash
curl -s http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.6-27b-awq",
"messages": [{"role": "user", "content": "Say hello in one word."}],
"max_tokens": 32
}' | jq .
```
Pole `"model"` musi odpowiadać `SERVED_MODEL_NAME` z `.env`.
---
## 12. Tuning po starcie (jeśli OOM)
Kolejność — zmieniaj w `.env` i restartuj:
```bash
docker compose --profile vllm down
# edytuj .env
docker compose --profile vllm up -d
```
| Krok | Zmiana | Kiedy |
|------|--------|-------|
| 1 | `MAX_MODEL_LEN=98304` lub `65536` | OOM przy ładowaniu lub długim prompcie |
| 2 | `GPU_MEMORY_UTILIZATION=0.90` | Nadal OOM |
| 3 | `KV_CACHE_DTYPE=turboquant_k8v4` | Potrzeba więcej miejsca na KV (bliżej Q4_0) |
---
## 13. Zmiana modelu (A / B na dysku, jeden w VRAM)
Kilka modeli może leżeć na `/data`**aktywny jest tylko jeden** w VRAM. Przełączenie = profil + restart kontenera.
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/vllm
# sprawdź co jest na dysku
./scripts/list-models.sh
# pobierz drugi model (jeśli potrzeba)
# ./scripts/download-model.sh <catalog-id>
# przełącz profil vLLM i zrestartuj
./scripts/switch-model.sh qwen3.6-27b-awq-128k
```
Nowy profil: skopiuj `profiles/_template.env`, dostosuj `VLLM_MODEL`, `QUANTIZATION`, `VLLM_EXTRA_ARGS`.
`start.sh` **odrzuca** `.gguf` w `VLLM_MODEL` — GGUF wymaga przyszłego `stacks/llamacpp/`.
Sprawdź miejsce przed większym modelem:
```bash
df -h /data
du -sh /data/apps/vllm/huggingface
```
---
## 14. Zarządzanie stackiem
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/vllm
docker compose --profile vllm ps
docker compose --profile vllm logs -f vllm
docker compose --profile vllm restart vllm
docker compose --profile vllm down
```
---
## 15. Weryfikacja
### Checklist — cały rozdział 04
**Dysk:**
- [ ] `/data` ~1 TB zamontowany (fstab)
- [ ] `Docker Root Dir: /data/docker`
**vLLM:**
- [ ] `.env` z ustawionym `VLLM_MODEL`
- [ ] `docker compose --profile vllm ps``vllm` running
- [ ] `nvidia-smi` — proces vLLM, VRAM w użyciu
- [ ] `curl http://localhost:8000/v1/models` — JSON z modelem
- [ ] `curl .../v1/chat/completions` — odpowiedź tekstowa
- [ ] Model na `/data/apps/vllm/huggingface`
### Szybki test końcowy
```bash
df -h / /data
docker info | grep "Docker Root Dir"
curl -s http://localhost:8000/v1/models | jq .
du -sh /data/apps/vllm/huggingface /data/docker
```
---
## 16. Troubleshooting
### 16.1 `/data` nie montuje się po reboot
```bash
sudo mount -a
cat /etc/fstab
```
### 16.2 `VLLM_MODEL is empty` lub `.gguf` rejected
```bash
./scripts/list-models.sh
./scripts/download-model.sh qwen3.6-27b-awq-vllm
./scripts/switch-model.sh qwen3.6-27b-awq-128k
```
Jeśli wpisałeś ścieżkę `.gguf` — użyj AWQ (vLLM) lub poczekaj na stack llama.cpp.
### 16.3 OOM na GPU (CUDA out of memory)
Zobacz sekcję 12 (tuning). Typowy zestaw na start po OOM:
```env
MAX_MODEL_LEN=65536
GPU_MEMORY_UTILIZATION=0.90
KV_CACHE_DTYPE=fp8
```
### 16.4 Błąd kwantyzacji AWQ
Upewnij się, że model ma suffix `-AWQ` i `QUANTIZATION=awq` w `.env`.
### 16.5 `connection refused` na :8000
Model jeszcze się ładuje — `docker compose --profile vllm logs -f vllm`.
### 16.6 Wolny pierwszy prefill przy długim kontekście
Normalne przy 128K — pierwsze żądanie z długim promptem trwa dłużej.
### 16.7 Brak miejsca na `/data`
```bash
df -h /data
docker system df
```
---
## 17. Czego nie robimy w tym kroku
| Element | Gdzie |
|---------|-------|
| ComfyUI | Rozdział 06 |
| LocalAI (UI + GGUF) | Rozdział 05 |
| Open WebUI (panel do vLLM) | później, opcjonalnie |
| Pełny Docker llama.cpp / GGUF | placeholder: [`stacks/llamacpp/`](../stacks/llamacpp/) — LocalAI może obsłużyć GGUF |
| Context 262K | start 128K; tuning później |
| Firewall | Rozdział 07 |
---
## 18. Następny krok
Po przejściu checklisty z sekcji 15:
1. Zgłoś w rozmowie z Cursorem, że krok 04 jest gotowy.
2. Przejdź do rozdziału **05 — LocalAI stack** ([`05-localai-stack.md`](05-localai-stack.md)).
---
## Podsumowanie wykonanych zmian
Po ukończeniu tego rozdziału:
- Dysk 1 TB: `/data` (Docker + modele)
- Stack vLLM gotowy bez domyślnego modelu
- Katalog modeli (`models.catalog.yaml`) + skrypty list/download/switch
- Po wyborze: Qwen3.6-27B AWQ (interim Q4), kontekst 128K, KV cache fp8
- GGUF lmstudio — ścieżki na `/data/apps/gguf/`, host llama.cpp planowany
- API OpenAI na porcie 8000
+140
View File
@@ -0,0 +1,140 @@
# 04a — Klucz API Server UI (krok po kroku)
> **Cel:** wpisać poprawny klucz API w panelu `:8091`, żeby działały Start/Stop, CLI, Pliki i GPU Fan.
**Szacowany czas:** 3 minuty
---
## 1. Co to jest klucz API?
To **hasło do panelu** — bez niego możesz tylko **oglądać** status stacków. Z kluczem możesz:
- Start / Stop / Restart stacków
- Terminal **CLI**
- Zakładka **Pliki**
- Sterowanie **GPU Fan**
---
## 2. Gdzie jest JEDYNY plik z kluczem?
Na serwerze produkcyjnym (systemd):
```
/opt/control-plane/.env
```
**Nie używaj** innych plików — stare ścieżki mylą:
| Plik | Status |
|------|--------|
| `/opt/control-plane/.env` | **TAK — używaj tego** |
| `stacks/control-plane/.env` | tylko dev (po sync ma ten sam klucz) |
| `stacks/server-ui/.env` | **NIE** — przestarzałe, ignoruj |
| `GPU_FAN_AGENT_KEY` | **NIE** — usunięte, używaj `API_KEY` |
---
## 3. Wyświetl klucz na serwerze
Zaloguj się na serwer (SSH) i wpisz:
```bash
sudo grep ^API_KEY= /opt/control-plane/.env
```
Przykład wyniku:
```
API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
Skopiuj **tylko** część po `=` (bez słowa `API_KEY=`).
Alternatywa — gotowa instrukcja z linkiem:
```bash
bash ~/cursor/ubuntu-bare-metal/stacks/server-ui/scripts/show-api-key.sh
```
---
## 4. Wpisz klucz w panelu (3 kroki)
### Krok A — otwórz panel
W przeglądarce na swoim komputerze:
```
http://<IP-serwera>:8091/
```
Przykład: `http://192.168.100.90:8091/`
### Krok B — wklej klucz
1. U góry strony znajdź pole **API Key**
2. Wklej skopiowany klucz
3. Kliknij **Zapisz**
### Krok C — sprawdź
1. Kliknij **Sprawdź klucz**
2. Powinno pojawić się: **Klucz poprawny** (zielony tekst)
3. Dopiero teraz używaj Start/Stop, CLI itd.
---
## 5. Szybsza metoda — gotowy link
Zamiast kroków BC możesz otworzyć od razu:
```
http://<IP-serwera>:8091/?api_key=TWÓJ_KLUCZ_Z_KROKU_3
```
Klucz zapisze się w przeglądarce automatycznie. Nadal kliknij **Sprawdź klucz** dla pewności.
---
## 6. Jak sprawdzić że wszystko działa
1. Zakładka **Stacki** → wybierz stack → **Start**
2. Brak czerwonego komunikatu `Invalid or missing API key`
3. Status stacku zmienia się na „running”
---
## 7. Błąd „Invalid or missing API key” — checklist
| # | Sprawdź | Co zrobić |
|---|---------|-----------|
| 1 | Kliknąłeś **Zapisz**? | Wklej klucz → **Zapisz****Sprawdź klucz** |
| 2 | Stary klucz w przeglądarce? | F12 → Application → Local Storage → usuń `server-ui-api-key`, odśwież stronę |
| 3 | Klucz z właściwego pliku? | Tylko `sudo grep ^API_KEY= /opt/control-plane/.env` |
| 4 | Panel po restarcie? | `sudo systemctl restart server-ui` |
| 5 | Właściwy proces na porcie? | `ss -tlnp \| grep 8091` — powinno być `/opt/server-ui` |
---
## 8. Po instalacji panelu
Instalator wypisuje gotowy link z kluczem. Jeśli go nie zapisałeś:
```bash
bash ~/cursor/ubuntu-bare-metal/stacks/server-ui/scripts/show-api-key.sh
```
---
## Podsumowanie
| Pytanie | Odpowiedź |
|---------|-----------|
| Gdzie klucz? | `/opt/control-plane/.env``API_KEY` |
| Jak wyświetlić? | `sudo grep ^API_KEY= /opt/control-plane/.env` |
| Jak wpisać w UI? | Pole API Key → Zapisz → Sprawdź klucz |
| Gotowy link? | `http://IP:8091/?api_key=KLUCZ` |
Powrót: [08 — Server UI](08-server-ui-install.md) · [README](README.md)
+315
View File
@@ -0,0 +1,315 @@
# 05 — LocalAI stack
> **Cel rozdziału:** uruchomić [LocalAI](https://github.com/mudler/LocalAI) w Dockerze z GPU (CUDA 13), wbudowanym UI na porcie **8070** i pustym katalogiem modeli. Modele dodasz później (GGUF, galeria).
**Szacowany czas:**
- Pobranie obrazu Docker: 1030 minut
- Start bez modelu: 12 minuty
**Wymagania:** ukończone rozdziały [01](01-system-update-and-docker.md)[04](04-vllm-stack.md) (część A — dysk `/data` zamontowany)
---
## Spis treści
1. [LocalAI vs vLLM](#1-localai-vs-vllm)
2. [Porty i architektura](#2-porty-i-architektura)
3. [Struktura plików stacku](#3-struktura-plików-stacku)
4. [Przygotowanie `.env`](#4-przygotowanie-env)
5. [Clone upstream (opcjonalnie)](#5-clone-upstream-opcjonalnie)
6. [Instalacja obrazu (bez modelu)](#6-instalacja-obrazu-bez-modelu)
7. [Start stacku](#7-start-stacku)
8. [Weryfikacja UI i API](#8-weryfikacja-ui-i-api)
9. [Zarządzanie stackiem](#9-zarządzanie-stackiem)
10. [Troubleshooting](#10-troubleshooting)
11. [Następny krok](#11-następny-krok)
---
## 1. LocalAI vs vLLM
| | vLLM (`stacks/vllm/`) | LocalAI (`stacks/localai/`) |
|--|----------------------|----------------------------|
| UI | Brak (tylko API) | **Wbudowany chat w przeglądarce** |
| Port | 8000 | **8070** (host) → 8080 (kontener) |
| Modele skwantyzowane | AWQ / HF (nie GGUF) | **GGUF, AWQ**, wiele backendów |
| Ten krok | Obraz pobrany, bez modelu OK | Start **bez modelu** — pusty `/models` |
Oba stacki mogą współistnieć na dysku, ale **nie ładuj dużych modeli na GPU równocześnie** (24 GB VRAM).
---
## 2. Porty i architektura
```mermaid
flowchart LR
browser["Przeglądarka :8070"]
curl["curl / OpenAI SDK"]
localai["Kontener localai"]
gpu["RTX 3090 Ti"]
disk["/data/apps/localai/models"]
browser --> localai
curl --> localai
localai --> gpu
localai --> disk
```
| Element | Wartość |
|---------|---------|
| Obraz | `localai/localai:v4.4.3-gpu-nvidia-cuda-13` |
| UI + API (LAN / tunel) | `http://127.0.0.1:8070` lub publicznie przez NPMPlus (rozdział 07) |
| Modele | `/data/apps/localai/models` |
| Docker data | `/data/docker` |
---
## 3. Struktura plików stacku
```
stacks/localai/
├── README.md
├── docker-compose.yml
├── .env.example
├── .gitignore
├── upstream/ # opcjonalny shallow clone (gitignored)
└── scripts/
├── clone-upstream.sh
├── pull.sh
└── start.sh
```
Katalogi na dysku 1 TB (tworzone przez skrypty):
```
/data/apps/localai/
├── models/
├── backends/
├── configuration/
├── images/
└── data/
```
---
## 4. Przygotowanie `.env`
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/localai
cp .env.example .env
cat .env
```
Oczekiwane:
```env
DATA_ROOT=/data
LOCALAI_PORT=8070
LOCALAI_API_KEY=your-secret-key
LOCALAI_IMAGE=localai/localai:v4.4.3-gpu-nvidia-cuda-13
CUDA_VISIBLE_DEVICES=0
DEBUG=false
```
---
## 5. Clone upstream (opcjonalnie)
Shallow clone repozytorium GitHub — **tylko referencja** (przykładowe YAML modeli). Runtime idzie z oficjalnego obrazu Docker, nie z buildu lokalnego.
```bash
./scripts/clone-upstream.sh
```
Powstaje `stacks/localai/upstream/` (ignorowane przez git).
---
## 6. Instalacja obrazu (bez modelu)
Pobiera wyłącznie obraz Docker — **nie startuje kontenera**, **nie pobiera modeli LLM**.
```bash
./scripts/pull.sh
```
Alternatywa ręczna:
```bash
docker compose --profile localai pull
```
Weryfikacja:
```bash
docker images | grep localai
docker compose --profile localai ps
```
Oczekiwane: obraz widoczny, kontener **nie** działa.
---
## 7. Start stacku
```bash
./scripts/start.sh
```
Skrypt sprawdza: `/data` zamontowany, Docker działa, tworzy katalogi w `/data/apps/localai/`.
Logi:
```bash
docker compose --profile localai logs -f localai
```
---
## 8. Weryfikacja UI i API
### 8.1 Health check
```bash
curl -s http://localhost:8070/readyz
```
Oczekiwane: odpowiedź HTTP 200 (tekst potwierdzający gotowość).
### 8.2 UI w przeglądarce
Otwórz na swoim PC (z sieci LAN):
```
http://127.0.0.1:8070
```
Adres IP serwera:
```bash
hostname -I | awk '{print $1}'
```
UI powinno się załadować — lista modeli będzie **pusta** (to OK na tym etapie).
### 8.3 API (opcjonalnie)
```bash
curl -s http://localhost:8070/v1/models -H "Authorization: Bearer $LOCALAI_API_KEY" | jq .
```
Pusta lista modeli — normalne bez pobranego modelu.
---
## 9. Zarządzanie stackiem
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/localai
docker compose --profile localai ps
docker compose --profile localai logs -f localai
docker compose --profile localai restart localai
docker compose --profile localai down
```
Przed testem modelu w LocalAI — zatrzymaj vLLM jeśli działa:
```bash
cd ../vllm
docker compose --profile vllm down
```
---
## 10. Troubleshooting
### 10.1 `/data` is not mounted
Wróć do [04-vllm-stack.md — część A](04-vllm-stack.md) i dokończ setup dysku.
### 10.2 GPU niewidoczne w kontenerze
```bash
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
```
Upewnij się, że używasz obrazu `-cuda-13`, nie `-cuda-12`.
### 10.3 Healthcheck failing / restarting
```bash
docker compose --profile localai logs --tail 100 localai
```
Pierwszy start może trwać 12 minuty. Healthcheck ma `start_period: 2m`.
### 10.4 UI niedostępne z innego komputera
LocalAI nasłuchuje na `127.0.0.1:8070`. Dostęp z LAN/internetu — przez NPMPlus (rozdział 07) lub SSH tunnel:
```bash
# na swoim PC:
ssh -L 8070:127.0.0.1:8070 tomasz-syn-grzegorza@<IP-serwera>
# potem: http://localhost:8070
```
### 10.5 Brak modeli w UI
Zamierzone na tym kroku. Modele dodasz w kolejnym etapie (Model Gallery, GGUF, CLI).
---
## 11. KV cache (po dodaniu modelu chat)
Domyślnie KV cache w llama.cpp jest w **f16** — zajmuje dużo VRAM przy długim kontekście. Na RTX 3090 Ti (24 GB) rekomendujemy **q8_0** dla K i V.
Ustawienia są w YAML modelu na `/data/apps/localai/models/<nazwa>.yaml`, sekcja `parameters:`:
| Pole | Wartość startowa |
|------|------------------|
| `cache_type_k` | `q8_0` |
| `cache_type_v` | `q8_0` |
| `flash_attention` | `true` |
| `context_size` | `8192` |
Zastosowanie z repo:
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/localai
./scripts/apply-kv-profile.sh gemma-4-12b-it-qat-q4_0
docker compose --profile localai restart localai
```
Skrypt tworzy backup YAML. Pliki w `/data/apps/localai/models/` są często **root-owned** — skrypt używa wtedy `docker exec localai` (volume `/models`).
Szczegóły: [`stacks/localai/coding-agent/KV-CACHE.md`](../stacks/localai/coding-agent/KV-CACHE.md)
Po załadowaniu modelu sprawdź VRAM:
```bash
nvidia-smi
docker compose --profile localai logs localai 2>&1 | tail -50
```
---
## 12. Następny krok
Po przejściu weryfikacji:
1. Zgłoś w rozmowie z Cursorem, że krok 05 jest gotowy.
2. Pobierz model (np. GGUF Qwen z katalogu vLLM) — osobny krok.
3. Później: rozdział **06 — sterowanie wentylatorami GPU** lub **07 — ComfyUI stack**.
---
## Checklist
- [ ] `.env` utworzony z `.env.example`
- [ ] `docker compose --profile localai pull` — obraz pobrany
- [ ] `./scripts/start.sh` — kontener `localai` running
- [ ] `curl http://localhost:8070/readyz` — OK
- [ ] UI otwiera się w przeglądarce na `:8070` (lub przez tunel SSH)
- [ ] Katalogi istnieją pod `/data/apps/localai/`
- [ ] (Po modelu chat) KV cache q8_0 w YAML + restart
+356
View File
@@ -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:** 1520 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) |
| 129% | **Niedozwolone** przez API |
| 30100% | 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. ~5065%).
### 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)
- 37 punktów
- temperatury rosnąco, unikalne
- prędkość: 0 lub 30100
---
## 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
+286
View File
@@ -0,0 +1,286 @@
# 07 — ComfyUI stack
> **Cel rozdziału:** uruchomić [ComfyUI](https://github.com/comfyanonymous/ComfyUI) w Dockerze z GPU, web UI na porcie **8188** i pustym katalogiem modeli. Modele dodasz później (checkpoint, LoRA, ComfyUI-Manager).
**Szacowany czas:**
- Pobranie obrazu Docker: 1030 minut (pierwszy raz)
- Pierwszy start (kopia ComfyUI do `/data`): 310 minut
**Wymagania:** ukończone rozdziały [01](01-system-update-and-docker.md)[05](05-localai-stack.md), mount `/data` z [04](04-vllm-stack.md)
**Kontekst:** Zamiast [Stability Matrix](https://github.com/LykosAI/StabilityMatrix) (GUI desktop) używamy ComfyUI w kontenerze — zgodnie z [03b](03b-system-tools.md) i researchiem w [`coding-agent/STABILITYMATRIX-RESEARCH.md`](../coding-agent/STABILITYMATRIX-RESEARCH.md).
---
## Spis treści
1. [ComfyUI vs Stability Matrix](#1-comfyui-vs-stability-matrix)
2. [Porty i architektura](#2-porty-i-architektura)
3. [Polityka GPU (LocalAI ↔ ComfyUI)](#3-polityka-gpu-localai--comfyui)
4. [Struktura plików stacku](#4-struktura-plików-stacku)
5. [Przygotowanie `.env`](#5-przygotowanie-env)
6. [Instalacja obrazu](#6-instalacja-obrazu)
7. [Start stacku](#7-start-stacku)
8. [Weryfikacja UI](#8-weryfikacja-ui)
9. [Zarządzanie stackiem](#9-zarządzanie-stackiem)
10. [Modele (później)](#10-modele-później)
11. [Troubleshooting](#11-troubleshooting)
12. [Następny krok](#12-następny-krok)
---
## 1. ComfyUI vs Stability Matrix
| | Stability Matrix | ComfyUI (`stacks/comfyui/`) |
|--|------------------|----------------------------|
| Typ | GUI desktop (AppImage) | **Docker, headless** |
| Wymaga pulpitu | Tak (X11/Wayland) | Nie — tylko przeglądarka |
| ComfyUI | Jeden z pakietów SM | **Bezpośrednio** w kontenerze |
| Zgodność z repo | Słaba na SSH-only | **Tak** |
SwarmUI (poprzedni UI obrazów) zostało usunięte — patrz [`SWARMUI-REMOVAL.md`](../coding-agent/SWARMUI-REMOVAL.md).
---
## 2. Porty i architektura
```mermaid
flowchart LR
browser["Przeglądarka :8188"]
comfyui["Kontener comfyui"]
gpu["RTX 3090 Ti"]
disk["/data/apps/comfyui/models"]
browser --> comfyui
comfyui --> gpu
comfyui --> disk
```
| Element | Wartość |
|---------|---------|
| Obraz | `yanwk/comfyui-boot:cu126-slim` |
| Web UI | `http://127.0.0.1:8188` lub `http://192.168.100.90:8188` (LAN) |
| Modele | `/data/apps/comfyui/models` |
| Docker data | `/data/docker` |
---
## 3. Polityka GPU (LocalAI ↔ ComfyUI)
RTX 3090 Ti 24 GB — **nie uruchamiaj** dużego modelu LLM (LocalAI) i dużego checkpointu SD/Flux **równocześnie**.
Przed startem ComfyUI z generowaniem obrazów:
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/localai
docker compose --profile localai stop localai
```
W Server UI (port 8091): Stop/Start stack `localai`, Start stack `comfyui`.
Skrypt `start.sh` ostrzega, gdy `localai` jest uruchomiony.
---
## 4. Struktura plików stacku
```
stacks/comfyui/
├── README.md
├── docker-compose.yml
├── .env.example
├── .gitignore
└── scripts/
├── ensure-dirs.sh
├── pull.sh
└── start.sh
```
Katalogi na dysku 1 TB:
```
/data/apps/comfyui/
├── storage/ # kopia ComfyUI (pierwszy start)
├── models/
├── cache/hf-hub/
├── cache/torch-hub/
├── input/
├── output/
├── custom_nodes/
└── workflows/
```
---
## 5. Przygotowanie `.env`
```bash
cd /home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal/stacks/comfyui
cp .env.example .env
cat .env
```
Domyślne wartości:
| Zmienna | Wartość |
|---------|---------|
| `DATA_ROOT` | `/data` |
| `COMFYUI_PORT` | `8188` |
| `COMFYUI_IMAGE` | `yanwk/comfyui-boot:cu126-slim` |
| `CUDA_VISIBLE_DEVICES` | `0` |
---
## 6. Instalacja obrazu
```bash
./scripts/pull.sh
```
Oczekiwany wynik: pobranie warstw `yanwk/comfyui-boot:cu126-slim` (kilka GB).
---
## 7. Start stacku
```bash
./scripts/start.sh
```
Skrypt:
1. Sprawdza mount `/data`
2. Tworzy katalogi (`ensure-dirs.sh`)
3. Ostrzega, jeśli `localai` działa
4. `docker compose --profile comfyui up -d`
Pierwszy start kopiuje ComfyUI do `/data/apps/comfyui/storage/` — obserwuj logi:
```bash
docker compose --profile comfyui logs -f comfyui
```
---
## 8. Weryfikacja UI
```bash
docker compose --profile comfyui ps
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8188/
```
Oczekiwane: kontener `healthy` lub `running`, HTTP **200** (może zająć ~3 min przy pierwszym starcie).
W przeglądarce (z sieci lokalnej):
```
http://192.168.100.90:8188
```
Tunel SSH z laptopa:
```bash
ssh -L 8188:127.0.0.1:8188 tomasz-syn-grzegorza@gmktec-k11
# potem http://localhost:8188
```
GPU:
```bash
nvidia-smi
```
---
## 9. Zarządzanie stackiem
```bash
docker compose --profile comfyui ps
docker compose --profile comfyui logs -f comfyui
docker compose --profile comfyui restart comfyui
docker compose --profile comfyui down
```
Powrót do LocalAI:
```bash
cd ../comfyui && docker compose --profile comfyui stop comfyui
cd ../localai && docker compose --profile localai start localai
```
---
## 10. Modele (później)
Compose **nie pobiera** modeli automatycznie.
Opcje:
1. **ComfyUI-Manager** w UI — instalacja węzłów i modeli
2. Ręcznie — pliki `.safetensors` / `.ckpt` do `/data/apps/comfyui/models/checkpoints/`
Szacunki VRAM (przy zatrzymanym LocalAI):
| Model | VRAM (orientacyjnie) |
|-------|----------------------|
| SD 1.5 | ~46 GB |
| SDXL | ~812 GB |
| Flux | ~1220 GB |
---
## 11. Troubleshooting
### HTTP nie odpowiada / 000
Pierwszy start trwa dłużej — sprawdź logi:
```bash
docker compose --profile comfyui logs --tail 80 comfyui
```
### `CUDA out of memory`
Zatrzymaj LocalAI i inne workloady GPU:
```bash
docker ps --format '{{.Names}}'
nvidia-smi
```
### Brak `/data`
```bash
mountpoint /data
# jeśli nie — rozdział 04, część A
```
### Kontener restartuje się w pętli
Sprawdź, czy NVIDIA Container Toolkit działa (rozdział 03):
```bash
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu22.04 nvidia-smi
```
---
## 12. Następny krok
Po przejściu weryfikacji:
1. Zgłoś w rozmowie z Cursorem, że krok 07 jest gotowy.
2. Pobierz pierwszy checkpoint (SD 1.5 lub SDXL) — osobny krok.
3. Później: rozdział **08 — firewall i hardening**.
---
## Checklist
- [ ] `.env` utworzony z `.env.example`
- [ ] `docker compose --profile comfyui pull` — obraz pobrany
- [ ] LocalAI zatrzymany przed pierwszym testem generowania (opcjonalnie przy samym starcie UI)
- [ ] `./scripts/start.sh` — kontener `comfyui` running
- [ ] `curl http://127.0.0.1:8188/` — HTTP 200
- [ ] UI otwiera się w przeglądarce na `:8188`
- [ ] Katalogi istnieją pod `/data/apps/comfyui/`
+230
View File
@@ -0,0 +1,230 @@
# 08 — Server UI i panel sterowania (Control Plane)
> **Cel rozdziału:** zainstalować panel Server UI do zarządzania stackami Docker (LocalAI, ComfyUI, vLLM, NPMPlus) oraz zakładkę GPU Fan — i wiedzieć, gdzie są klucze API.
**Szacowany czas:** 1015 minut
**Wymagania:** rozdział [01 — Docker](01-system-update-and-docker.md); opcjonalnie [06 — gpu-fan](06-gpu-fan-control.md) dla zakładki wentylatorów
---
## Spis treści
1. [Co to jest Server UI](#1-co-to-jest-server-ui)
2. [Dlaczego nie ma go w docker ps](#2-dlaczego-nie-ma-go-w-docker-ps)
3. [Instalacja jednym skryptem](#3-instalacja-jednym-skryptem)
4. [Gdzie są klucze API](#4-gdzie-są-klucze-api)
5. [Jak uruchomić i otworzyć panel](#5-jak-uruchomić-i-otworzyć-panel)
6. [Tryb Docker (opcjonalnie)](#6-tryb-docker-opcjonalnie)
7. [Troubleshooting](#7-troubleshooting)
8. [Następny krok](#8-następny-krok)
---
## 1. Co to jest Server UI
**Server UI** to jeden panel w przeglądarce (port **8091**), w którym możesz:
- włączać i wyłączać stacki Docker (Start / Stop / Restart),
- przeglądać logi kontenerów,
- otwierać linki do LocalAI, ComfyUI, vLLM, NPMPlus,
- zmieniać porty usług (zapis do `.env` stacku),
- sterować wentylatorami GPU (zakładka **GPU Fan**).
Zastępuje Portainer i Dockge.
---
## 2. Dlaczego nie ma go w `docker ps`
Komenda `docker ps` pokazuje **tylko kontenery Docker**.
| Co widzisz w `docker ps` | Co to jest |
|--------------------------|------------|
| `comfyui`, `npmplus`, `localai` | Stacki AI / proxy — **Docker** |
| **Brak** `server-ui` | Panel działa jako **usługa systemd** na hoście (domyślnie) |
| **Brak** `gpu-fan` | Agent wentylatorów — też **systemd** na hoście |
To **nie jest błąd**. Panel nie musi być kontenerem.
Sprawdzenie:
```bash
systemctl status server-ui gpu-fan
ss -tln | grep -E '8091|18090'
```
Jeśli wybrałeś instalację Server UI w **Dockerze** (opcja 2 w instalatorze), wtedy zobaczysz kontener:
```bash
docker compose --profile server-ui ps
```
---
## 3. Instalacja jednym skryptem
Na serwerze:
```bash
cd ~/cursor/ubuntu-bare-metal/stacks/server-ui
sudo ./scripts/install-control-plane.sh
```
### Menu instalatora
**1) gpu-fan** — agent sterowania wentylatorami GPU
- Działa **tylko na hoście** (root + NVML).
- **Nie instalujemy go w Dockerze** — karta wymaga bezpośredniego dostępu do sterownika NVIDIA.
- Zalecane: **Y** (tak).
**2) Server UI** — panel w przeglądarce
| Opcja | Opis |
|-------|------|
| **1 — Native** | systemd, `/opt/server-ui` (zalecane) |
| **2 — Docker** | kontener z dostępem do `docker.sock` |
| **3 — Pomiń** | tylko gpu-fan |
### Instalacja bez pytań (domyślnie: gpu-fan + server-ui native)
```bash
sudo ./scripts/install-control-plane.sh -y
```
### Tylko Server UI (bez gpu-fan)
```bash
sudo ./scripts/install-control-plane.sh --gpu-fan=no --server-ui=native
```
---
## 4. Klucz API — wpisz w panelu
**Pełna instrukcja krok po kroku:** [04a — Klucz API](04a-api-key.md)
Skrót po instalacji:
1. Na serwerze: `sudo grep ^API_KEY= /opt/control-plane/.env` — skopiuj wartość po `=`
2. W przeglądarce: `http://<IP-serwera>:8091/` → pole **API Key****Zapisz****Sprawdź klucz**
3. Lub gotowy link: `bash stacks/server-ui/scripts/show-api-key.sh` (wypisze URL z kluczem)
Jeden plik, jeden klucz — `/opt/control-plane/.env` (Server UI + gpu-fan).
**Nie używaj** `stacks/server-ui/.env` ani `GPU_FAN_AGENT_KEY` — to przestarzałe.
---
## 5. Jak uruchomić i otworzyć panel
### Native (systemd)
```bash
sudo systemctl status server-ui
sudo systemctl start server-ui # jeśli zatrzymany
sudo systemctl restart server-ui # po aktualizacji kodu
```
Adres (przykład):
```
http://192.168.100.90:8091/
```
### gpu-fan (jeśli zainstalowany)
```bash
sudo systemctl status gpu-fan
journalctl -u gpu-fan -f
```
### Weryfikacja API
```bash
curl -s http://127.0.0.1:8091/api/health
curl -s http://127.0.0.1:8091/api/stacks
```
### Aktualizacja kodu po zmianach w repo
```bash
cd ~/cursor/ubuntu-bare-metal/stacks/server-ui
sudo ./scripts/install.sh && sudo systemctl restart server-ui
```
---
## 6. Tryb Docker (opcjonalnie)
Jeśli w instalatorze wybrałeś **2 — Docker**:
```bash
cd ~/cursor/ubuntu-bare-metal/stacks/server-ui
docker compose --profile server-ui ps
docker compose --profile server-ui logs -f
docker compose --profile server-ui down # stop
sudo ./scripts/install-docker.sh # ponowna instalacja
```
gpu-fan **nadal** działa na hoście (systemd) — kontener Server UI łączy się z agentem przez `host.docker.internal:18090`.
Przełączenie z Docker na native:
```bash
docker compose --profile server-ui down
sudo ./scripts/install.sh
```
---
## 7. Troubleshooting
### Port 8091 zajęty
```bash
ss -tlnp | grep 8091
systemctl status server-ui
```
Zobacz też: [06 — gpu-fan, sekcja portów](06-gpu-fan-control.md#84-port-8090-zajęty--address-already-in-use) (podobna sytuacja — nie zwiększaj portu bez diagnozy).
### Zakładka GPU Fan nie działa
1. Czy gpu-fan działa: `systemctl status gpu-fan`
2. Czy agent odpowiada:
```bash
API_KEY=$(grep ^API_KEY= /opt/control-plane/.env | cut -d= -f2)
curl -s http://127.0.0.1:18090/api/status -H "X-API-Key: $API_KEY"
```
3. Ten sam klucz w panelu Server UI (pole API Key lub `?api_key=`)
### Start stacku zwraca 401 / Invalid API key
Zobacz [04a — Klucz API, sekcja 7](04a-api-key.md#7-błąd-invalid-or-missing-api-key--checklist).
### Start stacku zwraca 409
Tylko **jeden** duży workload GPU naraz (LocalAI **lub** ComfyUI **lub** vLLM). Zatrzymaj działający stack GPU przed startem drugiego.
---
## 8. Następny krok
- Zarządzaj stackami z panelu :8091
- Edytuj porty usług w kartach stacków (pole **Zapisz port**)
- Przy zmianie portu LocalAI zaktualizuj upstream w NPMPlus ręcznie
Powrót do roadmapy: [README.md](../README.md)
---
## Podsumowanie
| Pytanie | Odpowiedź |
|---------|-----------|
| Gdzie panel? | `http://<IP>:8091/` |
| Dlaczego nie w `docker ps`? | Domyślnie systemd, nie kontener |
| Klucz (Server UI + gpu-fan) | [04a — Klucz API](04a-api-key.md) · `/opt/control-plane/.env` |
| Instalacja | `sudo ./scripts/install-control-plane.sh` |
+117
View File
@@ -0,0 +1,117 @@
# 09 — Przeglądarka plików w Server UI
> **Cel rozdziału:** przeglądać i edytować pliki na serwerze z przeglądarki (zakładka **Pliki** w panelu :8091).
**Szacowany czas:** 10 minut
**Wymagania:** rozdział [08 — Server UI](08-server-ui-install.md) (działający panel + klucz API)
---
## 1. Otwórz zakładkę Pliki
1. Wejdź na panel: `http://<IP-serwera>:8091/`
2. Wpisz **API Key** (toolbar u góry) i kliknij **Zapisz**
3. Kliknij zakładkę **Pliki** (druga od lewej)
Bezpośredni link:
```
http://<IP-serwera>:8091/#files?api_key=TWÓJ_KLUCZ
```
---
## 2. Klucz API
Zobacz [04a — Klucz API](04a-api-key.md): pole **API Key****Zapisz****Sprawdź klucz**.
---
## 3. Nawigacja
| Element | Działanie |
|---------|-----------|
| Lista po lewej | Klik na **folder** → wejście; klik na **plik** → otwarcie w edytorze |
| Breadcrumb u góry | Skróty do katalogów nadrzędnych |
| **↑ Wyżej** | Katalog rodzica |
| **Odśwież** | Ponowne wczytanie listy |
Przykładowe ścieżki:
| Co chcesz zrobić | Ścieżka |
|------------------|---------|
| Repo projektu | `/home/tomasz-syn-grzegorza/cursor/ubuntu-bare-metal` |
| `.env` stacku LocalAI | `.../stacks/localai/.env` |
| Dane aplikacji | `/data/apps/` |
| Logi systemowe | `/var/log/` (jeśli masz uprawnienia) |
---
## 4. Edycja pliku
1. Kliknij plik tekstowy na liście
2. Zawartość pojawi się po prawej
3. Edytuj w polu tekstowym
4. Kliknij **Zapisz**
Pliki **binarne** (obrazy, modele) — tylko podgląd base64, bez zapisu.
---
## 5. Tworzenie i usuwanie
| Przycisk | Działanie |
|----------|-----------|
| **+ Folder** | Nowy podfolder w bieżącym katalogu |
| **+ Plik** | Nowy pusty plik |
| **Zmień nazwę** | Zaznacz element na liście, potem przycisk |
| **Usuń** | Zaznacz element — pojawi się potwierdzenie |
**Uwaga:** Nie można usunąć niepustego folderu — najpierw opróżnij go.
---
## 6. Brak uprawnień — co to znaczy?
Panel działa jako Twój użytkownik Linux (`tomasz-syn-grzegorza`), **nie jako root**.
| Objaw | Przyczyna | Rozwiązanie |
|-------|-----------|-------------|
| „Brak uprawnień” przy `/opt/control-plane/.env` | Plik root-only (600) | `sudo nano /opt/control-plane/.env` w SSH |
| Nie widać cudzego katalogu | Brak prawa odczytu | `sudo` w terminalu lub zmiana właściciela |
| Zapis odrzucony | Brak prawa zapisu | `chmod` / `chown` w SSH |
To normalne — explorer nie omija zabezpieczeń systemu.
---
## 7. Weryfikacja
1. Wejdź w `/tmp`
2. Kliknij **+ Plik**, nazwa: `server-ui-test.txt`
3. Wpisz tekst, **Zapisz**
4. Odśwież — plik na liście
5. **Usuń** plik
---
## 8. Następny krok
- Terminal w przeglądarce: [10 — CLI](10-server-ui-cli.md)
- Edytuj `.env` stacków w `stacks/<nazwa>/.env`
- Zarządzaj stackami w zakładce **Stacki**
- Steruj wentylatorami w **GPU Fan**
Powrót: [README.md](../README.md)
---
## Podsumowanie
| Pytanie | Odpowiedź |
|---------|-----------|
| Gdzie panel? | `http://<IP>:8091/#files` |
| Klucz API? | `sudo grep ^API_KEY= /opt/control-plane/.env` |
| Limit rozmiaru pliku? | 2 MiB (domyślnie) |
| Root w przeglądarce? | Nie — tylko uprawnienia użytkownika panelu |
+122
View File
@@ -0,0 +1,122 @@
# 10 — Terminal CLI w Server UI
> **Cel rozdziału:** uruchomić shell bash w przeglądarce (zakładka **CLI** w panelu :8091) — jak krótkie SSH, ale w UI.
**Szacowany czas:** 5 minut
**Wymagania:** rozdział [08 — Server UI](08-server-ui-install.md) (działający panel + klucz API)
---
## 1. Otwórz zakładkę CLI
1. Wejdź na panel: `http://<IP-serwera>:8091/`
2. Wpisz **API Key** (toolbar u góry) i kliknij **Zapisz**
3. Kliknij zakładkę **CLI** (pierwsza od lewej)
Bezpośredni link:
```
http://<IP-serwera>:8091/#cli?api_key=TWÓJ_KLUCZ
```
Status u góry terminala:
- **Połączono** (zielony) — gotowe
- **Wpisz i zapisz API Key** — brak klucza
- **Rozłączono** — kliknij **Połącz ponownie**
---
## 2. Klucz API
Zobacz [04a — Klucz API](04a-api-key.md): pole **API Key****Zapisz****Sprawdź klucz**.
---
## 3. Podstawowe komendy
W terminalu wpisz jak w SSH:
```bash
whoami
pwd
ls
docker ps
```
Powinieneś zobaczyć użytkownika `tomasz-syn-grzegorza` i dostęp do Dockera.
---
## 4. Programy interaktywne
| Program | Jak wyjść |
|---------|-----------|
| `htop` | klawisz `q` |
| `less plik` | `q` |
| `vim plik` | `:q` lub `:wq` |
| `nano plik` | `Ctrl+O`, `Ctrl+X` |
Zmiana rozmiaru okna przeglądarki dostosowuje terminal automatycznie.
---
## 5. sudo
Możesz użyć `sudo` — terminal poprosi o hasło **Twojego użytkownika Linux** (nie API Key):
```bash
sudo ls /root
```
---
## 6. Ograniczenia
| Co | Wyjaśnienie |
|----|-------------|
| Nie jesteś rootem | Panel działa jako Twój użytkownik — jak zwykłe SSH |
| Nowa sesja po reconnect | Zamknięcie zakładki / **Połącz ponownie** = nowy bash |
| Limit sesji | Domyślnie max 5 równoległych terminali (wszystkie karty) |
| Wyłączenie CLI | Admin może ustawić `CLI_ENABLED=0` w `/opt/control-plane/.env` |
---
## 7a. Pusty terminal (inne zakładki działają)
1. U góry: **Zapisz****Sprawdź klucz** (musi być „Klucz poprawny”)
2. Kliknij **Połącz ponownie**
3. Status powinien zmienić się na **Połączono** — pojawi się prompt bash
4. Jeśli nadal pusto: twardy refresh strony (Ctrl+F5), potem kroki 12
5. Zły klucz: status „Zły klucz API…” — zobacz [04a — Klucz API](04a-api-key.md)
---
## 7. Weryfikacja
1. Zakładka **CLI** → status **Połączono**
2. `echo test-cli-ok` → widzisz `test-cli-ok`
3. `docker ps` → lista kontenerów
4. Zmień rozmiar okna — prompt nie „łamie się” dziwnie
5. Przełącz na **Stacki** i wróć do **CLI** — nowa sesja (to normalne)
---
## 8. Następny krok
- Przeglądaj pliki w zakładce [Pliki](09-file-explorer.md)
- Zarządzaj stackami w **Stacki**
- Steruj wentylatorami w **GPU Fan**
Powrót: [README.md](../README.md)
---
## Podsumowanie
| Pytanie | Odpowiedź |
|---------|-----------|
| Gdzie terminal? | `http://<IP>:8091/#cli` |
| Klucz API? | [04a — Klucz API](04a-api-key.md) |
| Kto jesteś w shellu? | `tomasz-syn-grzegorza` (nie root) |
| vim/htop? | Tak — pełny PTY |