docs(ansible): README par rôle (19) + gaps IaC découverts à l'audit

Audit complet des rôles vs état réel du cluster. Chaque rôle a maintenant
un README.md : but, variables (défauts + surcharges host_vars/vault),
handlers, vérifications, caveats.

Gaps découverts et documentés :
- minio : rôle VIDE (tasks/main.yml sans aucune tâche), service inactif —
  placeholder à implémenter ou retirer (ports 9000/9001 ouverts pour rien)
- llama_server : ne gère que l'instance GPU :1234 — les services CPU
  llama-server-system :1236 et llama-server-monitor :1237 sont créés à la
  main sur gpu-01, non reproductibles par make apply-gpu (+ un
  llama-server-dev.service non documenté présent sur l'hôte)
- hermes_auto_improve : defaults port/repo/branch/log non consommés
  (valeurs en dur dans les scripts), défaut branch obsolète
- lm_studio : README de dépréciation, candidat suppression

Tables admin/ops/ansible.md, README.md et CLAUDE.md corrigées en conséquence.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Alkatrazz 2026-06-10 15:21:24 +02:00
parent 40fd7f0868
commit 0aa4c3650d
22 changed files with 538 additions and 6 deletions

View file

@ -85,13 +85,15 @@ Les tags correspondent aux noms de rôles. Tous les rôles sont idempotents.
### Rôles — storage-01
`hermes_user`, `common`, `gateway` (nftables + NAT), `dnsmasq`, `nfs_server`, `qdrant`, `postgresql`, `minio`, `litellm`, `hermes_agent`, `rag`, `node_exporter`, `alertmanager_webhook`, `postfix_relay`, `hermes_auto_improve` (worker doc Hermes + trigger server :9095)
`hermes_user`, `common`, `gateway` (nftables + NAT), `dnsmasq`, `nfs_server`, `qdrant`, `postgresql`, `minio` (⚠️ rôle vide, service non déployé), `litellm`, `hermes_agent`, `rag`, `node_exporter`, `alertmanager_webhook`, `postfix_relay`, `hermes_auto_improve` (worker doc Hermes + trigger server :9095)
### Rôles — gpu-01
`hermes_user`, `common`, `rocm`, `nfs_client`, `llama_server`, `node_exporter`
> `lm_studio` est présent dans `ansible/roles/` mais n'est plus utilisé dans aucun playbook.
> Chaque rôle a un `README.md` (variables, caveats, gaps IaC).
> `lm_studio` est présent dans `ansible/roles/` mais n'est plus utilisé dans aucun playbook (déprécié, voir son README).
> ⚠️ Gap IaC : les instances llama-server CPU `:1236`/`:1237` sur gpu-01 sont des services **manuels**, non gérés par le rôle `llama_server` (voir `ansible/roles/llama_server/README.md`).
### Caveat premier déploiement — hermes_agent

View file

@ -132,7 +132,7 @@ L'ensemble est géré en Infrastructure-as-Code : **Ansible** pour les hôtes Al
│ ├── alertmanager_webhook # Pont AlertManager → ask-agent
│ ├── postfix_relay # SMTP sortant via Gmail
│ ├── node_exporter # Métriques Prometheus
│ ├── minio # Stockage objet S3
│ ├── minio # ⚠️ placeholder vide — service non déployé
│ ├── postgresql # Base de données
│ ├── qdrant # Base vectorielle
│ └── hermes_auto_improve # Worker analyse doc + trigger server :9095

View file

@ -7,7 +7,8 @@ Le venv est dans `.venv/`, le `Makefile` fournit les raccourcis.
## Playbooks et rôles
Deux playbooks, un par machine (le `site.yml` les enchaîne) :
Deux playbooks, un par machine (le `site.yml` les enchaîne).
Chaque rôle a un `README.md` détaillé dans `ansible/roles/<nom>/` (variables, caveats, gaps).
### `playbooks/storage-01.yml` — hosts `gateway` (15 rôles)
@ -20,7 +21,7 @@ Deux playbooks, un par machine (le `site.yml` les enchaîne) :
| `nfs_server` | `nfs_server` | Exports NFS (modèles LLM, volumes k8s) |
| `qdrant` | `qdrant` | Base vectorielle (RAG) — `:6333` |
| `postgresql` | `postgresql` | PG 16 — bases hermes, litellm, n8n, openwebui, grafana |
| `minio` | `minio` | Stockage objet S3 |
| `minio` | `minio` | ⚠️ **Rôle vide** (placeholder) — service inactif, à implémenter ou retirer |
| `litellm` | `litellm` | Proxy LLM `:4000` + script `ask-agent` |
| `hermes_agent` | `hermes_agent` | Agent Hermes + skills + souls |
| `rag` | `rag` | Scripts `rag-ingest` / `rag-query` + docs RAG |
@ -37,7 +38,7 @@ Deux playbooks, un par machine (le `site.yml` les enchaîne) :
| `common` | `common` | Paquets de base, sécurité, NTP |
| `rocm` | `rocm` | Stack GPU AMD (ROCm 7.x, `HSA_OVERRIDE_GFX_VERSION=10.3.0`) |
| `nfs_client` | `nfs_client` | Montage `/mnt/models` depuis storage-01 |
| `llama_server` | `llama_server` | llama-server ×3 : GPU `:1234`, CPU `:1236`/`:1237` |
| `llama_server` | `llama_server` | llama-server **GPU `:1234` uniquement** — ⚠️ les instances CPU `:1236`/`:1237` (system/monitor) sont des services créés à la main sur gpu-01, hors IaC |
| `node_exporter` | `node_exporter` | Métriques Prometheus (+ rocm power) |
> ⚠️ Le rôle `lm_studio` existe encore dans `ansible/roles/` mais n'est référencé par **aucun** playbook (remplacé par `llama_server` en mai 2026). Candidat à la suppression.

View file

@ -0,0 +1,32 @@
# alertmanager_webhook
Pont AlertManager → Hermes : reçoit les alertes Prometheus en webhook et les délègue au profil `monitor` via ask-agent/LiteLLM.
## Ce que fait le rôle
- Déploie `webhook.py` dans `/opt/alertmanager-webhook` (serveur HTTP `:9093`, user `hermes`)
- Service systemd `alertmanager-webhook`
- Ouvre le port 9093 dans nftables (cluster + pods — AlertManager tourne dans k8s)
## Variables principales
| Variable | Défaut |
|---|---|
| `webhook_port` | 9093 |
| `webhook_user` | `hermes` |
| `litellm_url` | `http://127.0.0.1:4000/v1` |
## Configuration côté AlertManager
Le receiver est défini dans `k8s/infra/monitoring/values.yaml` → URL `http://192.168.10.1:9093/`. (n8n a aussi son propre receiver pour les emails — les deux coexistent.)
## Test manuel
```bash
curl -X POST http://192.168.10.1:9093/ -H 'Content-Type: application/json' \
-d '{"alerts":[{"status":"firing","labels":{"alertname":"Test","severity":"warning"},"annotations":{"summary":"test"}}]}'
```
## Caveat
Le traitement est asynchrone (thread) pour répondre vite à AlertManager — incident passé : BrokenPipeError quand la réponse LLM dépassait le timeout AlertManager (voir progress 2026-05-14).

View file

@ -0,0 +1,27 @@
# common
Socle de base pour tous les hôtes AlmaLinux (storage-01, gpu-01).
## Ce que fait le rôle
- Hostname + timezone (`Europe/Paris`) + EPEL + upgrade complet des paquets
- Paquets de base : vim, curl, jq, git, htop, chrony, bind-utils…
- NTP via chrony
- User `ansible` (groupe + sudo passwordless + clé SSH autorisée)
- Ajoute `admin_user` au groupe `systemd-journal` (lecture des logs sans sudo)
- Durcissement sshd
## Variables principales
| Variable | Défaut | Rôle |
|---|---|---|
| `timezone` | `Europe/Paris` | Timezone système |
| `base_packages` | liste (14 paquets) | Paquets installés partout |
| `ansible_service_user` | `ansible` | User de connexion Ansible |
`admin_user` vient de `group_vars/all/vars.yml`.
## Handlers
- `Restart sshd`
- `Reboot if kernel updated`**attention** : un upgrade kernel déclenche un reboot

View file

@ -0,0 +1,28 @@
# dnsmasq
DNS + DHCP du LAN cluster sur storage-01. Résout `*.lab.local` et fournit les baux DHCP statiques des nœuds Talos (boot PXE-like par MAC).
## Ce que fait le rôle
- Installe dnsmasq + config `/etc/dnsmasq.conf`
- Override systemd : attend l'interface USB ethernet avant de démarrer
- DHCP statique par adresse MAC pour compute-01/02/03
- Wildcard `*.lab.local``traefik_ip` (192.168.10.200)
## Variables principales
| Variable | Défaut | Rôle |
|---|---|---|
| `dns_upstream` | 1.1.1.1, 9.9.9.9 | Résolveurs amont |
| `dhcp_range_start/end` | 192.168.10.50-99 | Plage DHCP dynamique |
| `dhcp_static_hosts` | compute-01/02/03 (par MAC) | Baux statiques Talos |
| `traefik_ip` | 192.168.10.200 | Cible du wildcard `*.lab.local` |
| `dns_cluster_hosts` | les 5 machines | Entrées DNS fixes |
## Handlers
- `Restart dnsmasq`, `Reload systemd`
## Caveat
Si on change le MAC d'un nœud Talos (remplacement carte mère/NIC), mettre à jour `dhcp_static_hosts` **avant** de rebooter le nœud, sinon il prend une IP dynamique et sort du cluster.

View file

@ -0,0 +1,35 @@
# gateway
Fait de storage-01 le routeur/firewall du LAN cluster : nftables + NAT + IP forwarding.
Remplace firewalld (stoppé et désactivé).
## Ce que fait le rôle
- Désactive firewalld, installe nftables
- Active `net.ipv4.ip_forward`
- Déploie `/etc/nftables.conf` depuis `templates/nftables.conf.j2` (policy **drop** en input/forward)
## Ports ouverts (template nftables.conf.j2)
| Port | Source | Service |
|---|---|---|
| 22 | LAN maison + cluster | SSH |
| 53 udp/tcp, 67 udp | LAN cluster | dnsmasq (DNS + DHCP) |
| 111, 2049 | LAN cluster | NFS |
| 5432, 6333/6334, 9000/9001 | LAN cluster | PostgreSQL, Qdrant, MinIO |
| 9100, 9093 | cluster + pods 10.42/16 | node_exporter, alertmanager-webhook |
| 8080 | maison + cluster + pods | Hermes gateway |
| 9119 | `hermes_dashboard_allowed_ip` uniquement | Dashboard Hermes |
| 4000 | maison + cluster + pods | LiteLLM |
| 25 | cluster + pods | Postfix relay |
| 9095 | cluster + pods | hermes-auto-improve trigger |
NAT : masquerade du LAN cluster vers le WAN.
## Variables
Pas de defaults — utilise `lan_interface`, `wan_interface` (host_vars) et `hermes_dashboard_allowed_ip` (defaults du rôle hermes_agent).
## Caveat
**Tout nouveau service réseau doit ajouter son port ici** (modifier le template puis `--tags gateway`). C'est la cause de plusieurs incidents passés (voir `admin/incidents.md` 2026-05-13, port monitoring bloqué).

View file

@ -0,0 +1,37 @@
# hermes_agent
Installe et configure l'agent Hermes sur storage-01 : binaire, profils, skills, dashboard, gateway HTTP.
## Ce que fait le rôle
- Dépendances + installation du binaire via le script officiel (`curl | bash`) — **seulement si absent**
- `HERMES_HOME=/srv/data/hermes` (données NVMe), code dans `/opt/hermes`
- `.env` : `LM_BASE_URL` → LiteLLM `:4000`, `LM_API_KEY=lm-studio`
- `config.yaml` (profils), services systemd `hermes-agent` (gateway `:8080`) et `hermes-dashboard` (`:9119`)
- Wrapper global `/usr/local/bin/hermes`
- Ouvre le port gateway dans nftables
## Variables principales
| Variable | Défaut |
|---|---|
| `hermes_home` | `/opt/hermes` (code) |
| `hermes_data_dir` | `/srv/data/hermes` (profils/données) |
| `hermes_lm_base_url` | `http://127.0.0.1:4000/v1` |
| `hermes_model` | `hermes-default` |
| `hermes_gateway_port` | 8080 |
| `hermes_dashboard_port` / `hermes_dashboard_allowed_ip` | 9119 / 192.168.1.10 |
## ⚠️ Caveat premier déploiement — deux runs
L'installation du binaire et sa configuration sont dans le même rôle, mais la config est conditionnelle à `hermes_binary.stat.exists` **évalué avant l'installation**. Sur un hôte vierge :
```bash
ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags hermes_agent # run 1 : installe
ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags hermes_agent # run 2 : configure
```
## Pièges connus (voir aussi memory feedback_hermes_litellm)
- `LM_API_KEY=lm-studio` obligatoire dans `.env` — sans elle, Hermes boucle en erreurs d'auth
- Lancer `hermes -z` depuis `/srv/data/hermes` (HERMES_HOME), pas depuis `/opt/hermes`

View file

@ -0,0 +1,28 @@
# hermes_auto_improve
Worker d'analyse quotidienne de la doc par Hermes : trigger server HTTP (`:9095`) + script d'analyse. Le scheduling est fait par **n8n** (workflow « Hermes Doc Worker », 22h) — pas de timer systemd.
## Ce que fait le rôle
- Installe `gh` CLI (repo officiel)
- Déploie les deux scripts depuis `tools/hermes-auto-improve/` :
- `/usr/local/bin/hermes-auto-improve` (← `auto-improve.py`)
- `/usr/local/bin/hermes-auto-improve-server` (← `trigger-server.py`)
- Service systemd `hermes-auto-improve` (le serveur HTTP, `HOME=/root` pour les credentials gh)
- Crée `/var/lib/hermes-auto-improve` (state)
## Variables
| Variable | Défaut | Note |
|---|---|---|
| `hermes_auto_improve_state_dir` | `/var/lib/hermes-auto-improve` | seule variable réellement consommée |
| `hermes_auto_improve_port` / `repo` / `branch` / `log` | … | ⚠️ **non utilisées** — les valeurs sont codées en dur dans les scripts Python (port 9095, `/srv/data/lab/Funk-lab`, branche `hermes/daily-work`) ; le défaut `branch: feature/hermes-auto-improve` est obsolète |
## Dépendances hors-rôle
- Credentials `gh` de root sur storage-01 (auth GitHub faite à la main — non gérée par Ansible)
- Clone `/srv/data/lab/Funk-lab` (créé à la main)
- Port 9095 ouvert par le rôle `gateway`
- Hermes + LiteLLM + llama-server up (les analyses passent par le profil funk-ai)
Doc d'exploitation : `admin/ia/hermes-auto-improve.md`

View file

@ -0,0 +1,29 @@
# hermes_user
Crée le user `hermes` (uid/gid 1002) sur **les deux hôtes** avec SSH partagé : la clé générée sur storage-01 est autorisée sur gpu-01, ce qui permet à l'agent de lancer des commandes read-only sur le nœud GPU.
## Ce que fait le rôle
- User/groupe `hermes` (1002:1002, home `/opt/hermes`)
- Sudo **limité** (listes blanches différentes storage-01 / gpu-01)
- Génération clé ed25519 sur storage-01 → poussée dans `authorized_keys` de gpu-01
- `~/.ssh/config` + known_hosts pré-remplis (gpu-01)
- Copie du kubeconfig dans `~hermes/.kube/` si présent (accès kubectl read-only)
- Ajout au groupe `systemd-journal`
## Variables principales
| Variable | Défaut |
|---|---|
| `hermes_user` / `hermes_group` | `hermes` |
| `hermes_uid` / `hermes_gid` | 1002 |
| `hermes_home` | `/opt/hermes` |
| `hermes_ssh_key_type` | ed25519 |
## Ordre d'exécution
Doit passer **avant** `hermes_agent` (qui suppose le user existant). C'est le premier rôle des deux playbooks.
## Caveat
Le rôle touche les deux machines mais avec des branches conditionnelles (`inventory_hostname`) — un run sur storage-01 seul ne pousse pas la clé sur gpu-01 : lancer les **deux** playbooks après régénération de clé.

View file

@ -0,0 +1,26 @@
# litellm
Proxy LLM multi-modèles sur storage-01 (`:4000`) — point d'entrée unique pour Hermes, n8n, Open WebUI et ask-agent. Route vers llama-server (gpu-01) ou l'API Anthropic.
## Ce que fait le rôle
- venv `/opt/litellm/venv` avec `litellm[proxy]`, user système `litellm`
- Config `/etc/litellm/config.yaml` : alias `hermes-default`, `qwen3-8b`, `system`, `monitor`, `claude…`
- Service systemd + scripts utilitaires :
- `/usr/local/bin/ask-agent` — délégation inter-agents (texte → profil system/monitor/brain)
- `/usr/local/bin/hermes-switch` — bascule l'alias `hermes-default` entre qwen (local) et claude (API), puis restart litellm
- `/usr/local/bin/funk-cluster` — orchestration start/stop/status du homelab
## Variables principales
| Variable | Défaut |
|---|---|
| `litellm_host` / `litellm_port` | `0.0.0.0` / 4000 |
| `litellm_master_key` | `lm-studio` (clé API attendue par les clients) |
| `litellm_local_llm_base_url` | `http://192.168.10.20:1234/v1` |
| `litellm_anthropic_api_key` | `{{ vault_anthropic_api_key }}` |
## Caveat
- L'alias `hermes-default` est **ce que Hermes consomme** — changer le modèle derrière l'alias ne nécessite pas de reconfigurer Hermes
- `hermes-switch` modifie `/etc/litellm/config.yaml` **en dehors d'Ansible** : un `--tags litellm` réécrit la config et peut écraser un switch manuel vers claude

View file

@ -0,0 +1,38 @@
# llama_server
Compile llama.cpp (backend HIP/ROCm) et déploie le service **llama-server GPU** (`:1234`) sur gpu-01. Sert aussi les embeddings du RAG.
## Ce que fait le rôle
- Clone + build llama.cpp (cmake HIP, `gfx1030`) — build seulement si le binaire est absent
- Service systemd `llama-server` : modèle GGUF depuis `/mnt/models` (NFS), `:1234`
- Embeddings activés (`--embeddings`, pooling mean)
- Ouvre le port dans le firewall, désactive l'ancien service lm-studio
## Variables principales
| Variable | Défaut | Surcharge gpu-01 |
|---|---|---|
| `llama_server_port` | 1234 | — |
| `llama_model_path` | `""` | `/mnt/models/bartowski/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf` |
| `llama_model_alias` | `""` | `qwen3-8b` |
| `llama_ctx_size` | 32768 | 32768 |
| `llama_n_gpu_layers` | 99 | — |
| `hsa_override_gfx_version` | `10.3.0` | — |
## ⚠️ Gap IaC — instances CPU hors Ansible
Le rôle ne gère que l'instance **GPU** (`llama-server.service`). Les services suivants existent sur gpu-01 mais ont été créés **à la main** (non reproductibles par `make apply-gpu`) :
| Service | Port | Modèle | Usage |
|---|---|---|---|
| `llama-server-system.service` | 1236 | Qwen3-1.7B CPU | profil `system` |
| `llama-server-monitor.service` | 1237 | Qwen3-1.7B CPU | profil `monitor` |
| `llama-server-dev.service` | — | (non documenté, présent dans /etc/systemd/system) | ? |
**À faire** : templatiser ces instances dans le rôle (liste d'instances avec port/modèle/threads) pour qu'une réinstallation de gpu-01 restaure les 3 serveurs.
## Caveats
- Rebuild forcé : supprimer le binaire (`/opt/llama.cpp/build/bin/llama-server`) puis relancer le rôle
- Le modèle vient du NFS — voir caveat du rôle `nfs_client`

View file

@ -0,0 +1,14 @@
# lm_studio — ❌ DÉPRÉCIÉ (mai 2026)
Rôle d'installation de LM Studio headless sur gpu-01. **Remplacé par le rôle `llama_server`** (llama.cpp compilé avec ROCm) — n'est plus référencé par aucun playbook.
Le rôle `llama_server` désactive d'ailleurs explicitement le service `lm-studio` lors de son déploiement.
## Pourquoi conservé (temporairement)
- `TROUBLESHOOTING.md` documente le fix GLIBCXX (patchelf) qui pourrait resservir
- Historique de la première approche d'inférence (progress 2026-05-10)
## À faire
Candidat à la **suppression** : l'essentiel du troubleshooting est déjà dans l'historique git et `progress/2026-05-10.md`.

View file

@ -0,0 +1,16 @@
# minio — ⚠️ rôle vide (placeholder)
Ce rôle est référencé par `playbooks/storage-01.yml` mais son `tasks/main.yml` est **vide** : il ne déploie rien.
## État réel
- Aucune tâche, aucun template, aucun default
- Le service `minio` est **inactif** sur storage-01
- Seuls vestiges : `minio_data_dir: /srv/data/minio` dans host_vars, ports 9000/9001 ouverts dans le template nftables du rôle `gateway`
## Décision à prendre
- **Soit** implémenter le rôle (binaire MinIO, user, service, console `:9001`) si un besoin S3 apparaît (backups, artefacts)
- **Soit** retirer le rôle du playbook + fermer les ports 9000/9001 dans nftables
En l'état, il est inoffensif mais donne une fausse impression de service déployé dans la doc.

View file

@ -0,0 +1,20 @@
# nfs_client
Montages NFS sur gpu-01 depuis storage-01 — en particulier `/mnt/models` (modèles GGUF) consommé par llama-server.
## Ce que fait le rôle
- Installe nfs-utils, crée les points de montage
- Écrit les entrées fstab avec **automount systemd** (`x-systemd.automount`) — pas de montage bloquant au boot si storage-01 est éteint
- Active les unités `.automount`
## Variables principales
| Variable | Défaut | Surcharge gpu-01 |
|---|---|---|
| `nfs_server_ip` | 192.168.10.1 | — |
| `nfs_client_mounts` | `/mnt/nfs``/srv/data/nfs/k8s` | + `/mnt/models``/srv/data/models` |
## Caveat
llama-server dépend de `/mnt/models` : si storage-01 redémarre, l'automount se rétablit seul mais un llama-server déjà lancé avec un modèle en RAM continue de tourner. En revanche un **restart** de llama-server pendant que le NFS est indisponible échoue.

View file

@ -0,0 +1,25 @@
# nfs_server
Exports NFS de storage-01 : volumes k8s (`/srv/data/nfs/k8s`) et modèles LLM (`/srv/data/models`, montés par gpu-01).
## Ce que fait le rôle
- Installe nfs-utils + mdadm
- Capture l'état du RAID **sans le monter** (mdadm.conf de référence)
- Sanity check : `/srv/data` doit être un répertoire (bind-mount NVMe)
- Crée les répertoires d'export, déploie `/etc/exports`, démarre nfs-server
## Variables principales
| Variable | Où | Valeur |
|---|---|---|
| `nfs_exports` | host_vars/storage-01 | `/srv/data/nfs/k8s` + `/srv/data/models` (rw, no_root_squash, LAN cluster) |
| `raid_uuid`, `raid_mount` | host_vars/storage-01 | **Référence seulement** — RAID retiré de l'usage actif |
## ⚠️ Contexte RAID → NVMe (2026-05-29)
`/srv/data` est un **bind-mount NVMe** (`/home/data`), plus le RAID5. Les variables `raid_*` sont conservées pour référence (mdadm.conf, incidents) mais **ne doivent pas servir à monter un filesystem**. Voir `admin/incidents.md` (2026-05-27 et 2026-05-29).
## Handlers
- Reload des exports (`exportfs -ra`)

View file

@ -0,0 +1,26 @@
# node_exporter
Métriques Prometheus sur les hôtes hors-cluster (storage-01, gpu-01) — scrapées par kube-prometheus-stack. Sur gpu-01, ajoute un scraper ROCm (consommation GPU).
## Ce que fait le rôle
- Binaire node_exporter (version pinnée) + user dédié + service systemd (`:9100`)
- Textfile collector (`/var/lib/node_exporter/textfile_collector`)
- Ouvre le port 9100 dans nftables (cluster + pods)
- **Si `rocm_exporter_enabled`** (gpu-01) : script + timer systemd qui dump `rocm-smi` (puissance GPU en watts) dans le textfile collector toutes les 30 s → métrique `rocm_gpu_power_watts` (utilisée par le rapport horaire n8n pour le bilan énergie)
## Variables principales
| Variable | Défaut | gpu-01 |
|---|---|---|
| `node_exporter_version` | `1.9.1` | — |
| `node_exporter_port` | 9100 | — |
| `rocm_exporter_enabled` | `false` | `true` |
| `rocm_scrape_interval` | 30 | — |
## Vérifications
```bash
curl -s http://192.168.10.1:9100/metrics | head
curl -s http://192.168.10.20:9100/metrics | grep rocm_gpu_power
```

View file

@ -0,0 +1,31 @@
# postfix_relay
SMTP sortant du homelab : Postfix sur storage-01 relaie vers Gmail (`smtp.gmail.com:587`, App Password). Utilisé par n8n (rapports/alertes) et tout service du LAN/pods.
## Ce que fait le rôle
- Installe postfix + cyrus-sasl
- `main.cf` : relayhost Gmail, TLS, SASL, réécriture de l'expéditeur (generic map)
- `sasl_passwd` (depuis le vault) + postmap
- Ouvre le port 25 depuis le LAN cluster et les pods k8s
## Variables principales
| Variable | Défaut / source |
|---|---|
| `postfix_relay_host` / `port` | `smtp.gmail.com` / 587 |
| `postfix_relay_user` | group_vars (adresse Gmail) |
| `postfix_relay_password` | `vault_postfix_relay_password` (App Password Gmail) |
| `postfix_sender_email` | group_vars — tous les mails sortants sont réécrits vers cette adresse |
| `postfix_mynetworks` | 127/8, LAN cluster, pods 10.42/16, services 10.43/16 |
## Historique
Relay initialement via **Brevo**, basculé vers **Gmail SMTP + App Password** (2026-06). La doc `admin/infra/email.md` couvre la création de l'App Password.
## Test
```bash
echo "test" | mail -s "[Funk] test relay" aliyesilkaya93@gmail.com
sudo postqueue -p # file d'attente si échec
```

View file

@ -0,0 +1,26 @@
# postgresql
PostgreSQL 16 sur storage-01 — persistance de Hermes, LiteLLM, n8n, Open WebUI (et Grafana).
## Ce que fait le rôle
- Repo PGDG + désactivation du module AppStream
- PGDATA déplacé vers `/srv/data/postgres` (override systemd)
- Init du cluster si absent, `pg_hba.conf`, listen_addresses, port, shared_buffers
- Crée bases + users + privilèges (dont `GRANT ON SCHEMA public` requis en PG 15+)
## Variables principales
| Variable | Défaut |
|---|---|
| `postgresql_version` | 16 |
| `postgresql_data_dir` | `/srv/data/postgres` |
| `postgresql_listen_addresses` | `localhost, 192.168.10.1` (pods k8s via LAN) |
| `postgresql_databases` / `postgresql_users` | hermes, litellm, openwebui, n8n |
Mots de passe dans le vault : `vault_pg_hermes_password`, `vault_pg_litellm_password`, `vault_pg_openwebui_password`, `vault_pg_n8n_password`.
## Caveat
- Les tasks de Grant utilisent `no_log` — en cas d'échec, relancer avec `-vvv` après avoir temporairement retiré `no_log`
- Les pods k8s (n8n, openwebui, grafana) se connectent via `192.168.10.1:5432` — port ouvert dans nftables (rôle gateway)

View file

@ -0,0 +1,29 @@
# qdrant
Base vectorielle Qdrant sur storage-01 — mémoire sémantique du RAG (collection `funk-docs`).
## Ce que fait le rôle
- User système `qdrant`, données dans `/srv/data/qdrant` (NVMe)
- Télécharge le binaire (version pinnée), upgrade seulement si la version installée diffère
- Config `/opt/qdrant/config.yaml` + service systemd
## Variables principales
| Variable | Défaut |
|---|---|
| `qdrant_version` | `1.13.4` |
| `qdrant_http_port` / `qdrant_grpc_port` | 6333 / 6334 |
| `qdrant_host` | `0.0.0.0` (filtré par nftables — LAN cluster seulement) |
| `qdrant_data_dir` | `/srv/data/qdrant` |
## Vérifications
```bash
curl -s http://127.0.0.1:6333/collections
systemctl status qdrant
```
## Caveat — crash-loop silencieux
Si un segment de collection est corrompu, Qdrant panique au boot et reste en `activating (auto-restart)`**invisible dans `systemctl --state=failed`**. Symptôme : port 6333 fermé, `rag-query` en connection refused. Réparation : supprimer la collection corrompue et ré-ingérer (voir `admin/incidents.md` 2026-06-05).

View file

@ -0,0 +1,35 @@
# rag
Déploie la chaîne RAG sur storage-01 : scripts d'ingestion/requête + copie des docs + skill Hermes.
## Ce que fait le rôle
- Crée `/srv/data/rag/docs`
- Déploie `/usr/local/bin/rag-ingest` et `/usr/local/bin/rag-query`
- **Synchronise `admin/` du repo vers `/srv/data/rag/docs/`** (copie indexée)
- Déploie le skill `rag-docs` dans les skills globaux Hermes + le profil funk-ai
## Variables principales
| Variable | Défaut |
|---|---|
| `rag_docs_dir` | `/srv/data/rag/docs` |
| `qdrant_url` | `http://127.0.0.1:6333` |
| `embed_url` | `http://192.168.10.20:1234/v1/embeddings` (llama-server GPU) |
| `embed_model` | `qwen3-8b` |
| `rag_collection` | `funk-docs` |
## Workflow après modification de `admin/`
```bash
ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags rag # re-sync les docs
ssh storage-01 /usr/local/bin/rag-ingest # ré-indexe dans Qdrant
```
(`hermes-auto-improve` fait aussi un rsync + rag-ingest en fin de run.)
## Caveats
- **Dépendances fortes** : Qdrant up (`:6333`) et llama-server GPU up (`:1234`) — sinon connection refused
- `rag-ingest` parcourt **tout** `/srv/data/rag/docs` y compris `hermes/builtin/` (rapports du bot) — pollution potentielle des résultats, exclusion à prévoir
- Les embeddings viennent du modèle de génération (Qwen3-8B) — un modèle d'embedding dédié (nomic-embed, bge-m3) est dans la roadmap

View file

@ -0,0 +1,27 @@
# rocm
Stack GPU AMD sur gpu-01 (AlmaLinux, RX 6700XT) : repos AMD, runtime ROCm, paquets de build pour llama.cpp.
## Ce que fait le rôle
- Clé GPG AMD + repos `amdgpu` et `rocm` (latest)
- kernel headers/devel (requis pour amdgpu-dkms)
- Runtime : rocminfo, rocm-hip-runtime, rocm-opencl-runtime, rocblas, hipblaslt
- Paquets build (pour le rôle `llama_server`) : hipblas-devel, rocblas-devel, hip-devel, hipcc, cmake, gcc-c++, patchelf
- `HSA_OVERRIDE_GFX_VERSION=10.3.0` **system-wide** (`/etc/environment`) et dans `profile.d`
- Ajoute le user ansible aux groupes `video` et `render`
## Variables principales
| Variable | Défaut |
|---|---|
| `rocm_rhel_version` | `9.4` |
| `hsa_override_gfx_version` | `10.3.0` |
## ⚠️ Contrainte critique
La RX 6700XT (**gfx1031**) n'est pas supportée officiellement par ROCm. Sans `HSA_OVERRIDE_GFX_VERSION=10.3.0` (la faire passer pour une gfx1030), **tout calcul GPU échoue**. La variable doit être présente dans l'environnement de chaque service GPU (le template systemd de llama_server la définit aussi).
## Caveat
Les repos pointent vers `latest` — un `make apply-gpu` peut tirer une nouvelle version majeure de ROCm. Après upgrade kernel ou ROCm, vérifier `rocm-smi` et un completion de test avant de considérer le nœud sain (voir `admin/ia/rocm.md`).