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>
This commit is contained in:
ALI YESILKAYA 2026-06-18 11:16:34 +02:00 committed by GitHub
parent e1ec26d546
commit c023ab0e58
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 102 additions and 31 deletions

View file

@ -0,0 +1,880 @@
# 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 | Exports `/srv/data/nfs/k8s` + `/srv/data/models` |
| 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 --bind 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
- [x] `lab-infra/ansible/` initialisé — inventory, rôles common + gateway ✅
- [x] nftables/NAT/IP forwarding opérationnels ✅
- [x] Rôle `dnsmasq` — résolution `*.lab.local`
- [ ] Route statique sur la Freebox (LAN domestique → LAN cluster)
- [ ] 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
- [x] Ajout de gpu-01 à l'inventaire Ansible ✅
- [x] Rôle `rocm` : repo AMD + drivers + `HSA_OVERRIDE_GFX_VERSION=10.3.0`
- [x] Validation ROCm : RX 6700XT détectée ✅
- [x] Rôle `lm_studio` : install + service systemd + bind `0.0.0.0:1234`
- [x] Téléchargement modèles : gemma-4-e2b, gemma-4-e4b ✅
- [x] Validation : `curl http://192.168.10.20:1234/v1/models`
### 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 sur le RAID5 (`/srv/data/hermes`)
### Phase 4 — Stack données sur storage-01 (Ansible)
- [x] Rôle `nfs_server` : RAID5 `md127` monté `/srv/data`, exports NFS ✅
- [x] Rôle `nfs_client` sur gpu-01 — automount `/mnt/nfs` + `/mnt/models`
- [x] Modèles LM Studio migrés sur NFS (`/srv/data/models`) ✅
- [ ] 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
**Installation** : script officiel `https://lmstudio.ai/install.sh` — nécessite un patch ELF
sur `watcher.node` (module Node natif compilé GCC 12) car AlmaLinux 9 / GCC 11 ne fournit
que `GLIBCXX_3.4.29` alors que le binaire requiert `GLIBCXX_3.4.30`. Le symbole concerné
existe dans la libstdc++ système sous `GLIBCXX_3.4.11` — le patch réécrit le VERNEED ELF.
Détail complet : `ansible/roles/lm_studio/TROUBLESHOOTING.md`.
**Service systemd** : `lm-studio.service` sur gpu-01, géré par Ansible.
- Wrapper `run-llmster.sh` comme PID principal (reste en vie, surveille `llmster`)
- `Restart=on-failure` pour redémarrage automatique
- `HSA_OVERRIDE_GFX_VERSION=10.3.0` injecté dans l'environnement du service
**CLI** : `/usr/local/bin/lms` est un wrapper global (délègue au user `lmstudio`)
```bash
lms ls # liste les modèles
lms get <modele> # télécharger
lms load <modele> --context-length 16384 # charger en mémoire
lms server status
```
**Modèles** : stockés sur le NFS partagé (`/srv/data/models` sur storage-01),
montés sur gpu-01 via automount systemd (`/mnt/models`).
`/opt/lmstudio/.lmstudio/models` est un symlink → `/mnt/models`.
Tout modèle téléchargé avec `lms get` atterrit directement sur le RAID.
**Endpoint** : `http://192.168.10.20:1234/v1` (API OpenAI-compatible)
### 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
- **Dispositif** : `md127` (mdadm software RAID5, 4×1 TB = 2.7 TB utiles, ext4)
- **Monté** : `/srv/data` — point de montage principal de toutes les données persistantes
- **Superbloc mdadm sur les disques** : survit à un changement d'OS, ré-assemblage auto au boot
- **Arborescence** :
```
/srv/data/
├── nfs/k8s/ → NFS provisioner Kubernetes
├── models/ → modèles LM Studio (partagés avec gpu-01 via NFS)
├── hermes/ → mémoire/skills Hermes Agent
├── postgres/ → données PostgreSQL
├── qdrant/ → données Qdrant
└── minio/ → données MinIO
```
- **À sauvegarder** : configs k8s (Git), dumps BDD, mémoire Hermes (`/srv/data/hermes`)
- **Modèles LLM** : stockés sur le RAID (`/srv/data/models`) — re-téléchargeables si perte
### 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-10)
### Rôles Ansible déployés
| Rôle | Cible | État |
|---|---|---|
| `common` | storage-01, gpu-01 | ✅ |
| `gateway` | storage-01 | ✅ nftables, NAT, IP forwarding |
| `dnsmasq` | storage-01 | ✅ résolution `*.lab.local` |
| `nfs_server` | storage-01 | ✅ RAID5 monté `/srv/data`, exports NFS |
| `nfs_client` | gpu-01 | ✅ automount `/mnt/nfs` + `/mnt/models` |
| `rocm` | gpu-01 | ✅ RX 6700XT détectée |
| `lm_studio` | gpu-01 | ✅ service actif, API accessible |
| `postgresql` | storage-01 | ❌ stub vide |
| `qdrant` | storage-01 | ❌ stub vide |
| `minio` | storage-01 | ❌ stub vide |
| `hermes_agent` | storage-01 | ❌ stub vide |
### Infrastructure
- ✅ storage-01 opérationnel — `192.168.1.200` (WAN) / `192.168.10.1` (LAN cluster)
- ✅ gpu-01 opérationnel — `192.168.10.20`, LM Studio accessible
- ✅ RAID5 `md127` monté `/srv/data` (2.7 TB, ext4, état clean)
- ✅ NFS exports actifs : `/srv/data/nfs/k8s`, `/srv/data/models`
- ✅ LM Studio `http://192.168.10.20:1234/v1` — répond depuis storage-01
- ✅ Modèles sur NFS : gemma-4-e2b, gemma-4-e4b, nomic-embed-text
- ❌ Route statique Freebox non configurée (LAN domestique → LAN cluster)
- ❌ Premier commit GitHub non effectué
- ❌ Cluster k8s non démarré (Phase 5)
- ❌ Hermes Agent non installé sur storage-01 (Phase 3)
---
## 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/

