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.
| Runbook | Alertes et signaux |
|---|---|
| provider-outage | EaiProviderFailing, EaiGatewayErrorRatio, EaiSloFastBurn, EaiControlPlaneHighErrorRate |
| cost-spike | EaiCostSpike, EaiQuotaRejectionsHigh |
| key-leak | Wazuh 100805, scanner de secrets, signalement d'un fournisseur |
| prompt-injection | Wazuh 100804, EaiSecurityEventsSpike |
| gpu-saturation | EaiGpuSaturated, EaiVllmTtftSlo, EaiGpuXidError, EaiGpuMemoryFull |
| control-plane-down | EaiControlPlaneDown, EaiControlPlaneHighLatency, EaiControlPlaneLatencySlo |
| worker-down | EaiWorkerDown, EaiWorkerJobFailing, EaiStaleHeartbeats |
| media-backlog | EaiMediaQueueBacklog |
| database-unavailable | /readyz répond 503 avec database: false |
| kill-switch-active | EaiKillSwitchActive, Wazuh 100801 |
| Chaîne d'audit | EaiAuditChainBroken, EaiAuditChainNotVerified : Alertes |
| Runtime MCP | EaiMcpRuntimeFailures, 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
- Identifier le fournisseur : label
providerde l'alerte, tableau Gateway, métriquelitellm_deployment_failure_responses_total. - 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
- Les fallbacks LiteLLM basculent automatiquement (
router_settings.fallbacks). Vérifiez que le repli reste conforme (classification, région) dans les politiques OPA. - Si la panne dure, désactivez le fournisseur :
POST /v1/providers/{pid}/disable(auditéprovider.disable, Wazuh 100801), ou ajoutez-le àkill_switch.providersdes 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
- Tableau FinOps : tenant, fournisseur, modèle et clé API à l'origine du coût (
eai_gateway_cost_total,eai_gateway_tokens_total). - Cherchez une boucle d'agent (réglages
max_stepsetmax_depthdeagent_autonomydans les données OPA) ou une clé compromise (appels depuis une adresse inhabituelle dansGET /v1/audit/events).
Étapes
- Baissez
model_invocation.max_cost_per_requestdans les données OPA, ou le budget du tenant. - Suspendez l'agent :
POST /v1/agents/{agent_id}/suspend(/killpour l'arrêter immédiatement). - 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
- Révoquez immédiatement : clé API de tenant (
DELETE /v1/api-keys/{key_id}, ouPOST /v1/api-keys/{key_id}/rotate), clé de fournisseur dans la console du fournisseur. - 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. - Clé Transit suspectée :
bao write -f transit/keys/<cle>/rotate, puis rechiffrez les données (rewrap). - 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
- Suspendez l'agent (
POST /v1/agents/{agent_id}/suspend). - Mettez le document en quarantaine (retirez son ACL) ou bloquez l'outil dans la politique.
- Vérifiez qu'aucune action irréversible n'a été exécutée sans approbation (politique
agent_autonomy, demandes d'approbation). - Passez la garde du tenant à
block(prompt_injection_modedes réglages du tenant, défautEAI_PROMPT_INJECTION_DEFAULT_MODE). - 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
- Tableau GPU : utilisation, mémoire, file
vllm:num_requests_waitingpar modèle. - KEDA a-t-il atteint
maxReplicasdu modèle ?kubectl -n enterprise-ai get scaledobject. Sinon, des nœuds GPU sont-ils libres ? (GPU Operator, erreurs XID).
Étapes
- Augmentez
maxReplicasdu modèle dansvllm.models, ou ajoutez des nœuds GPU. - Activez un fallback LiteLLM vers un modèle plus petit ou vers un fournisseur autorisé.
- Limitez le débit du tenant dans APISIX.
- 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
- Kubernetes :
kubectl -n enterprise-ai get pods -l app.kubernetes.io/component=control-planeet les journaux d'un pod. Paquets :systemctl status navin-platform-apietjournalctl -u navin-platform-api -n 200. unsafe production settings:dans les journaux : une règle de production n'est pas respectée.password authentication failedou un délai dépassé : voir database-unavailable.curl -fsS <url-api>/readyzdonne l'état de la base et des migrations.
Étapes
- Corrigez le réglage nommé par le journal (Référence de configuration), puis
redémarrez (
kubectl rollout restart deploy/enterprise-ai-control-plane, ousystemctl restart navin-platform-api). - Latence élevée seulement : vérifiez le HPA (
kubectl -n enterprise-ai get hpa) et les limites CPU ; augmentezcontrolPlane.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
- Un worker tourne-t-il ?
kubectl -n enterprise-ai get pods -l app.kubernetes.io/component=control-plane-worker, ousystemctl status navin-platform-worker. - Un worker qui reste
activatingou dont l'initialisation échoue : une migration est en attente (python -m eai.migrate --check). - Une tâche en échec : label
job_namedeeai_worker_job_failures_total, puis les journaux du worker.
Étapes
- Migration en attente : appliquez-la (
navin-platform-db migrate, ou le Job de migration du chart). - Redémarrez le worker. Un seul réplica est actif (verrou consultatif PostgreSQL
EAI_WORKER_LOCK_KEY) : un second attend. - Battements de cœur périmés : dès que le worker tourne à nouveau, sa tâche
heartbeatssignale les exécutions au-delà du seuil de péremption (EAI_HEARTBEAT_STALE_SECONDS) et les passe entimed_outau-delà deEAI_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
- Démarrez ou mettez à l'échelle les workers média (
maxReplicasdeworkers.items,lagThreshold). - Tâches bloquées en
running: la tâchemedia_requeueremet en file une tâche dont le bail a expiré (EAI_MEDIA_JOB_LEASE_SECONDS) et la passe en échec aprèsEAI_MEDIA_JOB_MAX_ATTEMPTSprises.
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
- Kubernetes :
kubectl -n eai-data get cluster eai-postgres(CloudNativePG) montre le primaire et les réplicas. Paquets :systemctl status postgresqletsudo navin-platform-db status. - Erreurs TLS : vérifiez l'autorité de
sslrootcertet lesslmodedeEAI_DATABASE_URL.
Étapes
- CloudNativePG promeut automatiquement un réplica ; attendez le nouveau primaire, le Service
eai-postgres-rwle suit. - Disque plein : agrandissez le volume (
storage.sizedu cluster) ou libérez l'archive WAL. - 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
- Confirmez que l'activation est voulue (incident en cours, ordre de confinement du SOC).
- Levez-le par le même canal une fois la cause corrigée :
POST /v1/providers/{pid}/enable, retirez l'entrée dekill_switchdans 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, puisPOST /v1/soc/recoveries/{recovery_id}/approvepar une seconde personne).
Vérification : eai_kill_switches_active revient à 0 pour ce type.