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