Funk-lab/admin/install/gpu-01.md
ALI YESILKAYA af98b47018
docs(cluster): aligne la doc sur l'état réel + re-ingest RAG + fix ubatch embed (#44)
* fix(rag): ubatch=2048 pour llama-embed + retry rag-ingest + nettoie defaults rag

L'instance llama-embed (:1238) tournait avec l'ubatch llama.cpp par défaut (512).
En mode --embeddings + pooling, toute l'entrée doit tenir dans un seul ubatch →
tout chunk > 512 tokens échouait en HTTP 500 « input too large to process.
increase the physical batch size ». ~46 chunks du RAG (CHUNK_MAX=2000 chars ≈
700 tokens) n'étaient pas indexés.

- llama_server : ajoute llama_embed_ubatch_size (2048 = ctx) + flags
  --batch-size/--ubatch-size dans le template llama-embed.service.
- rag-ingest : retry (5×, backoff) sur erreurs transitoires 5xx/réseau de l'embed.
- rag/defaults : aligne embed_url/embed_model sur nomic :1238 (étaient des vars
  mortes pointant encore qwen3-8b :1234 — trompeuses).

Résultat : ré-ingestion 436/436 chunks, 0 erreur.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(cluster): aligne la doc sur l'état réel (relevé 2026-06-21) + snapshot

Passe de vérification terrain (SSH s01/g01 + kubectl) pour corriger les écarts
doc↔réalité, et ajout d'un document de référence vérifié.

- admin/ops/etat-cluster.md (nouveau) : snapshot daté — machines, services+ports
  par hôte, workloads k8s, namespaces, IngressRoute, bases PG, modèles LiteLLM,
  RAG/Qdrant, + procédure pour régénérer le relevé.
- OS AlmaLinux 9.7 → 9.8 (s01/g01) ; précise k8s v1.33.1 (CLAUDE/README/install/talos).
- RAG funk-docs : retire le warning périmé « supprimée 2026-06-17 / à re-ingérer » →
  reconstruite (436 chunks, nomic-embed-text :1238 dim 768, CPU). Maj rag.md,
  incidents.md, stt.md.
- Namespace sacrifice (hors-repo, hors ArgoCD) + bases PG grafana/sacrifice +
  services ai via IngressRoute + registry in-cluster (CLAUDE.md, k9s.md).
- Services de résilience (llm-heartbeat, llama-watchdog/embed) et instances CPU
  manuelles :1236/:1237 (souvent éteintes) documentés.
- Journal progress/2026-06-21.md : section relevé + RAG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 23:29:05 +02:00

