diff --git a/.gitignore b/.gitignore index 66e95a7..80ff8df 100644 --- a/.gitignore +++ b/.gitignore @@ -21,9 +21,6 @@ keys.txt # Journaux de session (notes de debug, IPs, infos locales) progress/ -# Documentation réseau domestique (topologie LAN privée) -Funk/ - # Divers .DS_Store *.swp diff --git a/Funk/Funk-infra/HOMELAB.md b/Funk/Funk-infra/HOMELAB.md new file mode 100644 index 0000000..0a07ab0 --- /dev/null +++ b/Funk/Funk-infra/HOMELAB.md @@ -0,0 +1,871 @@ +# Homelab IA — Architecture et plan de déploiement + +> 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 --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 --bind 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 +- [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 # télécharger +lms load --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 : `.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/ diff --git a/Funk/Funk-infra/agents/README.md b/Funk/Funk-infra/agents/README.md new file mode 100644 index 0000000..b7b8616 --- /dev/null +++ b/Funk/Funk-infra/agents/README.md @@ -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/ +goose session --config goose-config.yaml +``` diff --git a/Funk/Funk-infra/agents/data/goose-config.yaml b/Funk/Funk-infra/agents/data/goose-config.yaml new file mode 100644 index 0000000..d66189a --- /dev/null +++ b/Funk/Funk-infra/agents/data/goose-config.yaml @@ -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 diff --git a/Funk/Funk-infra/agents/global/goose-config.yaml b/Funk/Funk-infra/agents/global/goose-config.yaml new file mode 100644 index 0000000..fea4c75 --- /dev/null +++ b/Funk/Funk-infra/agents/global/goose-config.yaml @@ -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 diff --git a/Funk/Funk-infra/agents/infra/goose-config.yaml b/Funk/Funk-infra/agents/infra/goose-config.yaml new file mode 100644 index 0000000..883ba58 --- /dev/null +++ b/Funk/Funk-infra/agents/infra/goose-config.yaml @@ -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 diff --git a/Funk/Funk-infra/agents/monitoring/goose-config.yaml b/Funk/Funk-infra/agents/monitoring/goose-config.yaml new file mode 100644 index 0000000..52175da --- /dev/null +++ b/Funk/Funk-infra/agents/monitoring/goose-config.yaml @@ -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 diff --git a/Funk/Funk-infra/agents/sysadmin/goose-config.yaml b/Funk/Funk-infra/agents/sysadmin/goose-config.yaml new file mode 100644 index 0000000..be5e5bf --- /dev/null +++ b/Funk/Funk-infra/agents/sysadmin/goose-config.yaml @@ -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 diff --git a/Funk/HOMELAB.md b/Funk/HOMELAB.md new file mode 100644 index 0000000..fb4ae2b --- /dev/null +++ b/Funk/HOMELAB.md @@ -0,0 +1,821 @@ +# Homelab IA — Architecture et plan de déploiement + +> 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/ diff --git a/admin/hermes.md b/admin/hermes.md index 3c050ac..e930514 100644 --- a/admin/hermes.md +++ b/admin/hermes.md @@ -44,15 +44,17 @@ sudo journalctl -u hermes-dashboard -f ## TUI (chat interactif) -Le TUI nécessite un terminal interactif (PTY). Lancer depuis une session SSH : +Le TUI nécessite un terminal interactif (PTY) et doit tourner sous le compte `hermes` : ```bash # Depuis le poste perso ssh storage-01 -sudo hermes-tui # wrapper dans /usr/local/bin/hermes-tui +sudo -i -u hermes # basculer vers le compte hermes +cd /srv/data/hermes +hermes --tui ``` -> Le wrapper gère automatiquement HERMES_HOME, PATH et le changement d'utilisateur vers hermes. +> Lancer depuis un autre compte (ex: ansible) génère des "gateway error" — toujours utiliser le compte hermes. ---