359afb3a59
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>
774 lines
20 KiB
Markdown
774 lines
20 KiB
Markdown
# 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
|