# 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.7 | | 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 | --- ## État vérifié — 2026-06-05 - **Services critiques** : Tous les services (llama-server, systemd, NFS) actifs sans dégradation - **OS/Kernel** : AlmaLinux 9.7 / Linux 5.14.0-687.5.3.el9_8.x86_64 - **Espace disque** : /boot à 74% (sur 960M), autres partitions sous 25% - **Conformité** : Aucune divergence détectée avec la documentation - **Observation** : L'export NFS vers /srv/data/models fonctionne normalement (2.7T disponibles)