# 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` | | 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. --- ## 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: " | python3 -m json.tool # Activer/désactiver un workflow curl -s -X POST http://n8n.lab.local/api/v1/workflows//activate \ -H "X-N8N-API-KEY: " curl -s -X POST http://n8n.lab.local/api/v1/workflows//deactivate \ -H "X-N8N-API-KEY: " # Dernières exécutions curl -s "http://n8n.lab.local/api/v1/executions?limit=5" \ -H "X-N8N-API-KEY: " | 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` --- ## État vérifié — 2026-06-05 - **Services n8n** : 1 pod actif (`n8n-76c99cdfc5-s8xlr`) sur 7 replicaset déclenchés (tous à 0/0). - **Ingress** : Aucun objet ingress trouvé dans le namespace `ai` (contrôle des expositions HTTP). - **Divergences** : Les replicaset n8n-* ne scalent pas (desired=0), contrairement à la configuration attendue. - **Élément opérationnel** : Le pod actif montre une instance isolée, sans réplication ou équilibrage de charge.