Funk-lab/admin/k8s/n8n.md
Alkatrazz 40fd7f0868 docs: synchroniser la doc avec l'état réel du cluster (revue Ansible + incident Qdrant)
- ops/ansible.md : tableau complet des rôles par playbook (15 storage-01, 6 gpu-01),
  caveat hermes_agent, note lm_studio inutilisé
- ia/hermes-auto-improve.md : NOUVEAU — doc du worker déployé (trigger :9095,
  modes du script, endpoints, PR squash, pièges connus)
- k8s/n8n.md : workflow 3 "Hermes Doc Worker" documenté (22h, /trigger/all,
  boucle de polling), clé API → vault
- incidents.md : Qdrant crash-loop depuis 2026-06-05 (segment funk-docs corrompu,
  invisible dans --state=failed) + procédure de réparation
- ia/rag.md : bandeau RAG HS
- CLAUDE.md : état 2026-06-10, rôle hermes_auto_improve, 3 workflows n8n,
  vault complet (n8n_api_key, Gmail au lieu de Brevo), section auto-improve
- README.md : lien admin/ops/cluster.md corrigé, arborescence complète
  (tools/, admin/, progress/, skills), roadmap à jour
- PROGRESS.md : entrée 2026-05-29 (migration NVMe) qui existait sans être référencée
- ansible : suppression effective des templates daily timer (cleanup b9be63c)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 15:11:53 +02:00

10 KiB

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 — stockée dans le vault Ansible (vault_n8n_api_key)

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)

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 :

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
GPU Power 1h avg_over_time(rocm_gpu_power_watts{instance="gpu-01"}[1h:5m]) → Wh cette heure
GPU Power 24h avg_over_time(rocm_gpu_power_watts{instance="gpu-01"}[24h:5m]) → kWh 24h glissants

Section énergie GPU : affichée dans chaque rapport entre l'analyse Hermes et les métriques brutes. À minuit (exécution 00:00), un encart BILAN JOURNALIER met en avant la consommation totale en kWh des 24h écoulées.


3. Hermes Doc Worker — Funk-lab

ID : CX72UUOempE1YtNL
Déclencheurs : Schedule quotidien 22h00 · webhook manuel POST /webhook/hermes-doc-run · (un ancien Schedule 30min existe mais est désactivé)

Pipeline :

Schedule 22h (ou webhook manuel)
    │
    ▼
Déclencher run (HTTP POST storage-01:9095/trigger/all)
  → lance hermes-auto-improve --all (28 docs, ~60-90 min)
    │
    ▼
┌── Attendre run (5 min) ◄────────────┐
│       │                             │
│       ▼                             │
│   Status run (GET :9095/status)     │
│       │                             │
│       ▼                             │
│   Run terminé ? (IF running=false) ─┘ false → reboucle
│       │ true
└───────▼
Format Run → LLM Run (résumé) → Email Run → Envoyer Run
    │
    ▼
Est 22h ? (IF heure courante = 22)
    │ true
    ▼
Déclencher PR (POST :9095/trigger/daily-pr)
  → crée ou met à jour la PR hermes/daily-work → main (squash-only)
    │
    ▼
Attendre PR (5 min) → Status PR → Format PR → LLM PR → Email PR → Envoyer PR

Backend : trigger server hermes-auto-improve sur storage-01 (:9095), déployé par le rôle Ansible hermes_auto_improve. Voir admin/ia/hermes-auto-improve.md.

Gestion via API : la clé API n8n est dans le vault Ansible (vault_n8n_api_key) :

make vault-view | grep n8n_api_key
curl -s -H "X-N8N-API-KEY: $KEY" http://n8n.lab.local/api/v1/workflows

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 KubePodCrashLoopingkubectl 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

# 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