mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 13:44:42 +02:00
docs: documenter Open WebUI, n8n et mettre à jour l'état du projet
- CLAUDE.md : état au 2026-05-29 — Open WebUI + n8n ✅, LiteLLM sur 0.0.0.0, postfix Gmail SMTP, suppression ⏳ workloads IA - admin/k8s/open-webui.md : architecture, déploiement, credentials, dépannage, différence avec Hermes TUI - admin/k8s/n8n.md : architecture, 2 workflows documentés (alertes + rapport horaire), 8 idées de workflows futurs, opérations courantes, dépannage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0df9ccf812
commit
12f219c83b
3 changed files with 378 additions and 5 deletions
11
CLAUDE.md
11
CLAUDE.md
|
|
@ -6,17 +6,18 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||
|
||||
**Funk** — homelab IA composé d'un cluster Kubernetes (Talos) pour les services applicatifs, d'un hôte d'inférence LLM dédié (gpu-01 / llama-server ROCm), et d'un agent autonome (Hermes Agent) sur storage-01. Stack IaC complète : Ansible + talhelper + ArgoCD.
|
||||
|
||||
**État actuel (2026-05-25)** :
|
||||
**État actuel (2026-05-29)** :
|
||||
- ✅ Hermes Agent opérationnel — multi-profils (funk-ai/system/monitor/brain)
|
||||
- ✅ RAG opérationnel — Qdrant 284 chunks, `rag-ingest` / `rag-query`, skill funk-ai
|
||||
- ✅ Monitoring complet — Prometheus + Grafana + AlertManager → webhook Hermes
|
||||
- ✅ Monitoring complet — Prometheus + Grafana + AlertManager → webhook Hermes + n8n
|
||||
- ✅ storage-01 installé — `192.168.10.1` (LAN cluster), `192.168.1.200` (WAN)
|
||||
- ✅ gpu-01 installé — llama-server GPU (:1234) + CPU (:1236/:1237) opérationnels
|
||||
- ✅ LiteLLM sur storage-01 — proxy multi-modèles + ask-agent
|
||||
- ✅ LiteLLM sur storage-01 — proxy multi-modèles + ask-agent (écoute `0.0.0.0:4000`)
|
||||
- ✅ Cluster k8s Talos opérationnel (MetalLB + Traefik + wildcard DNS lab.local)
|
||||
- ✅ postfix_relay — SMTP sortant via Brevo (aliyesilkaya93@gmail.com)
|
||||
- ✅ postfix_relay — SMTP sortant via Gmail SMTP + App Password (aliyesilkaya93@gmail.com)
|
||||
- ✅ Open WebUI opérationnel — `openwebui.lab.local`, namespace `ai`, backend LiteLLM
|
||||
- ✅ n8n opérationnel — `n8n.lab.local`, namespace `ai`, 2 workflows actifs
|
||||
- ⏳ WOL compute nodes non configuré (BIOS) — allumage manuel requis
|
||||
- ⏳ ArgoCD bootstrap + workloads IA (Open WebUI, n8n)
|
||||
|
||||
Journal de progression : `PROGRESS.md` → `progress/YYYY-MM-DD.md`
|
||||
|
||||
|
|
|
|||
248
admin/k8s/n8n.md
Normal file
248
admin/k8s/n8n.md
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
# n8n — Automatisation de workflows
|
||||
|
||||
n8n est le moteur d'automatisation du lab. Il orchestre les tâches récurrentes, connecte les services entre eux et envoie des rapports/alertes par email via LiteLLM + Postfix.
|
||||
|
||||
---
|
||||
|
||||
## Accès
|
||||
|
||||
| URL | `http://n8n.lab.local` |
|
||||
|---|---|
|
||||
| Namespace k8s | `ai` |
|
||||
| Port interne | `5678` |
|
||||
| API key | générée dans Settings → n8n API |
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Déclencheurs Pipeline Sortie
|
||||
──────────── ──────── ──────
|
||||
AlertManager webhook → Formatage JSON Email Gmail
|
||||
Cron (toutes les heures) → Requêtes Prometheus → (via Postfix :25)
|
||||
Webhook manuel → LiteLLM hermes-default
|
||||
(résumé/analyse)
|
||||
```
|
||||
|
||||
**SMTP** : n8n envoie via Postfix sur `192.168.10.1:25` (pas d'auth, réseau interne). Postfix relaie vers `smtp.gmail.com:587` avec App Password.
|
||||
|
||||
**LLM** : n8n appelle LiteLLM sur `http://192.168.10.1:4000/v1/chat/completions` avec `model: hermes-default`.
|
||||
|
||||
---
|
||||
|
||||
## Déploiement (ArgoCD)
|
||||
|
||||
Manifests dans `k8s/apps/n8n/` :
|
||||
- `deployment.yaml` — pod n8n
|
||||
- `service.yaml` — ClusterIP :5678
|
||||
- `ingress.yaml` — IngressRoute Traefik
|
||||
- `pvc.yaml` — données applicatives (NFS)
|
||||
- `secret.yaml` — secrets (non commité, à créer manuellement)
|
||||
|
||||
Application ArgoCD : `k8s/apps-of-apps/apps/n8n.yaml`
|
||||
|
||||
### Créer le secret (première installation)
|
||||
|
||||
```bash
|
||||
kubectl create secret generic n8n-secret -n ai \
|
||||
--from-literal=db-password="PASSWORD" \
|
||||
--from-literal=encryption-key="$(openssl rand -hex 32)"
|
||||
```
|
||||
|
||||
Le mot de passe est dans le vault Ansible (`vault_pg_n8n_password`).
|
||||
|
||||
---
|
||||
|
||||
## Credentials configurées
|
||||
|
||||
| Nom | Type | Détail |
|
||||
|---|---|---|
|
||||
| `Postfix local` | SMTP | `192.168.10.1:25`, sans auth, STARTTLS désactivé |
|
||||
|
||||
> Pour créer une credential OpenAI/LiteLLM manuellement :
|
||||
> Settings → Credentials → New → OpenAI → Base URL: `http://192.168.10.1:4000/v1`, API Key: `lm-studio`
|
||||
|
||||
---
|
||||
|
||||
## Workflows actifs
|
||||
|
||||
### 1. Alertes Prometheus → Résumé LLM → Gmail
|
||||
|
||||
**ID** : `4lfZ0sHZqQ5HYEph`
|
||||
**Déclencheur** : Webhook POST sur `http://n8n.lab.local/webhook/alerts`
|
||||
**Configuré dans** : `k8s/infra/monitoring/values.yaml` (receiver AlertManager)
|
||||
|
||||
**Pipeline** :
|
||||
```
|
||||
AlertManager POST
|
||||
│
|
||||
├── Respond to Webhook (répond OK immédiatement)
|
||||
│
|
||||
▼
|
||||
Format Alertes (Code)
|
||||
→ extrait alertname, instance, severity, summary, description
|
||||
│
|
||||
▼
|
||||
Résumé LLM (HTTP Request → LiteLLM)
|
||||
→ system: "assistant ops, résumé concis en français"
|
||||
│
|
||||
▼
|
||||
Envoyer Email (SMTP)
|
||||
→ Subject: [Funk] N alerte(s) — firing/resolved
|
||||
→ Body: résumé LLM
|
||||
```
|
||||
|
||||
**Test manuel** :
|
||||
```bash
|
||||
curl -X POST http://n8n.lab.local/webhook/alerts \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"version":"4","status":"firing","receiver":"n8n-webhook",
|
||||
"alerts":[{
|
||||
"status":"firing",
|
||||
"labels":{"alertname":"HighMemory","instance":"192.168.10.12:9100","severity":"warning"},
|
||||
"annotations":{"summary":"RAM élevée","description":"RAM > 85%"}
|
||||
}]
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Rapport Horaire Système — Funk
|
||||
|
||||
**ID** : `i2KAGxBFDps7IjIP`
|
||||
**Déclencheur** : Cron toutes les heures (`:00`)
|
||||
|
||||
**Pipeline** :
|
||||
```
|
||||
Schedule (toutes les heures)
|
||||
│
|
||||
├── CPU (Prometheus) avg 1h par nœud
|
||||
├── Mémoire (Prometheus) avg_over_time 1h
|
||||
├── Mémoire Max (Prometheus) max_over_time 1h
|
||||
├── Disque (Prometheus) snapshot actuel
|
||||
├── Services (Prometheus) up/down
|
||||
└── Services Changes changements d'état sur 1h
|
||||
│
|
||||
▼
|
||||
Format Rapport (Code)
|
||||
→ tableau métriques par nœud (avg/max mémoire, CPU moyen 1h)
|
||||
→ liste services stables/instables
|
||||
│
|
||||
▼
|
||||
Analyse LLM (HTTP Request → LiteLLM)
|
||||
→ system: "résumé état général, points d'attention, recommandation"
|
||||
│
|
||||
▼
|
||||
Préparer Email (Code)
|
||||
→ assemble : résumé LLM + séparateur + tableau métriques
|
||||
│
|
||||
▼
|
||||
Envoyer Rapport (SMTP)
|
||||
→ Subject: [Funk] Rapport systeme - DD/MM/YYYY HH:MM:SS
|
||||
→ Body HTML (pre tag) : résumé + métriques
|
||||
```
|
||||
|
||||
**Queries Prometheus utilisées** :
|
||||
|
||||
| Nœud | Query |
|
||||
|---|---|
|
||||
| CPU | `100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[1h])) * 100)` |
|
||||
| Mémoire | `avg_over_time((1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)[1h:5m]) * 100` |
|
||||
| Mémoire Max | `max_over_time((1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)[1h:5m]) * 100` |
|
||||
| Disque | `(filesystem_size - filesystem_free) / filesystem_size * 100` (mountpoint=/) |
|
||||
| Services | `up` |
|
||||
| Services Changes | `changes(up[1h]) > 0` |
|
||||
|
||||
---
|
||||
|
||||
## Workflows à ajouter
|
||||
|
||||
### Court terme
|
||||
|
||||
**Alerte disque > 80%**
|
||||
Cron toutes les 30 min → query Prometheus `disk > 80` → si résultat non vide → email d'alerte.
|
||||
Utile car AlertManager ne couvre pas toujours les seuils fins par nœud.
|
||||
|
||||
**Redémarrage automatique pod crashé**
|
||||
Webhook AlertManager sur `KubePodCrashLooping` → `kubectl rollout restart` via HTTP Request vers l'API k8s (ou script SSH sur storage-01) → notification email.
|
||||
|
||||
**Rapport hebdomadaire étendu**
|
||||
Cron dimanche 09h → même pipeline que le rapport horaire mais avec fenêtre 7 jours (`[7d]`) + statistiques min/max de la semaine.
|
||||
|
||||
### Moyen terme
|
||||
|
||||
**Budget Anthropic API**
|
||||
Cron quotidien → requête API Anthropic usage → si > seuil configuré → email d'alerte.
|
||||
Évite les surprises de facturation Claude.
|
||||
|
||||
**Notification nouveaux commits Funk-lab**
|
||||
GitHub webhook → n8n → email/notification résumé du commit.
|
||||
Utile pour tracker les changements sur d'autres postes.
|
||||
|
||||
**Monitor llama-server performance**
|
||||
Cron horaire → query Prometheus `llamacpp_tokens_per_second` → si tokens/s < seuil (GPU dégradé) → alerte email.
|
||||
|
||||
**Rotation/nettoyage logs**
|
||||
Cron quotidien → SSH storage-01 → `journalctl --vacuum-time=30d` → rapport taille libérée.
|
||||
|
||||
### Long terme
|
||||
|
||||
**Auto-scaling modèle Hermes**
|
||||
Monitor charge LiteLLM → si charge élevée, switcher automatiquement vers `claude-sonnet-4-6` via `hermes-switch claude` → revenir à `qwen` après N minutes.
|
||||
|
||||
**RAG re-indexation automatique**
|
||||
Webhook Git (push sur admin/) → déclencher `rag-ingest` via SSH sur storage-01 → email confirmation nombre de chunks indexés.
|
||||
|
||||
**Résumé quotidien Hermes**
|
||||
Cron 08h00 → interroger Hermes sur l'état du lab → recevoir un briefing matinal par email avec état services, alertes de la nuit, métriques clés.
|
||||
|
||||
---
|
||||
|
||||
## Opérations courantes
|
||||
|
||||
```bash
|
||||
# Logs n8n
|
||||
kubectl logs deploy/n8n -n ai -f
|
||||
|
||||
# Redémarrer n8n
|
||||
kubectl rollout restart deploy/n8n -n ai
|
||||
|
||||
# Lister les workflows via API
|
||||
curl -s http://n8n.lab.local/api/v1/workflows \
|
||||
-H "X-N8N-API-KEY: <clé>" | python3 -m json.tool
|
||||
|
||||
# Activer/désactiver un workflow
|
||||
curl -s -X POST http://n8n.lab.local/api/v1/workflows/<id>/activate \
|
||||
-H "X-N8N-API-KEY: <clé>"
|
||||
curl -s -X POST http://n8n.lab.local/api/v1/workflows/<id>/deactivate \
|
||||
-H "X-N8N-API-KEY: <clé>"
|
||||
|
||||
# Dernières exécutions
|
||||
curl -s "http://n8n.lab.local/api/v1/executions?limit=5" \
|
||||
-H "X-N8N-API-KEY: <clé>" | python3 -c \
|
||||
"import sys,json; [print(e['id'], e['status'], e.get('stoppedAt','')) for e in json.load(sys.stdin)['data']]"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dépannage
|
||||
|
||||
| Symptôme | Cause | Action |
|
||||
|---|---|---|
|
||||
| Email vide | Expression `$json.xxx` évaluée à vide dans emailSend | Utiliser un nœud Code intermédiaire qui assemble le corps, puis `emailType: "html"` + `html: "={{ $json.htmlBody }}"` |
|
||||
| SMTP ETIMEDOUT | Port 25 non ouvert pour les pods | Vérifier nftables : `tcp dport 25 ip saddr { 192.168.10.0/24, 10.42.0.0/16 }` |
|
||||
| LLM timeout | hermes-default trop lent (> 2 min) | Passer en mode async : ajouter "Respond to Webhook" en branche parallèle avant le LLM |
|
||||
| Prometheus query vide | Service DNS interne non résolu | Utiliser l'URL service k8s : `http://kube-prometheus-stack-prometheus.monitoring.svc.cluster.local:9090` |
|
||||
| Workflow ne se déclenche pas | Webhook AlertManager mal configuré | Tester : `curl -X POST http://n8n.lab.local/webhook/alerts -d '{...}'` |
|
||||
|
||||
---
|
||||
|
||||
## Configuration Ansible / k8s
|
||||
|
||||
- **Secrets k8s** : `kubectl get secret n8n-secret -n ai`
|
||||
- **Base de données** : PostgreSQL `n8n` sur storage-01 (`vault_pg_n8n_password`)
|
||||
- **PVC data** : NFS, 5 Gi, claimName `n8n-data`
|
||||
- **nftables** : port 25 ouvert `10.42.0.0/16` (pods) dans le rôle `gateway`
|
||||
- **AlertManager** : receiver `hermes-monitor` dans `k8s/infra/monitoring/values.yaml`
|
||||
124
admin/k8s/open-webui.md
Normal file
124
admin/k8s/open-webui.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# Open WebUI — Interface de chat IA
|
||||
|
||||
Open WebUI est l'interface web de chat connectée à LiteLLM. Elle permet d'accéder à tous les modèles du lab depuis un navigateur, avec historique persistant et gestion multi-utilisateurs.
|
||||
|
||||
---
|
||||
|
||||
## Accès
|
||||
|
||||
| URL | `http://openwebui.lab.local` |
|
||||
|---|---|
|
||||
| Namespace k8s | `ai` |
|
||||
| Port interne | `8080` |
|
||||
| Backend LLM | LiteLLM `http://192.168.10.1:4000/v1` |
|
||||
|
||||
**Modèles disponibles** (via LiteLLM) :
|
||||
- `hermes-default` — Qwen3-8B sur gpu-01, profil principal (~35 tok/s)
|
||||
- `qwen3-8b` — alias direct gpu-01
|
||||
- `claude-sonnet-4-6` — Claude API Anthropic (facturé)
|
||||
- `claude-opus-4-7` — Claude API Anthropic (facturé)
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Navigateur
|
||||
│
|
||||
▼
|
||||
Traefik (openwebui.lab.local)
|
||||
│
|
||||
▼
|
||||
Open WebUI pod (namespace ai)
|
||||
│ OPENAI_API_BASE_URL=http://192.168.10.1:4000/v1
|
||||
▼
|
||||
LiteLLM (storage-01 :4000)
|
||||
│
|
||||
├── hermes-default → llama-server gpu-01 :1234
|
||||
└── claude-* → Anthropic API
|
||||
```
|
||||
|
||||
**Base de données** : PostgreSQL sur storage-01 (`openwebui` DB). Les conversations, utilisateurs et paramètres sont persistés.
|
||||
|
||||
---
|
||||
|
||||
## Déploiement (ArgoCD)
|
||||
|
||||
Manifests dans `k8s/apps/open-webui/` :
|
||||
- `deployment.yaml` — pod Open WebUI
|
||||
- `service.yaml` — ClusterIP :8080
|
||||
- `ingress.yaml` — IngressRoute Traefik
|
||||
- `pvc.yaml` — données applicatives (NFS)
|
||||
- `secret.yaml` — secrets (non commité, à créer manuellement)
|
||||
|
||||
Application ArgoCD : `k8s/apps-of-apps/apps/open-webui.yaml`
|
||||
|
||||
### Créer le secret (première installation)
|
||||
|
||||
```bash
|
||||
kubectl create secret generic open-webui-secret -n ai \
|
||||
--from-literal=litellm-api-key="lm-studio" \
|
||||
--from-literal=database-url="postgresql://openwebui:PASSWORD@192.168.10.1:5432/openwebui" \
|
||||
--from-literal=webui-secret-key="$(openssl rand -hex 32)"
|
||||
```
|
||||
|
||||
Le mot de passe PostgreSQL est dans le vault Ansible (`vault_pg_openwebui_password`).
|
||||
|
||||
---
|
||||
|
||||
## Premier démarrage
|
||||
|
||||
1. Naviguer sur `http://openwebui.lab.local`
|
||||
2. Créer un compte administrateur (premier compte = admin automatiquement)
|
||||
3. Sélectionner un modèle dans le dropdown en haut
|
||||
4. Commencer à discuter
|
||||
|
||||
**Note** : au premier démarrage, Open WebUI télécharge des modèles sentence-transformer (~500 MB) pour le RAG local. Le pod peut sembler lent pendant 2-3 minutes — c'est normal.
|
||||
|
||||
---
|
||||
|
||||
## Différence avec Hermes TUI
|
||||
|
||||
| | Open WebUI | Hermes TUI |
|
||||
|---|---|---|
|
||||
| Accès | Navigateur (réseau local) | SSH + `hermes chat` |
|
||||
| Contexte Funk | ✗ LLM générique | ✅ Skills RAG, monitoring, agent |
|
||||
| Historique | ✅ Persistant (PostgreSQL) | ✗ Session uniquement |
|
||||
| Multi-utilisateurs | ✅ | ✗ |
|
||||
| Upload fichiers | ✅ | ✗ |
|
||||
| Usage | Chat général, documents | Admin lab, debug infra |
|
||||
|
||||
---
|
||||
|
||||
## Variables d'environnement clés
|
||||
|
||||
| Variable | Valeur | Rôle |
|
||||
|---|---|---|
|
||||
| `OPENAI_API_BASE_URL` | `http://192.168.10.1:4000/v1` | Backend LiteLLM |
|
||||
| `OPENAI_API_KEY` | `lm-studio` | Clé LiteLLM master key |
|
||||
| `DATABASE_URL` | `postgresql://...` | Persistance PostgreSQL |
|
||||
| `ENABLE_OLLAMA_API` | `false` | Désactiver Ollama |
|
||||
| `WEBUI_NAME` | `Funk AI` | Nom affiché |
|
||||
|
||||
---
|
||||
|
||||
## Dépannage
|
||||
|
||||
| Symptôme | Cause | Action |
|
||||
|---|---|---|
|
||||
| "Aucun modèle disponible" | LiteLLM inaccessible | Vérifier `curl http://192.168.10.1:4000/v1/models -H 'Authorization: Bearer lm-studio'` depuis un pod |
|
||||
| Pod OOMKilled | RAM insuffisante au 1er boot | Attendre le rechargement ou augmenter la limit mémoire |
|
||||
| Connexion refusée | Pod pas encore prêt | `kubectl get pods -n ai` — attendre readiness probe |
|
||||
| Erreur DB migrations | PostgreSQL inaccessible | `kubectl logs deploy/open-webui -n ai` |
|
||||
|
||||
```bash
|
||||
# Logs
|
||||
kubectl logs deploy/open-webui -n ai -f
|
||||
|
||||
# Redémarrer
|
||||
kubectl rollout restart deploy/open-webui -n ai
|
||||
|
||||
# Vérifier connectivité LiteLLM depuis le pod
|
||||
kubectl exec -n ai deploy/open-webui -- curl -s http://192.168.10.1:4000/v1/models \
|
||||
-H 'Authorization: Bearer lm-studio'
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue