Funk-lab/archive/Funk/HOMELAB.md
ALI YESILKAYA c023ab0e58
docs: passe de cohérence documentaire (STT, Ghostfolio, embeddings, Qdrant) (#15)
Aligne la documentation sur l'état réel du cluster au 2026-06-18 :

- Qdrant : crash-loop résolu le 17/06 (statut « HS / EN COURS » corrigé dans
  CLAUDE.md, README, admin/ia/rag.md, admin/incidents.md, admin/ia/stt.md).
  Précision : collection funk-docs supprimée lors de la réparation → re-ingest
  RAG encore à faire (pas de surévaluation du statut).
- STT (assistant vocal « Jarvis ») : ajouté partout (était déployé mais non documenté).
- Ghostfolio : ajouté partout (était déployé mais non documenté).
- Embeddings dédiés nomic-embed-text :1238 : marqués opérationnels (roadmap
  README disait encore « TODO »).
- llama-server : ×3 → ×4 (instance embeddings) ; gap IaC précisé (embeddings géré
  par le rôle, seules les 2 instances CPU restent manuelles).
- Structure k8s/ corrigée dans CLAUDE.md : ajout stt/ + ghostfolio/, suppression
  des sous-dossiers traefik/ + metallb/ inexistants (installés via helm au bootstrap).
- Namespaces et liste des secrets Vault (vault_pg_ghostfolio_password) complétés.
- admin/README.md : index complété (~10 docs manquants : email, n8n, open-webui,
  ghostfolio, k9s, stt, rag, hermes-voice/souls/auto-improve, alertmanager-webhook).
- Funk/ (conception d'origine : LM Studio + agents Goose, obsolète) déplacé sous
  archive/ avec bandeau « obsolète » + archive/README.md (historique git préservé).


Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-18 11:16:34 +02:00

830 lines
35 KiB
Markdown
Raw 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.

# Homelab IA — Architecture et plan de déploiement
> ## ⚠️ DOCUMENT OBSOLÈTE — ARCHIVE HISTORIQUE
>
> Ceci est la **conception d'origine** du homelab (pré-`Funk-lab`). Il décrit des choix
> **abandonnés** : inférence via **LM Studio** (remplacée par llama-server / ROCm) et agents
> **Goose** (remplacés par **Hermes Agent**). **Ce document ne fait plus foi.**
>
> 👉 Référence à jour : [`CLAUDE.md`](../../CLAUDE.md) et la base de connaissance [`admin/`](../../admin/).
> Conservé pour mémoire uniquement — voir [`archive/README.md`](../README.md).
> Document de référence consolidé pour le déploiement d'un homelab IA combinant
> un cluster Kubernetes (Talos) pour les services applicatifs et deux hôtes
> Linux dédiés pour l'inférence LLM (LM Studio) et l'agent autonome (Hermes Agent).
> Stack IaC complète : Ansible + talhelper + ArgoCD, GitOps de bout en bout.
> À utiliser comme contexte pour Claude Code.
---
## 1. Objectifs
- Faire tourner **Hermes Agent** (Nous Research) comme agent autonome
auto-amélioré, alimenté par **LM Studio** comme serveur d'inférence local.
- Apprendre Kubernetes en environnement réaliste (cluster multi-nœuds, GitOps)
pour les services applicatifs (Open WebUI, n8n, monitoring...).
- Apprendre Talos Linux (OS immuable, API-only, pensé pour Kubernetes).
- Maximiser l'utilisation du GPU AMD RX 6700XT pour l'inférence LLM.
- Tout gérer en Infrastructure as Code (versionné dans Git).
## 2. Priorités (par ordre)
1. Facilité d'administration
2. Apprentissage / montée en compétences
3. Performance brute (utiliser le 6700XT au max)
4. Haute disponibilité / résilience
## 3. Vision long terme
- Cible : ~10 machines à 2-3 ans, mix Talos (cluster k8s) + AlmaLinux (services natifs)
- Tout doit être reproductible depuis Git (réinstall complète possible en quelques heures)
- BlueBanquise reste une option à reconsidérer si on dépasse 25+ hôtes Linux classiques
ou si on ajoute du HPC/Slurm
---
## 4. Inventaire matériel
| Machine | CPU | RAM | Stockage | Réseau | Rôle |
|---|---|---|---|---|---|
| **storage-01** | AMD Ryzen 3 3200G (Zen+, 2019) | 32 GB DDR4 | 1× SSD OS + 4×1 TB RAID5 (2.7 TB exploitables) | 1× Gigabit | Hors cluster — passerelle + admin + stockage + Hermes Agent |
| **compute-01** | AMD A10-9700E (Excavator, 2016) | 16 GB DDR3 | SSD SATA | 1× Gigabit (r8169) | k8s control-plane (Talos) |
| **compute-02** | AMD A10-9700E | 8 GB DDR3 | SSD SATA | 1× Gigabit (r8169) | k8s worker (Talos) |
| **compute-03** | AMD A10-9700E | 8 GB DDR3 | SSD SATA | 1× Gigabit (r8169) | k8s worker (Talos) |
| **gpu-01** | AMD Ryzen 9 5950X (16 cœurs) | 32 GB DDR4 | NVMe 1 TB | 1× Gigabit | **Hors cluster** — hôte LM Studio dédié — RX 6700XT 12 GB |
| **switch** | Netgear GS308EV4 (8 ports Gigabit, managé Plus, VLAN 802.1Q) | — | — | — | Switch principal |
**Validation Talos déjà effectuée** : compute-01 boote correctement avec
Talos v1.13.0 en mode maintenance, IP DHCP obtenue, chipset r8169 reconnu nativement.
---
## 5. Architecture réseau
### 5.1. Topologie physique
```
Internet
┌───────────┐
│ Freebox │ 192.168.1.254 (gateway + DHCP LAN domestique)
└─────┬─────┘
│ VLAN 1 (port 1)
┌─────┴────────────────────────────────────────┐
│ Switch Netgear GS308EV4 │
│ P1 P2 P3 P4 P5 P6 P7 P8 │
│ V1 V1 V10 V10 V10 V10 V10 V1 │
└──┬───┬───┬───┬───┬───┬───┬───┬──────────────┘
│ │ │ │ │ │ │ └── PC perso (192.168.1.x)
│ │ │ │ │ │ └────── storage-01 NIC2 (192.168.10.1) ← LAN cluster
│ │ │ │ │ └────────── compute-03 (.10.13)
│ │ │ │ └────────────── compute-02 (.10.12)
│ │ │ └────────────────── compute-01 (.10.11)
│ │ └────────────────────── gpu-01 (.10.20)
│ └────────────────────────── storage-01 NIC1 (192.168.1.200) ← WAN
└────────────────────────────── Freebox
┌──────────────────────────────┐
│ storage-01 (AlmaLinux 9.7) │
│ - NIC1 (port 2) : 192.168.1.200 ← WAN / LAN domestique
│ - NIC2 (port 7) : 192.168.10.1 ← LAN cluster + gateway + NAT
└─────┬────────────────────────┘
│ (routage + NAT entre les deux interfaces)
┌────┴────┬──────────┬──────────┐
│ │ │ │
compute-01 compute-02 compute-03 gpu-01
.10.11 .10.12 .10.13 .10.20
(Talos) (Talos) (Talos) (AlmaLinux + LM Studio)
```
### 5.2. Vue logique des composants IA
```
┌──────────────────────────────────────────────────────────────────────┐
│ Cluster Kubernetes (Talos) │
│ 3 nœuds : compute-01/02/03 │
│ │
│ • Open WebUI • Traefik (ingress) │
│ • LiteLLM (proxy) • MetalLB (LB L2) │
│ • n8n (workflows) • cert-manager │
│ • Prometheus/Grafana • ArgoCD (GitOps) │
└──────────────────┬─────────────────────────┬─────────────────────────┘
│ │
│ NFS / S3 / DB │ HTTP /v1/chat/completions
▼ ▼
┌──────────────────────────────┐ ┌──────────────────────────────────┐
│ storage-01 (AlmaLinux 9.7) │ │ gpu-01 (AlmaLinux 9.7) │
│ 192.168.10.1 HORS CLUSTER │ │ 192.168.10.20 HORS CLUSTER │
│ │ │ │
│ Données : │ │ • LM Studio (mode serveur) │
│ • NFS (/srv/nfs/k8s) │ │ écoute sur :1234 │
│ • PostgreSQL │ │ • API OpenAI-compatible │
│ • Qdrant (vectoriel) │ │ • RX 6700XT via ROCm/Vulkan │
│ • MinIO (S3) │ │ • CLI `lms` pour pilotage │
│ │ │ │
│ Agent IA : │ │ │
│ • Hermes Agent ★ │◄──┤ Hermes appelle LM Studio │
│ (service systemd) │ │ via http://192.168.10.20:1234 │
│ │ │ │
│ Infra : │ │ │
│ • Passerelle / NAT │ │ │
│ • dnsmasq (lab.local) │ │ │
│ • Bastion admin │ │ │
└──────────────────────────────┘ └──────────────────────────────────┘
```
### 5.3. Plan d'adressage IP
**LAN domestique (existant, géré par la Freebox) — 192.168.1.0/24**
| IP | Hôte | Notes |
|---|---|---|
| `192.168.1.254` | Freebox | Gateway internet + DHCP |
| `192.168.1.10` | Machine 9950x3d (poste perso) | Déjà occupé |
| `192.168.1.200` | **storage-01** (interface WAN cluster) | IP statique réservée |
**LAN cluster (nouveau, isolé) — 192.168.10.0/24**
| IP | Hostname | Rôle |
|---|---|---|
| `192.168.10.1` | storage-01 | Gateway + admin + stockage + Hermes Agent (hors cluster k8s) |
| `192.168.10.11` | compute-01 | k8s control-plane (Talos, 16 GB) |
| `192.168.10.12` | compute-02 | k8s worker (Talos, 8 GB) |
| `192.168.10.13` | compute-03 | k8s worker (Talos, 8 GB) |
| `192.168.10.20` | gpu-01 | Hôte LM Studio dédié (AlmaLinux, hors cluster k8s) |
| `192.168.10.200-230` | (pool) | MetalLB — IP virtuelles des services k8s exposés |
**Ports applicatifs notables**
| Hôte | Port | Service | Notes |
|---|---|---|---|
| gpu-01 | 1234 | LM Studio API (OpenAI-compatible) | `http://192.168.10.20:1234/v1` |
| storage-01 | 22 | SSH (bastion + cible Ansible) | |
| storage-01 | 53 | dnsmasq | Résolution `*.lab.local` |
| storage-01 | 2049 | NFS | Export `/srv/nfs/k8s` |
| storage-01 | 5432 | PostgreSQL | |
| storage-01 | 6333 | Qdrant HTTP | |
| storage-01 | 9000 | MinIO S3 | |
| storage-01 | 9001 | MinIO Console | |
| MetalLB | 80/443 | Traefik | Tous les Ingress du cluster |
| MetalLB | 8080 | ArgoCD UI | `argocd.lab.local` |
**Réseaux internes Kubernetes (ne pas modifier sauf raison spécifique)**
- Pods (Flannel) : `10.42.0.0/16`
- Services : `10.43.0.0/16`
### 5.4. Câblage du switch GS308EV4
Tous les ports en mode **Access** (pas de trunk). storage-01 utilise deux NICs physiques — une par VLAN.
| Port | Connecté à | VLAN | Mode |
|---|---|---|---|
| 1 | Freebox | 1 - Default | Access |
| 2 | storage-01 NIC1 (WAN, 192.168.1.200) | 1 - Default | Access |
| 3 | gpu-01 (192.168.10.20) | 10 - cluster-funk | Access |
| 4 | compute-01 (192.168.10.11) | 10 - cluster-funk | Access |
| 5 | compute-02 (192.168.10.12) | 10 - cluster-funk | Access |
| 6 | compute-03 (192.168.10.13) | 10 - cluster-funk | Access |
| 7 | storage-01 NIC2 (LAN cluster, 192.168.10.1) | 10 - cluster-funk | Access |
| 8 | PC perso (192.168.1.x) | 1 - Default | Access |
**Avantage vs trunk** : pas de subinterface `eno1.10` à configurer — deux interfaces physiques classiques dans NetworkManager. Plus simple, moins de risque d'erreur au démarrage.
### 5.5. Route statique sur la Freebox
À configurer dans *Paramètres Freebox > Mode avancé > Configuration de routage* :
```
Réseau de destination : 192.168.10.0
Masque : 255.255.255.0
Passerelle : 192.168.1.200
```
Cela permet à toutes les machines du LAN domestique de joindre directement le LAN cluster.
---
## 6. Choix d'OS
| Machine | OS | Justification |
|---|---|---|
| storage-01 | **AlmaLinux 9.7 minimal** | Stack RHEL maîtrisée, stabilité, support sécurité jusqu'en 2032, doc abondante NFS/nftables/MinIO/Postgres |
| compute-01 | **Talos Linux v1.13+** | Choix d'apprentissage assumé, validation matérielle OK |
| compute-02 | **Talos Linux v1.13+** | idem |
| compute-03 | **Talos Linux v1.13+** | idem |
| gpu-01 | **AlmaLinux 9.7 minimal** | Cohérence RHEL avec storage-01, ROCm via repo officiel AMD pour RHEL 9 |
**Note sur AlmaLinux + ROCm pour gpu-01** : la majorité de la doc communautaire
ROCm + RX 6700XT vise Ubuntu. Sur AlmaLinux 9, utiliser le repo officiel AMD
pour RHEL 9 (`https://repo.radeon.com/rocm/`). Adapter les commandes dnf au
lieu d'apt. En cas de blocage ROCm, Vulkan reste un fallback fonctionnel pour LM Studio.
---
## 7. Architecture applicative
### 7.1. Topologie cluster Kubernetes
- **Control-plane** : single (compute-01 uniquement)
- **Workers** : compute-02, compute-03
- **storage-01 et gpu-01 sont HORS du cluster**
### 7.2. Découpage des responsabilités
**gpu-01 — Hôte d'inférence LLM (hors cluster)**
- LM Studio en mode serveur headless
- API OpenAI-compatible exposée sur `:1234`
**storage-01 — Bastion admin + données + agent (hors cluster)**
- Passerelle réseau (NAT, routage VLAN)
- Bastion : `talosctl`, `kubectl`, `helm`, `argocd` CLI, `ansible`
- Services données : NFS, PostgreSQL, Qdrant, MinIO
- **Hermes Agent** en service systemd
- dnsmasq pour la résolution `*.lab.local`
**Cluster Kubernetes (Talos, 3 nœuds)**
- Couche infra : MetalLB, Traefik, cert-manager, Longhorn, nfs-subdir-external-provisioner
- Couche observabilité : kube-prometheus-stack, Loki
- Couche applicative IA : Open WebUI, LiteLLM, n8n
- **GitOps via ArgoCD**
### 7.3. Flux principal Hermes ↔ LM Studio
```
Utilisateur → CLI Hermes / Telegram / autre interface
(sur storage-01)
Hermes Agent (skills, mémoire, tools)
[storage-01 :daemon systemd]
│ HTTP POST /v1/chat/completions
LM Studio (modèle chargé en VRAM 6700XT)
[gpu-01 :1234]
│ Réponse streaming
Hermes Agent (parsing tool calls, exécution)
Utilisateur
```
### 7.4. Deux setups IA — poste perso vs cluster Funk
#### Setup 1 — Poste perso (9950X3D) — dev local
**Matériel** : Ryzen 9 9950X3D · 32 GB DDR5 · RX 9070 XT 16 GB VRAM
| Composant | Config |
|---|---|
| LM Studio | `http://127.0.0.1:1234/v1` (bind localhost par défaut) |
| Ollama | `http://127.0.0.1:11434` (aussi installé) |
| Hermes Agent | config `base_url: http://127.0.0.1:1234/v1` |
| Goose agents | `Funk/Funk-infra/agents/` → pointent sur `http://localhost:1234/v1` |
**Démarrage LM Studio :**
```bash
# Charger le modèle avec un context suffisant (système Hermes ≈ 15 000 tokens)
lms load <modele> --context-length 16384
lms server start --port 1234
```
**Config Hermes (`~/.hermes/config.yaml`) :**
```yaml
model:
default: <nom-modele>
provider: lmstudio
base_url: http://127.0.0.1:1234/v1
context_length: 16384
```
**Goose agents :**
```bash
cd Funk/Funk-infra/agents/<nom-agent>
goose session --config goose-config.yaml
```
| Agent Goose | Modèle cible | Usage |
|---|---|---|
| `global` | qwen2.5-14b | Raisonnement général |
| `infra` | qwen2.5-coder-14b | k8s, Talos, Helm, ArgoCD |
| `sysadmin` | qwen2.5-7b | Admin système, diagnostics |
| `monitoring` | llama3.2-3b | Logs, métriques |
| `data` | qwen2.5-14b | Analyse de données |
---
#### Setup 2 — Cluster Funk (production)
**Matériel GPU** : gpu-01, Ryzen 9 5950X · 32 GB DDR4 · RX 6700XT 12 GB VRAM
| Composant | Config |
|---|---|
| LM Studio | `http://192.168.10.20:1234/v1` (bind `0.0.0.0`) |
| Hermes Agent | service systemd sur storage-01 |
| Hermes `base_url` | `http://192.168.10.20:1234/v1` |
**Démarrage LM Studio sur gpu-01 :**
```bash
HSA_OVERRIDE_GFX_VERSION=10.3.0 lms load <modele> --context-length 16384
lms server start --port 1234 --host 0.0.0.0
```
**Config Hermes sur storage-01 (`~/.hermes/config.yaml`) :**
```yaml
model:
default: <nom-modele>
provider: lmstudio
base_url: http://192.168.10.20:1234/v1
context_length: 16384
```
**Différence clé avec setup 1** : `HSA_OVERRIDE_GFX_VERSION=10.3.0` obligatoire pour la RX 6700XT (gfx1031 non officiellement supporté par ROCm). Sur la RX 9070 XT du poste perso, cette variable n'est pas nécessaire.
---
## 8. Stack IaC / Automatisation
### 8.1. Principe : un seul repo Git, trois flux de déploiement
Toute l'infrastructure est gérée en GitOps depuis un repo Git unique. Trois outils
se partagent les responsabilités selon la cible :
```
┌──────────────────────────────────────────────────────────────────┐
│ Repo Git du lab (sur poste admin + remote Gitea/GitHub privé) │
│ │
│ lab-infra/ │
│ ├── ansible/ ← gère storage-01 + gpu-01 │
│ │ ├── inventory.yml │
│ │ ├── playbooks/ │
│ │ ├── roles/ │
│ │ └── group_vars/ │
│ ├── talos/ ← configs Talos via talhelper │
│ │ ├── talconfig.yaml │
│ │ ├── talsecret.sops.yaml │
│ │ └── clusterconfig/ (généré par talhelper) │
│ ├── k8s/ ← manifests / Helm values │
│ │ ├── apps/ ← apps déployées par ArgoCD │
│ │ ├── infra/ ← MetalLB, Traefik, cert-manager... │
│ │ └── argocd-bootstrap/ ← Application of Applications │
│ └── docs/ │
│ └── HOMELAB.md ← ce document │
└────────┬─────────────────────────┬────────────────────┬──────────┘
│ │ │
│ ansible-playbook │ talosctl │ git push
│ (push manuel SSH) │ apply-config │ → ArgoCD
│ │ (push manuel) │ pull auto
▼ ▼ ▼
storage-01, compute-01/02/03 Workloads dans
gpu-01 (Talos) le cluster k8s
(AlmaLinux)
```
### 8.2. Outil 1 — Ansible (vanilla) pour les hôtes Linux classiques
**Cible** : storage-01 et gpu-01 (et futures machines AlmaLinux/Debian).
**Choix** : Ansible vanilla, **rôles écrits from scratch**. Pas de framework type
BlueBanquise — surdimensionné pour 5-10 hôtes Linux à terme. À reconsidérer si
on dépasse 25+ hôtes ou si on ajoute du HPC/Slurm.
**Structure des rôles prévus** :
```
ansible/
├── ansible.cfg
├── inventory.yml
├── group_vars/
│ ├── all.yml # variables communes (DNS, NTP, users)
│ ├── gateway.yml # variables passerelle
│ └── gpu_hosts.yml # variables hôtes GPU
├── host_vars/
│ ├── storage-01.yml
│ └── gpu-01.yml
├── playbooks/
│ ├── site.yml # playbook racine
│ ├── storage-01.yml
│ └── gpu-01.yml
└── roles/
├── common/ # paquets de base, sshd, sudoers, motd
├── gateway/ # NetworkManager VLAN, IP forwarding, nftables, NAT
├── dnsmasq/ # DNS local *.lab.local
├── nfs_server/ # NFS server + exports
├── postgresql/ # Postgres + DB init
├── qdrant/ # Qdrant via Podman
├── minio/ # MinIO via Podman
├── rocm/ # repo AMD + drivers + HSA_OVERRIDE
├── lm_studio/ # install + service systemd
└── hermes_agent/ # install + config + systemd unit
```
**Inventaire** :
```yaml
# ansible/inventory.yml
all:
children:
gateway:
hosts:
storage-01:
ansible_host: 192.168.10.1
gpu_hosts:
hosts:
gpu-01:
ansible_host: 192.168.10.20
almalinux:
children:
gateway:
gpu_hosts:
```
**Lancement type** :
```bash
cd ansible/
ansible-playbook -i inventory.yml playbooks/site.yml --check # dry-run
ansible-playbook -i inventory.yml playbooks/site.yml # apply
ansible-playbook -i inventory.yml playbooks/site.yml --tags rocm # cibler 1 rôle
```
**Bonnes pratiques** :
- Tous les rôles **idempotents** (peuvent être ré-exécutés sans casse).
- Variables sensibles dans **Ansible Vault** (mot de passe Postgres, clés API).
- Un playbook = une machine ou un groupe, pas de "playbook fourre-tout".
- Tags systématiques pour cibler un rôle spécifique.
### 8.3. Outil 2 — talhelper pour les nœuds Talos
**Cible** : compute-01, compute-02, compute-03.
**Pourquoi talhelper** : `talosctl gen config` brut produit des configs longues
et difficiles à maintenir. `talhelper` lit un seul fichier `talconfig.yaml`
clair et génère les configs YAML par nœud, avec gestion des secrets (chiffrement
SOPS) et patches par nœud.
**Structure** :
```
talos/
├── talconfig.yaml # config déclarative (lue par talhelper)
├── talsecret.sops.yaml # secrets chiffrés (token bootstrap, certs CA)
├── talenv.yaml # version Talos, version k8s
├── patches/ # patches YAML par nœud ou groupe
│ ├── compute-01.yaml
│ └── all-controlplane.yaml
└── clusterconfig/ # généré : ne PAS commit (au .gitignore)
├── lab-compute-01.yaml
├── lab-compute-02.yaml
└── lab-compute-03.yaml
```
**Workflow** :
```bash
cd talos/
# 1. Éditer talconfig.yaml (ajout d'un nœud, changement de version k8s, etc.)
vim talconfig.yaml
# 2. Régénérer les configs nœud
talhelper genconfig
# 3. Appliquer sur un nœud spécifique
talhelper gencommand apply --node compute-02 | bash
# 4. Bootstrap (uniquement la première fois, sur le control-plane)
talhelper gencommand bootstrap --node compute-01 | bash
# 5. Récupérer le kubeconfig
talhelper gencommand kubeconfig | bash
```
**Avantage GitOps** : le `talconfig.yaml` est ta source de vérité. N'importe qui
(toi dans 6 mois) peut lire ce fichier et comprendre l'état du cluster Talos
sans avoir à inspecter les nœuds.
### 8.4. Outil 3 — ArgoCD pour les workloads Kubernetes
**Cible** : tout ce qui tourne dans le cluster k8s (apps + infra k8s).
**Principe** : ArgoCD surveille en continu un dossier Git et garantit que l'état
réel du cluster correspond à ce qui est déclaré dans Git.
**Pattern recommandé : "App of Apps"**
```
k8s/
├── argocd-bootstrap/ # bootstrap ArgoCD lui-même
│ └── argocd-install.yaml
├── apps-of-apps/
│ └── root.yaml # une Application qui pointe sur apps/
├── infra/ # déployé d'abord
│ ├── metallb/
│ │ ├── application.yaml
│ │ └── values.yaml
│ ├── traefik/
│ ├── cert-manager/
│ ├── longhorn/
│ └── nfs-provisioner/
└── apps/ # déployé ensuite
├── litellm/
│ ├── application.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── ingress.yaml
├── open-webui/
├── n8n/
├── monitoring/ # kube-prometheus-stack
└── external-services/ # ExternalName vers storage-01
├── postgresql-external.yaml
├── qdrant-external.yaml
└── lm-studio-external.yaml # ExternalName vers gpu-01:1234
```
**Workflow d'utilisation** :
```bash
# 1. Modifier un manifest
vim k8s/apps/open-webui/deployment.yaml
# 2. Commit + push
git add k8s/apps/open-webui/
git commit -m "open-webui: bump to v0.4.0, add OIDC config"
git push
# 3. ArgoCD détecte le changement (poll par défaut toutes les 3 min)
# → applique automatiquement dans le cluster
# → visible dans l'UI argocd.lab.local
```
**Bénéfices** :
- Source de vérité unique (Git)
- Historique complet via `git log`
- Rollback en `git revert` + push
- Recréation totale du cluster en cas de désastre : install Talos via talhelper,
install ArgoCD via le bootstrap, ArgoCD redéploie tout le reste tout seul
### 8.5. Récapitulatif des responsabilités
| Outil | Cible | Mode de déploiement | Stockage source |
|---|---|---|---|
| **Ansible** | Hôtes Linux classiques (storage-01, gpu-01, futures Alma) | Push manuel (`ansible-playbook`) | `lab-infra/ansible/` |
| **talhelper** | Nœuds Talos (compute-01/02/03) | Push manuel (`talosctl apply-config`) | `lab-infra/talos/` |
| **ArgoCD** | Workloads Kubernetes (apps + infra k8s) | Pull automatique depuis Git | `lab-infra/k8s/` |
### 8.6. Repo Git : où l'héberger ?
**Court terme** : repo local sur ton poste + remote sur **GitHub** (privé) ou
**GitLab** (privé) → simple et fiable.
**Moyen terme (recommandé)** : héberger un **Gitea** ou **Forgejo** sur
storage-01 (rôle Ansible dédié) + miroir GitHub pour backup. Avantages :
- Indépendance totale (pas besoin d'Internet pour déployer)
- Apprentissage de l'auto-hébergement Git
- ArgoCD pointe sur `git.lab.local/admin/lab-infra.git`
### 8.7. Gestion des secrets
**Pas de secrets en clair dans Git, jamais.** Trois mécanismes selon la couche :
- **Ansible** : Ansible Vault pour les secrets (`ansible-vault encrypt_string`)
- **Talos** : SOPS + age (intégré nativement à talhelper)
- **Kubernetes** : Sealed Secrets (Bitnami) ou External Secrets Operator
pointant sur un Vault — pour démarrer, Sealed Secrets est plus simple
---
## 9. Feuille de route par phases
Chaque phase est validable indépendamment. Ne passer à la suivante que quand
la précédente fonctionne.
### Phase 0 — Préparation
- [x] Validation matérielle Talos sur 1 ThinkCentre (compute-01) ✅ effectué
- [ ] Vérifier que tous les ThinkCentre ont des SSD SATA opérationnels
- [ ] Préparer 1 clé USB pour Talos + 1 clé USB pour AlmaLinux
- [ ] Initialiser le repo Git `lab-infra/` sur le poste admin
### Phase 1 — Infra réseau (storage-01 manuel + bootstrap Ansible)
- [x] Installation AlmaLinux sur storage-01 ✅
- [x] Configuration IP de base — storage-01 joignable (192.168.10.1 LAN cluster) ✅
- [x] IP WAN storage-01 fixée à 192.168.1.200 ✅
- [x] Configuration VLAN sur le GS308EV4 ✅ — tous ports Access, storage-01 sur deux NICs physiques
- [ ] Initialiser `lab-infra/ansible/` avec inventory + rôle `common` + rôle `gateway`
- [ ] Premier `ansible-playbook` qui configure VLAN/nftables/NAT/IP forwarding
- [ ] Route statique sur la Freebox
- [ ] Rôle `dnsmasq` pour résolution `*.lab.local`
- [ ] Validation : ping bidirectionnel LAN domestique ↔ LAN cluster
### Phase 2 — Hôte gpu-01 + LM Studio (Ansible)
- [x] Installation AlmaLinux sur gpu-01 ✅ — ping OK depuis storage-01
- [ ] Ajout de gpu-01 à l'inventaire Ansible
- [ ] Rôle `rocm` : repo AMD + drivers + `HSA_OVERRIDE_GFX_VERSION=10.3.0`
- [ ] Validation ROCm : `rocminfo` doit lister la RX 6700XT
- [ ] Rôle `lm_studio` : install + service systemd avec bind `0.0.0.0:1234`
- [ ] Téléchargement d'un modèle test (Hermes 4, Qwen 2.5 7B...)
- [ ] Validation : `curl http://192.168.10.20:1234/v1/models` depuis storage-01
### Phase 3 — Hermes Agent sur storage-01 (Ansible)
- [ ] Rôle `hermes_agent` : install via script officiel
- [ ] Configuration provider custom endpoint (LM Studio gpu-01)
- [ ] Premier `hermes chat` interactif
- [ ] (Optionnel) Service systemd pour daemon background
- [ ] Données persistantes (`~/.hermes/`) sur le RAID5
### Phase 4 — Stack données sur storage-01 (Ansible)
- [ ] Rôle `nfs_server` : export `/srv/nfs/k8s` vers `192.168.10.0/24`
- [ ] Rôle `postgresql` : install + DB init
- [ ] Rôle `qdrant` : Podman + service systemd
- [ ] Rôle `minio` : Podman + service systemd
- [ ] Validation : tous les services accessibles depuis le LAN cluster
### Phase 5 — Cluster Talos (talhelper)
- [ ] Génération image Talos via factory.talos.dev (extensions `iscsi-tools`)
- [ ] Init `lab-infra/talos/` avec `talconfig.yaml` (3 nœuds)
- [ ] `talhelper genconfig`
- [ ] Apply sur compute-01 (control-plane) puis bootstrap etcd
- [ ] Apply sur compute-02 et compute-03 (workers)
- [ ] Validation : `kubectl get nodes` montre 3 nœuds Ready
### Phase 6 — Bootstrap ArgoCD + infra k8s (GitOps)
- [ ] Install ArgoCD manuel via Helm (une seule fois, l'install ArgoCD reste manuelle)
- [ ] Init `lab-infra/k8s/` avec App of Apps pattern
- [ ] Création des Applications ArgoCD pour : MetalLB, Traefik, cert-manager
- [ ] Validation : pod nginx test exposé via Ingress, accessible depuis le LAN
### Phase 7 — Stockage k8s (ArgoCD)
- [ ] Application ArgoCD : `nfs-subdir-external-provisioner` pointant sur storage-01
- [ ] Application ArgoCD : Longhorn (avec `iscsi-tools` extension Talos)
- [ ] Validation : 1 PVC NFS + 1 PVC Longhorn créés et montés
### Phase 8 — Apps IA (ArgoCD)
- [ ] Applications ArgoCD : ExternalName vers Postgres, Qdrant, LM Studio
- [ ] Application ArgoCD : LiteLLM (proxy vers LM Studio)
- [ ] Application ArgoCD : Open WebUI (front, pointe sur LiteLLM)
- [ ] Application ArgoCD : n8n
- [ ] Application ArgoCD : kube-prometheus-stack + Loki
- [ ] Validation finale : workflow n8n → Open WebUI → LiteLLM → LM Studio
### Phase 9 — Optionnel : Gitea local + miroir
- [ ] Rôle Ansible `gitea` sur storage-01
- [ ] Migration du repo `lab-infra` vers Gitea local
- [ ] Reconfiguration ArgoCD pour pointer sur `git.lab.local`
- [ ] Miroir push vers GitHub privé (sauvegarde)
---
## 10. Points d'attention spécifiques
### 10.1. RX 6700XT et ROCm sur AlmaLinux 9
- gfx1031 non officiellement supporté par ROCm
- **Variable obligatoire** : `HSA_OVERRIDE_GFX_VERSION=10.3.0`
- ROCm s'exécute directement sur l'OS hôte (gpu-01), pas dans des conteneurs
- Fallback Vulkan possible dans LM Studio si ROCm coince
- Doc ROCm pour RHEL 9 : https://rocm.docs.amd.com/projects/install-on-linux/
### 10.2. LM Studio en mode serveur
- Par défaut LM Studio bind sur `127.0.0.1` → inaccessible depuis le réseau
- Forcer `0.0.0.0` via CLI : `lms server start --port 1234 --host 0.0.0.0`
- LM Studio CLI : `lms ls`, `lms load <model>`, `lms unload`, `lms server status`
### 10.3. Hermes Agent
- Daemon : possible via systemd unit
- Mémoire/skills stockés dans `~/.hermes/`**à mettre sur le RAID5**
- Variables `.env` dans `~/.hermes/.env`
### 10.4. RAM serrée sur ThinkCentre 8 GB
- Réserver système+kubelet : `system-reserved=cpu=500m,memory=1Gi`,
`kube-reserved=cpu=500m,memory=1Gi`
- Toujours définir `resources.requests/limits` sur les pods
- Sinon risque OOM-killer sur le nœud entier
### 10.5. Single control-plane
- Si compute-01 tombe, plus de `kubectl apply` mais les workloads continuent
- Snapshots etcd réguliers : `talosctl etcd snapshot` vers storage-01 (cron Ansible)
### 10.6. RAID5 sur storage-01
- 4×1 TB = 2.7 TB exploitables
- Sauvegarder : configs k8s (Git), bases de données (dump périodique
vers MinIO ou NAS externe), mémoire/skills Hermes (`~/.hermes/`)
- Pas les modèles LM Studio (re-téléchargeables)
### 10.7. Sécurité passerelle = bastion admin
- storage-01 cumule passerelle + bastion + Hermes + données → SPOF assumé
- gpu-01 sans rôle réseau critique : si tombe, perte inférence uniquement
### 10.8. Bootstrap : ce qui reste manuel
GitOps ne peut pas faire le bootstrap absolu. Restent toujours manuels :
- Installation OS sur chaque machine (AlmaLinux ou Talos depuis USB)
- Configuration IP/SSH minimale pour qu'Ansible puisse se connecter
- Premier déploiement ArgoCD via Helm
- Tout le reste est ensuite géré par Ansible / talhelper / ArgoCD
---
## 11. Outils à installer sur storage-01 (bastion admin)
```bash
# Outils Kubernetes / Talos
- talosctl (admin Talos)
- talhelper (génération configs Talos)
- kubectl (admin Kubernetes)
- helm (charts)
- argocd CLI
- k9s (TUI Kubernetes)
# Outils IaC
- ansible-core
- sops + age (secrets Talos)
# Outils IA
- hermes (Hermes Agent)
- curl/jq (debug API LM Studio)
# Outils système
- nftables, dnsmasq, nfs-utils, postgresql-server, podman
- minio, qdrant (binaires ou conteneurs Podman)
# Optionnel
- gitea ou forgejo (Git local)
- restic ou borgbackup (sauvegardes)
```
Tous installés via les rôles Ansible — pas de installation manuelle au-delà
du bootstrap initial.
---
## 12. Conventions et nommage
- Hostnames : `storage-01`, `compute-01`, `compute-02`, `compute-03`, `gpu-01`
- Domaine local : `lab.local`
- Services exposés via cluster : `<service>.lab.local` → IP MetalLB de Traefik
- Endpoint LM Studio : `http://192.168.10.20:1234/v1` (ou `lms.lab.local`)
- Namespaces k8s :
- `argocd` (ArgoCD lui-même)
- `infra` (MetalLB, Traefik, cert-manager, monitoring)
- `storage` (Longhorn, NFS provisioner)
- `external` (ExternalName vers services storage-01/gpu-01)
- `ai` (Open WebUI, LiteLLM)
- `workflows` (n8n)
- Git :
- Branches : `main` (= prod), `feature/*` (changements en cours)
- Commits : conventional commits (`feat:`, `fix:`, `chore:`, `docs:`)
---
## 13. État actuel (2026-05-09)
- ✅ Architecture validée
- ✅ Test Talos sur compute-01 effectué (boot OK, IP DHCP, talosctl répond)
- ✅ Stack IaC choisie : Ansible vanilla + talhelper + ArgoCD
- ✅ Hermes Agent configuré sur le poste perso (Setup 1 — 9950X3D + LM Studio local)
- ✅ AlmaLinux installé sur storage-01 — ping OK (`192.168.1.200` WAN, `192.168.10.1` LAN cluster)
- ✅ AlmaLinux installé sur gpu-01 — ping OK depuis storage-01 (`192.168.10.20`)
- ✅ Connectivité LAN cluster (VLAN 10) : storage-01 ↔ gpu-01 fonctionnelle
- ⏳ Phase 1 en cours : Ansible + rôles + dnsmasq + NAT à configurer
- ⏳ Phase 2 en cours : ROCm + LM Studio sur gpu-01 à installer
- ❌ Ansible pas encore exécuté (repo `lab-infra/` à initialiser)
- ❌ VLAN switch GS308EV4 à confirmer / finaliser
- ❌ Route statique Freebox à configurer
- ❌ Aucun cluster k8s monté
- ❌ LM Studio pas encore installé sur gpu-01
- ❌ Hermes Agent pas encore installé sur storage-01
---
## 14. Annexes — Liens utiles
**Infrastructure**
- Talos Linux : https://www.talos.dev/
- Image Factory Talos : https://factory.talos.dev/
- talhelper : https://github.com/budimanjojo/talhelper
- AlmaLinux 9 : https://almalinux.org/
- ROCm install (RHEL 9) : https://rocm.docs.amd.com/projects/install-on-linux/
**Kubernetes / GitOps**
- ArgoCD : https://argo-cd.readthedocs.io/
- ArgoCD App of Apps pattern : https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-bootstrapping/
- Sealed Secrets : https://github.com/bitnami-labs/sealed-secrets
- Longhorn : https://longhorn.io/
- MetalLB : https://metallb.universe.tf/
**IaC**
- Ansible docs : https://docs.ansible.com/
- Ansible Vault : https://docs.ansible.com/ansible/latest/vault_guide/index.html
- SOPS : https://github.com/getsops/sops
**IA**
- LM Studio : https://lmstudio.ai/
- LM Studio CLI : https://lmstudio.ai/docs/cli
- Hermes Agent : https://github.com/NousResearch/hermes-agent
- LiteLLM : https://docs.litellm.ai/
- Open WebUI : https://docs.openwebui.com/