365 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Installation gpu-01
Guide d'installation complet de gpu-01 — de l'ISO AlmaLinux 9.7 à llama-server
en production avec ROCm sur RX 6700XT. Écrit après installation réelle.
---
## Sommaire
1. [Rôle et architecture](#1-rôle-et-architecture)
2. [Installation AlmaLinux 9.7 (base OS)](#2-installation-almalinux-97-base-os)
3. [Configuration réseau initiale (manuelle)](#3-configuration-réseau-initiale-manuelle)
4. [Prérequis : storage-01 opérationnel](#4-prérequis--storage-01-opérationnel)
5. [Jouer le playbook Ansible](#5-jouer-le-playbook-ansible)
6. [Vérifications post-install](#6-vérifications-post-install)
7. [Pièges et incidents rencontrés](#7-pièges-et-incidents-rencontrés)
---
## 1. Rôle et architecture
gpu-01 est le serveur d'inférence LLM du lab. Il n'est pas dans le cluster Kubernetes.
Il est consommé par storage-01 (LiteLLM le pointe directement via HTTP).
### Ce qu'il fait
| Fonction | Détail |
|---|---|
| Inférence LLM | llama-server (llama.cpp) via ROCm 7.x sur RX 6700XT 12 GB VRAM |
| Embeddings | `/v1/embeddings` OpenAI-compatible (`--embeddings --pooling mean`) |
| NFS client | Monte `/srv/data/models` depuis storage-01 → symlink pour llama-server |
### Matériel
| Composant | Détail |
|---|---|
| CPU | AMD Ryzen 5 3600 (6c/12t) |
| RAM | 32 GB DDR4 |
| GPU | AMD RX 6700XT — 12 GB VRAM, architecture RDNA2 (gfx1031) |
| OS | AlmaLinux 9.8 (installé depuis ISO 9.7, point releases via `dnf update`) |
| Disque | SSD SATA 500 GB (OS + binaires) |
| Stockage modèles | NFS via storage-01 `/srv/data/models` → monté sur `/mnt/models` |
### Contrainte critique — RX 6700XT (gfx1031)
La RX 6700XT n'est **pas officiellement supportée** par ROCm. Son GFX ID est `gfx1031`.
ROCm ne reconnaît que jusqu'à `gfx1030` dans la plupart des versions.
**Workaround permanent** dans tout service qui utilise le GPU :
```
HSA_OVERRIDE_GFX_VERSION=10.3.0
```
Sans cette variable, ROCm ne voit pas le GPU et l'inférence tombe sur le CPU.
---
## 2. Installation AlmaLinux 9.7 (base OS)
Même ISO que storage-01 : AlmaLinux 9.7 minimal.
```bash
sudo dd if=AlmaLinux-9.7-x86_64-minimal.iso of=/dev/sdX bs=4M status=progress conv=fsync
```
### Paramètres d'installation (Anaconda)
**Réseau** : gpu-01 est dans le LAN cluster — il n'a pas d'accès direct au LAN domestique.
Pour accéder à internet pendant l'install (télécharger les packages ROCm), il faut que
storage-01 soit déjà en ligne et fasse le NAT.
Configurer l'interface réseau :
- IP statique : `192.168.10.20/24`
- Gateway : `192.168.10.1` (storage-01)
- DNS : `192.168.10.1`
- Hostname : `gpu-01`
**Disque** : sélectionner le SSD SATA (pas le NVMe si présent — celui-ci peut être
réservé à autre chose). Partitionnement automatique LVM convient.
**Utilisateur** : root avec mot de passe temporaire.
---
## 3. Configuration réseau initiale (manuelle)
Avant Ansible, vérifier que gpu-01 est joignable via storage-01 :
```bash
# Depuis le poste perso via jump
ssh -J ansible@192.168.1.200 root@192.168.10.20
```
Depuis storage-01 :
```bash
ping 192.168.10.20 # doit répondre
```
Si storage-01 n'a pas encore `192.168.10.20 gpu-01` dans `/etc/hosts` :
```bash
ssh s01 "echo '192.168.10.20 gpu-01' | sudo tee -a /etc/hosts"
```
Vérifier que gpu-01 a accès à internet via storage-01 (NAT) :
```bash
ssh -J s01 root@192.168.10.20 "ping -c3 8.8.8.8"
```
---
## 4. Prérequis : storage-01 opérationnel
gpu-01 dépend de storage-01 pour :
- **DNS** : `192.168.10.1` doit résoudre `lab.local`
- **NAT** : pour télécharger les packages ROCm (~10 GB de téléchargements)
- **NFS** : `/srv/data/models` doit être exporté pour monter les modèles
Vérifier avant de continuer :
```bash
ssh s01 "sudo systemctl is-active dnsmasq nftables nfs-server"
# → active / active / active
```
---
## 5. Jouer le playbook Ansible
Tout se lance depuis le poste perso à la racine du repo.
### Test de connectivité
```bash
make ping
# gpu-01 doit maintenant répondre
```
Si gpu-01 n'est pas encore dans l'inventaire, il l'est déjà (`ansible/inventory.yml`) :
```yaml
gpu_hosts:
hosts:
gpu-01:
ansible_host: 192.168.10.20
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o ProxyJump=root@192.168.1.200'
```
La première exécution se fait en root. Après le rôle `common`, ce sera le compte `ansible`.
### Phase 1 — Base OS
```bash
cd ansible && ../.venv/bin/ansible-playbook playbooks/gpu-01.yml --tags common
```
Même chose que storage-01 : hostname, timezone, EPEL, user ansible, SSH durci.
### Phase 2 — ROCm
```bash
cd ansible && ../.venv/bin/ansible-playbook playbooks/gpu-01.yml --tags rocm
```
Le rôle `rocm` fait :
- Ajoute le repo AMD officiel (`amdgpu-install`)
- Installe ROCm 7.x (`rocm-hip-sdk`, `rocm-opencl-runtime`, `rocminfo`, `clinfo`)
- Ajoute l'user `ansible` aux groupes `video` et `render` (accès GPU sans root)
- Déploie `/etc/environment` et `/etc/profile.d/rocm.sh` avec `HSA_OVERRIDE_GFX_VERSION=10.3.0`
- Reload udev pour les permissions GPU
> L'installation ROCm pèse environ 8-10 GB — prévoir 15-20 minutes selon la connexion.
> gpu-01 télécharge via le NAT de storage-01.
Vérifier :
```bash
ssh g01 "HSA_OVERRIDE_GFX_VERSION=10.3.0 rocminfo | grep -A3 'Agent 2'"
# doit lister : AMD Radeon RX 6700 XT, gfx1031
```
### Phase 3 — NFS client (modèles)
```bash
cd ansible && ../.venv/bin/ansible-playbook playbooks/gpu-01.yml --tags nfs_client
```
Le rôle `nfs_client` fait :
- Installe `nfs-utils`, `autofs`
- Configure les montages dans `/etc/fstab` (ou automount) :
- `/mnt/nfs``192.168.10.1:/srv/data/nfs/k8s`
- `/mnt/models``192.168.10.1:/srv/data/models`
- Options : `nfsvers=4,soft,timeo=30,retrans=3,x-systemd.automount`
- Crée le symlink `/opt/lmstudio/.lmstudio/models``/mnt/models`
> Les montages sont `soft` avec timeout : si storage-01 est éteint, gpu-01 boot
> normalement et ne reste pas bloqué à attendre le NFS.
Vérifier :
```bash
ssh g01 "df -h /mnt/models"
ssh g01 "ls /mnt/models/"
# → bartowski/Qwen3-8B-GGUF/ (ou autre modèle présent sur le RAID)
```
### Phase 4 — llama-server (inférence ROCm)
```bash
cd ansible && ../.venv/bin/ansible-playbook playbooks/gpu-01.yml --tags llama_server
```
Le rôle `llama_server` fait :
- Télécharge le binaire `llama-server` pré-compilé pour ROCm (release llama.cpp GitHub)
- Déploie `/etc/systemd/system/llama-server.service` :
- `HSA_OVERRIDE_GFX_VERSION=10.3.0` dans l'environnement
- `--model /mnt/models/bartowski/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf`
- `--alias qwen3-8b`
- `--ctx-size 32768`
- `--host 0.0.0.0 --port 1234`
- `--embeddings --pooling mean` (pour `/v1/embeddings` OAI-compatible)
- Active et démarre `llama-server.service`
Variables dans `host_vars/gpu-01/vars.yml` :
```yaml
llama_model_path: "/mnt/models/bartowski/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf"
llama_model_alias: "qwen3-8b"
llama_ctx_size: 32768
```
> Avec un contexte de 32768 tokens, l'empreinte mémoire est :
> ~5 GB modèle + ~3 GB KV cache = ~8 GB sur 12 GB VRAM.
> Ajuster `llama_ctx_size` si un modèle plus lourd est utilisé.
---
## 6. Vérifications post-install
### Checklist
```bash
# 1. GPU détecté par ROCm
ssh g01 "HSA_OVERRIDE_GFX_VERSION=10.3.0 rocminfo | grep -E 'Agent|gfx'"
# 2. NFS monté
ssh g01 "df -h /mnt/models && ls /mnt/models/"
# 3. llama-server actif
ssh g01 "sudo systemctl is-active llama-server"
ssh g01 "curl -s http://localhost:1234/v1/models | python3 -m json.tool"
# 4. Inférence fonctionnelle (test depuis storage-01)
ssh s01 "curl -s http://192.168.10.20:1234/v1/chat/completions \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer lm-studio' \
-d '{\"model\":\"qwen3-8b\",\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}],\"max_tokens\":10}'"
# 5. Embeddings fonctionnels
ssh s01 "curl -s http://192.168.10.20:1234/v1/embeddings \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer lm-studio' \
-d '{\"model\":\"qwen3-8b\",\"input\":\"test\"}' | python3 -c 'import sys,json; d=json.load(sys.stdin); print(len(d[\"data\"][0][\"embedding\"]), \"dimensions\")'"
# → 4096 dimensions
```
### VRAM en cours d'inférence
```bash
ssh g01 "watch -n 2 'cat /sys/class/drm/card*/device/mem_info_vram_used'"
# Affiche la VRAM utilisée en octets — diviser par 1073741824 pour avoir des GB
```
---
## 7. Pièges et incidents rencontrés
---
### ❌ ROCm ne voit pas le GPU — HSA_OVERRIDE absent
**Symptôme** : `rocminfo` liste uniquement le CPU, pas le GPU RX 6700XT.
llama-server démarre mais tourne sur le CPU → ~2 tok/s au lieu de ~35 tok/s.
**Cause** : La RX 6700XT est `gfx1031`, non officiel dans ROCm. Sans `HSA_OVERRIDE_GFX_VERSION=10.3.0`,
ROCm ignore ce GPU.
**Fix** : La variable doit être présente dans :
1. `/etc/environment` (sessions interactives)
2. Le `[Service]` de `llama-server.service` (service systemd)
```ini
[Service]
Environment=HSA_OVERRIDE_GFX_VERSION=10.3.0
```
Géré par le rôle Ansible `llama_server`. Vérifier :
```bash
ssh g01 "sudo systemctl cat llama-server | grep HSA"
```
---
### ❌ Gemma 4 — crash ROCm au-delà de 800 tokens
**Symptôme** : llama-server crash ou freeze dès que le contexte dépasse ~800 tokens
avec les modèles Gemma 4.
**Cause** : Bug de compatibilité entre l'architecture Gemma 4 et le backend ROCm
sur cette combinaison ROCm 7.x + gfx1031 (non officiel). Non reproduit avec Qwen3.
**Fix** : Utiliser Qwen3-8B ou Qwen2.5-14B. Ne pas charger de modèles Gemma 4 sur gpu-01.
---
### ❌ Embeddings — erreur si --pooling absent
**Symptôme** : Requêtes vers `/v1/embeddings` retournent une erreur 500 ou des vecteurs vides.
**Cause** : llama-server nécessite `--embeddings` ET `--pooling mean` pour activer
les embeddings OAI-compatible. `--embeddings` seul active le endpoint mais sans
pooling les résultats sont incorrects.
**Fix** : Le service doit avoir les deux flags :
```
--embeddings --pooling mean
```
Géré par le rôle Ansible `llama_server`.
---
### ❌ NFS bloquant au boot si storage-01 est éteint
**Symptôme** : gpu-01 boot très lentement (plusieurs minutes) ou reste bloqué en
attendant les montages NFS si storage-01 n'est pas allumé.
**Cause** : Montages NFS en `hard` (comportement par défaut) — le client attend
indéfiniment que le serveur réponde.
**Fix** : Options `soft,timeo=30,retrans=3` dans fstab/automount + `x-systemd.automount`.
Avec `soft`, si storage-01 ne répond pas en 30 × timeo ms, le montage échoue proprement
et gpu-01 continue à démarrer. Le montage sera réessayé au premier accès.
Géré par le rôle Ansible `nfs_client`.
---
### ❌ llama-server redémarre pas si modèle indisponible au boot
**Symptôme** : `llama-server.service` en `failed` au démarrage car `/mnt/models/...`
n'est pas encore monté (NFS automount).
**Cause** : Conflit d'ordre de démarrage — llama-server démarre avant que
le montage NFS soit déclenché.
**Fix** : `After=mnt-models.automount` dans le `.service`. Géré par Ansible.
Ou simplement `sudo systemctl start llama-server` après boot.
---
### Résumé des points d'attention
| Sujet | Règle |
|---|---|
| HSA_OVERRIDE | `HSA_OVERRIDE_GFX_VERSION=10.3.0` dans tout service GPU et dans `/etc/environment` |
| Gemma 4 | Interdit sur gpu-01 — crash ROCm >800 tokens |
| Embeddings | `--embeddings --pooling mean` obligatoires ensemble |
| Contexte 32k | ~8 GB VRAM sur 12 GB — ajuster si modèle plus lourd |
| NFS boot | Options `soft,timeo=30` — jamais `hard` |
| ROCm install | ~10 GB de téléchargement — prévoir le NAT storage-01 opérationnel |