Aller au contenu principal

Runbooks

Version anglaise : en/runbooks.md.

Chaque runbook donne le symptôme (alerte ou signal), le diagnostic, les étapes et la vérification. Les noms d'alertes sont ceux de deploy/observability/prometheus/rules/eai-slo-cost.yaml (copie deploy/observability/k8s/prometheusrule-eai.yaml), du chart (templates/control-plane/monitoring.yaml) et des règles Wazuh deploy/wazuh/rules/eai_audit_rules.xml. Leur runbook_url pointe vers les titres ci-dessous : gardez les noms des titres.

RunbookAlertes et signaux
provider-outageEaiProviderFailing, EaiGatewayErrorRatio, EaiSloFastBurn, EaiControlPlaneHighErrorRate
cost-spikeEaiCostSpike, EaiQuotaRejectionsHigh
key-leakWazuh 100805, scanner de secrets, signalement d'un fournisseur
prompt-injectionWazuh 100804, EaiSecurityEventsSpike
gpu-saturationEaiGpuSaturated, EaiVllmTtftSlo, EaiGpuXidError, EaiGpuMemoryFull
control-plane-downEaiControlPlaneDown, EaiControlPlaneHighLatency, EaiControlPlaneLatencySlo
worker-downEaiWorkerDown, EaiWorkerJobFailing, EaiStaleHeartbeats
media-backlogEaiMediaQueueBacklog
database-unavailable/readyz répond 503 avec database: false
kill-switch-activeEaiKillSwitchActive, Wazuh 100801
Chaîne d'auditEaiAuditChainBroken, EaiAuditChainNotVerified : Alertes
Runtime MCPEaiMcpRuntimeFailures, EaiMcpRuntimeInstancesFailed, EaiMcpCatalogStale, EaiMcpCallErrorRatio : Runtime MCP

provider-outage​

Symptôme : EaiProviderFailing (un fournisseur échoue au-delà de 50 % pendant 5 minutes), EaiGatewayErrorRatio (plus de 10 % des requêtes de la passerelle échouent), EaiSloFastBurn ou EaiControlPlaneHighErrorRate (taux de 5xx au-dessus de 2 %).

Diagnostic

  1. Identifier le fournisseur : label provider de l'alerte, tableau Gateway, métrique litellm_deployment_failure_responses_total.
  2. Distinguer une panne du fournisseur d'un défaut local : si tous les fournisseurs échouent, vérifiez LiteLLM (kubectl -n enterprise-ai logs deploy/enterprise-ai-litellm) et la sortie réseau (hubble observe --namespace enterprise-ai --verdict DROPPED).

Étapes

  1. Les fallbacks LiteLLM basculent automatiquement (router_settings.fallbacks). Vérifiez que le repli reste conforme (classification, région) dans les politiques OPA.
  2. Si la panne dure, désactivez le fournisseur : POST /v1/providers/{pid}/disable (audité provider.disable, Wazuh 100801), ou ajoutez-le à kill_switch.providers des données OPA. Informez les tenants.

Vérification : le taux d'erreur de EaiGatewayErrorRatio repasse sous 10 %. Retour à la normale : POST /v1/providers/{pid}/enable, retirez-le du kill switch, surveillez le taux d'erreur pendant 30 minutes.

cost-spike​

Symptôme : EaiCostSpike (coût horaire de la passerelle trois fois au-dessus de la moyenne sur 7 jours pendant 30 minutes) ou EaiQuotaRejectionsHigh (plus de 30 refus de quota ou de budget par minute).

Diagnostic

  1. Tableau FinOps : tenant, fournisseur, modèle et clé API à l'origine du coût (eai_gateway_cost_total, eai_gateway_tokens_total).
  2. Cherchez une boucle d'agent (réglages max_steps et max_depth de agent_autonomy dans les données OPA) ou une clé compromise (appels depuis une adresse inhabituelle dans GET /v1/audit/events).

Étapes

  1. Baissez model_invocation.max_cost_per_request dans les données OPA, ou le budget du tenant.
  2. Suspendez l'agent : POST /v1/agents/{agent_id}/suspend (/kill pour l'arrêter immédiatement).
  3. Révoquez une clé compromise : DELETE /v1/api-keys/{key_id} ; ou activez le kill switch du tenant.

Vérification : eai:gateway_cost:rate1h revient à son niveau habituel. Rapprochez ensuite avec la facture : POST /v1/finops/reconciliation/run.

