# 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 --context-length 16384 lms server start --port 1234 ``` **Config Hermes (`~/.hermes/config.yaml`) :** ```yaml model: default: provider: lmstudio base_url: http://127.0.0.1:1234/v1 context_length: 16384 ``` **Goose agents :** ```bash cd Funk/Funk-infra/agents/ 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 --context-length 16384 lms server start --port 1234 --host 0.0.0.0 ``` **Config Hermes sur storage-01 (`~/.hermes/config.yaml`) :** ```yaml model: default: 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 `, `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 : `.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/