View file

@ -0,0 +1,25 @@
# Funk — Agents locaux (Goose + LM Studio)
Chaque agent a son propre profil Goose et son modèle LM Studio dédié.
Tous pointent sur le même serveur LM Studio (port 1234), modèle spécifié par agent.
## Agents
| Agent | Modèle | Usage |
|---|---|---|
| `global` | qwen2.5-14b | Raisonnement général, coordination |
| `monitoring` | llama3.2-3b | Surveillance logs/métriques, léger et rapide |
| `sysadmin` | qwen2.5-7b | Administration système, maintenance |
| `infra` | qwen2.5-coder-14b | Kubernetes, Talos, Helm, ArgoCD |
| `data` | qwen2.5-14b | Analyse de données, rapports |
## Prérequis
LM Studio daemon + server démarrés, modèles chargés (voir commandes ci-dessous).
## Lancer un agent
```bash
cd agents/<nom-agent>
goose session --config goose-config.yaml
```

View file

@ -0,0 +1,18 @@
version: "1.0"
profile:
name: funk-data
description: "Agent data — analyse de données, logs, métriques, rapports"
provider: openai
model: qwen2.5-14b-instruct
base_url: http://localhost:1234/v1
api_key: lm-studio
system_prompt: |
Tu es l'agent data de funk. Tu analyses des données brutes et tu produis des insights.
Tu traites des logs système, métriques Prometheus, exports Grafana, dumps de bases de données.
Tu génères des rapports structurés en markdown. Tu identifies les tendances et anomalies.
Sois précis et chiffré dans tes analyses. Inclus toujours un résumé exécutif en tête de rapport.
extensions:
- shell
- file_manager

View file

@ -0,0 +1,19 @@
version: "1.0"
profile:
name: funk-global
description: "Agent général funk — raisonnement, planification, coordination"
provider: openai
model: qwen2.5-14b-instruct
base_url: http://localhost:1234/v1
api_key: lm-studio
system_prompt: |
Tu es funk, un assistant IA intelligent intégré à un homelab Kubernetes.
Tu coordonnes les autres agents spécialisés et tu prends les décisions de haut niveau.
Tu connais l'infrastructure : cluster Talos Linux, GPU AMD RX 6700XT, storage-01 AlmaLinux.
Réseau cluster : 192.168.10.0/24, domaine lab.local.
Tu réponds toujours en français sauf si on te parle en anglais.
extensions:
- shell
- file_manager

View file

@ -0,0 +1,19 @@
version: "1.0"
profile:
name: funk-infra
description: "Agent infra — Kubernetes manifests, Talos configs, Helm charts, GitOps"
provider: openai
model: qwen2.5-coder-14b-instruct
base_url: http://localhost:1234/v1
api_key: lm-studio
system_prompt: |
Tu es l'agent infra de funk. Tu gères tout ce qui est infrastructure as code.
Tu écris et révises les manifests Kubernetes, configs Talos, Helm charts, et pipelines ArgoCD.
Conventions : namespaces = infra / storage / ai / workflows / argocd. Domaine = lab.local.
MetalLB pool : 192.168.10.200-230. CNI : Flannel. Ingress : Traefik.
GPU node : gpu-01 — taint gpu=amd:NoSchedule, HSA_OVERRIDE_GFX_VERSION=10.3.0 obligatoire.
extensions:
- shell
- file_manager

View file

@ -0,0 +1,18 @@
version: "1.0"
profile:
name: funk-monitoring
description: "Agent monitoring — surveillance logs, métriques, alertes"
provider: openai
model: llama3.2-3b-instruct
base_url: http://localhost:1234/v1
api_key: lm-studio
system_prompt: |
Tu es l'agent monitoring de funk. Tu surveilles les logs et métriques du cluster.
Tu analyses les fichiers de logs, détectes les anomalies, et génères des rapports concis.
Sois direct et factuel. Si tu détectes un problème, indique le niveau de sévérité : INFO, WARN, CRITICAL.
Réseau cluster : 192.168.10.0/24. Nodes : compute-01/02/03 (10.11-13), gpu-01 (10.20), storage-01 (10.1).
extensions:
- shell
- file_manager

View file

@ -0,0 +1,19 @@
version: "1.0"
profile:
name: funk-sysadmin
description: "Agent sysadmin — administration système, maintenance, diagnostics"
provider: openai
model: qwen2.5-7b-instruct
base_url: http://localhost:1234/v1
api_key: lm-studio
system_prompt: |
Tu es l'agent sysadmin de funk. Tu administres les machines du homelab.
Tu exécutes des commandes système, vérifies l'état des services, effectues la maintenance.
Stack : AlmaLinux 9.7 (storage-01), Talos Linux (compute-01/02/03, gpu-01).
Sois prudent avant d'exécuter des commandes destructives — demande confirmation.
Outils dispo : ssh, talosctl, kubectl, systemctl, nftables.
extensions:
- shell
- file_manager