key-leak​

Symptôme : règle Wazuh 100805 (identifiant révoqué ou renouvelé), alerte du scanner de secrets, signalement d'un fournisseur.

Diagnostic : identifiez l'identifiant (clé API de tenant, clé de fournisseur, jeton OpenBao, clé Transit) et la première utilisation illégitime dans GET /v1/audit/events?actor=<id>.

Étapes

  1. Révoquez immédiatement : clé API de tenant (DELETE /v1/api-keys/{key_id}, ou POST /v1/api-keys/{key_id}/rotate), clé de fournisseur dans la console du fournisseur.
  2. Remplacez-la dans OpenBao (bao kv put kv/eai/prod/<chemin> ...) ; External Secrets resynchronise le Secret (rafraîchissement d'une heure), ou redémarrez LiteLLM.
  3. Clé Transit suspectée : bao write -f transit/keys/<cle>/rotate, puis rechiffrez les données (rewrap).
  4. Déclarez l'incident (POST /v1/incidents) ; données personnelles concernées : notification RGPD sous 72 heures.

Vérification : l'ancien identifiant est refusé (401) ; GET /v1/audit/verify montre une chaîne valide.

prompt-injection​

Symptôme : règle Wazuh 100804 (actions d'audit security.prompt_injection.blocked ou .detected), EaiSecurityEventsSpike pour le type de l'événement de sécurité.

Diagnostic : retrouvez l'exécution, l'agent et la source (document RAG, outil, utilisateur) avec GET /v1/audit/correlations?trace_id=<trace>.

Étapes

  1. Suspendez l'agent (POST /v1/agents/{agent_id}/suspend).
  2. Mettez le document en quarantaine (retirez son ACL) ou bloquez l'outil dans la politique.
  3. Vérifiez qu'aucune action irréversible n'a été exécutée sans approbation (politique agent_autonomy, demandes d'approbation).
  4. Passez la garde du tenant à block (prompt_injection_mode des réglages du tenant, défaut EAI_PROMPT_INJECTION_DEFAULT_MODE).
  5. Ajoutez le cas aux tests promptfoo et garak de la CI.

Vérification : la même entrée est désormais refusée (security.prompt_injection.blocked dans l'audit).

gpu-saturation​

Symptôme : EaiGpuSaturated (GPU au-delà de 95 % avec plus de 20 requêtes en file pendant 10 minutes), EaiVllmTtftSlo (p95 du temps jusqu'au premier jeton au-delà de 2 secondes), EaiGpuXidError, EaiGpuMemoryFull.

Diagnostic

  1. Tableau GPU : utilisation, mémoire, file vllm:num_requests_waiting par modèle.
  2. KEDA a-t-il atteint maxReplicas du modèle ? kubectl -n enterprise-ai get scaledobject. Sinon, des nœuds GPU sont-ils libres ? (GPU Operator, erreurs XID).

Étapes

  1. Augmentez maxReplicas du modèle dans vllm.models, ou ajoutez des nœuds GPU.
  2. Activez un fallback LiteLLM vers un modèle plus petit ou vers un fournisseur autorisé.
  3. Limitez le débit du tenant dans APISIX.
  4. Erreur XID répétée : isolez le nœud (kubectl cordon <noeud>) et ouvrez un ticket matériel.

Vérification : vllm:num_requests_waiting repasse sous le seuil de vllm.keda.threshold ; l'alerte se résout.

control-plane-down​

Symptôme : EaiControlPlaneDown (aucune cible saine pendant 5 minutes), EaiControlPlaneHighLatency ou EaiControlPlaneLatencySlo (p95 au-delà d'une seconde).

Diagnostic

  1. Kubernetes : kubectl -n enterprise-ai get pods -l app.kubernetes.io/component=control-plane et les journaux d'un pod. Paquets : systemctl status navin-platform-api et journalctl -u navin-platform-api -n 200.
  2. unsafe production settings: dans les journaux : une règle de production n'est pas respectée. password authentication failed ou un délai dépassé : voir database-unavailable.
  3. curl -fsS <url-api>/readyz donne l'état de la base et des migrations.

Étapes

  1. Corrigez le réglage nommé par le journal (Référence de configuration), puis redémarrez (kubectl rollout restart deploy/enterprise-ai-control-plane, ou systemctl restart navin-platform-api).
  2. Latence élevée seulement : vérifiez le HPA (kubectl -n enterprise-ai get hpa) et les limites CPU ; augmentez controlPlane.autoscaling.maxReplicas.

Vérification : /readyz répond 200 ready ; l'alerte se résout.

worker-down​

Symptôme : EaiWorkerDown (aucun tick pendant 5 minutes), EaiWorkerJobFailing (plus de 2 échecs d'une tâche en 30 minutes), EaiStaleHeartbeats (exécutions actives au battement de cœur périmé).

Diagnostic

  1. Un worker tourne-t-il ? kubectl -n enterprise-ai get pods -l app.kubernetes.io/component=control-plane-worker, ou systemctl status navin-platform-worker.
  2. Un worker qui reste activating ou dont l'initialisation échoue : une migration est en attente (python -m eai.migrate --check).
  3. Une tâche en échec : label job_name de eai_worker_job_failures_total, puis les journaux du worker.

Étapes

  1. Migration en attente : appliquez-la (navin-platform-db migrate, ou le Job de migration du chart).
  2. Redémarrez le worker. Un seul réplica est actif (verrou consultatif PostgreSQL EAI_WORKER_LOCK_KEY) : un second attend.
  3. Battements de cœur périmés : dès que le worker tourne à nouveau, sa tâche heartbeats signale les exécutions au-delà du seuil de péremption (EAI_HEARTBEAT_STALE_SECONDS) et les passe en timed_out au-delà de EAI_WORKER_HEARTBEAT_TIMEOUT_SECONDS.

Vérification : eai_worker_last_tick_timestamp_seconds{worker="worker"} est récent ; eai_heartbeat_stale_runs revient à 0.

media-backlog​

Symptôme : EaiMediaQueueBacklog (plus de 100 tâches média en file, ou la plus ancienne âgée de plus de 15 minutes).

Diagnostic : eai_media_queue_depth et eai_media_queue_oldest_age_seconds ; des workers média tournent-ils (kubectl -n enterprise-ai get pods, systemctl status navin-platform-media-worker) et KEDA les a-t-il mis à l'échelle ?

Étapes

  1. Démarrez ou mettez à l'échelle les workers média (maxReplicas de workers.items, lagThreshold).
  2. Tâches bloquées en running : la tâche media_requeue remet en file une tâche dont le bail a expiré (EAI_MEDIA_JOB_LEASE_SECONDS) et la passe en échec après EAI_MEDIA_JOB_MAX_ATTEMPTS prises.

Vérification : la profondeur de la file diminue ; l'alerte se résout.

database-unavailable​

Symptôme : /readyz répond 503 avec "database": false ; les journaux de l'API et du worker montrent des erreurs de connexion.

Diagnostic

  1. Kubernetes : kubectl -n eai-data get cluster eai-postgres (CloudNativePG) montre le primaire et les réplicas. Paquets : systemctl status postgresql et sudo navin-platform-db status.
  2. Erreurs TLS : vérifiez l'autorité de sslrootcert et le sslmode de EAI_DATABASE_URL.

Étapes

  1. CloudNativePG promeut automatiquement un réplica ; attendez le nouveau primaire, le Service eai-postgres-rw le suit.
  2. Disque plein : agrandissez le volume (storage.size du cluster) ou libérez l'archive WAL.
  3. Perte de données : restaurez (PostgreSQL, Haute disponibilité et PRA).

Vérification : /readyz répond 200 avec database: true et migrations: true.

kill-switch-active​

Symptôme : EaiKillSwitchActive (un kill switch de fournisseur, de modèle ou de tenant actif depuis 5 minutes), Wazuh 100801 (provider.disable, model.disable, agent.kill, agent.suspend).

Diagnostic : label kind de eai_kill_switches_active ; GET /v1/soc/kill-switches liste les kill switches et leurs accusés de vérification ; l'événement d'audit indique qui l'a activé.

Étapes

  1. Confirmez que l'activation est voulue (incident en cours, ordre de confinement du SOC).
  2. Levez-le par le même canal une fois la cause corrigée : POST /v1/providers/{pid}/enable, retirez l'entrée de kill_switch dans les données OPA, ou la reprise à quatre yeux du SOC pour un kill switch posé par un ordre de confinement (POST /v1/soc/recoveries, puis POST /v1/soc/recoveries/{recovery_id}/approve par une seconde personne).

Vérification : eai_kill_switches_active revient à 0 pour ce type.