Alerting : de la métrique au message Slack
Ce guide explique comment une alerte naît d'une métrique, mûrit, et finit par te prévenir dans Slack. Objectif : comprendre chaque maillon pour ne pas subir une alerte qui se déclenche (ou pire, une qui ne se déclenche pas).
ADR lié (le pourquoi des décisions) : Alerting Alertmanager + Slack. Pré-requis utile : Comprendre l'observabilité.
L'idée en une image
L'observabilité, c'est le cockpit (les cadrans, le journal de bord). L'alerting, c'est le détecteur de fumée : tu ne regardes pas les cadrans en permanence, tu veux être réveillé seulement quand quelque chose cloche vraiment.
Tout l'enjeu d'une bonne alerte tient en une phrase :
Se déclencher quand il faut (sinon on rate la panne), et seulement quand il faut (sinon on coupe le détecteur à force de fausses alertes).
La chaîne complète
métrique (Prometheus)
│ une PrometheusRule l'évalue en boucle
▼
condition vraie ──► Pending ──(for: écoulé)──► Firing
│ │
│ ▼
│ Alertmanager
│ (groupe, route, inhibe)
│ │
▼ ▼
résolu ──► Resolved ──────────────────────► Slack
Trois acteurs, trois rôles distincts :
| Acteur | Rôle | Ne fait PAS |
|---|---|---|
Prometheus (via PrometheusRule) |
évalue les conditions, décide Pending/Firing |
n'envoie aucune notification |
| Alertmanager | reçoit les alertes déclenchées (firing), les groupe, route, inhibe | ne décide pas si une alerte se déclenche |
| Slack | affiche le message | rien d'autre |
Erreur classique : croire que « Prometheus envoie l'alerte ». Non. Prometheus déclare qu'une alerte se déclenche ; c'est Alertmanager qui décide quoi en faire et où l'envoyer.
Le cycle de vie d'une alerte
C'est le concept central. Une alerte passe par des états :
| État | Couleur | Signification |
|---|---|---|
Normal (Inactive) |
vert | la condition est fausse, tout va bien |
Pending |
orange | la condition est vraie, mais on attend pour confirmer |
Firing |
rouge | la condition est vraie depuis assez longtemps → on alerte |
Resolved |
— | la condition est redevenue fausse → on prévient que c'est fini |
Le rôle du for: (l'anti-faux-positif)
Le champ for: est le délai de confirmation. Une règle avec for: 5m dit :
« Ne se déclenche que si la condition reste vraie 5 minutes d'affilée. »
Pourquoi ? Parce qu'un pod qui redémarre une fois, un pic de latence d'une
seconde, ce n'est pas une panne, c'est la vie normale d'un système. Le for: filtre
le bruit transitoire. C'est lui qui transforme Pending (orange, « ça pourrait
être un souci ») en Firing (rouge, « c'est un vrai souci »).
condition : faux ──── vrai ──── vrai ──── vrai ──── vrai
état : Normal Pending Pending Firing! Firing
└──────── for: 5m ────────┘
Les 4 alertes FastAPI
Elles reprennent exactement les métriques du dashboard RED (#74) : pas de devinette, on alerte sur ce qu'on mesure déjà.
| Alerte | Question métier | for |
sévérité |
|---|---|---|---|
FastAPITargetDown |
« l'appli répond-elle à Prometheus ? » | 2m | critical |
FastAPIPodCrashLooping |
« un pod redémarre-t-il en boucle ? » | 5m | critical |
FastAPIHighErrorRate |
« trop de 5xx ? » (Errors du RED) | 5m | warning |
FastAPIHighLatency |
« trop lent ? » (p99, Duration du RED) | 5m | warning |
Deux familles : la disponibilité (les 2 premières, critical) et la qualité
de service (les 2 dernières, warning). La sévérité sert ensuite au routage.
Ce que fait Alertmanager (les 3 verbes)
Une fois qu'une alerte est Firing, elle arrive chez Alertmanager qui applique
trois traitements :
1. Grouper (group_wait)
Si 10 pods tombent en même temps, tu ne veux pas 10 messages. Alertmanager
attend un court instant (group_wait, ~30s) et regroupe les alertes
similaires en une notification. C'est aussi pourquoi le message Slack arrive
quelques secondes après le Firing côté Grafana.
2. Router (par sévérité)
Chaque alerte est dirigée selon ses labels. Ici, le routage se fait par
severity vers Slack. On pourrait router les critical vers un canal d'astreinte
et les warning vers un canal d'équipe.
3. Inhiber (étouffer le redondant)
Si une alerte critical se déclenche, inutile de spammer avec les warning du même
namespace : Alertmanager les inhibe (les masque tant que le critical dure).
Les deux alertes qu'on NE veut PAS voir
| Alerte | Pourquoi elle existe | Pourquoi routée null |
|---|---|---|
| Watchdog | se déclenche en permanence par conception (deadman's switch) | si elle s'arrête, c'est que la chaîne d'alerting elle-même est morte. On la surveille ailleurs, pas dans Slack |
| InfoInhibitor | rouage interne du mécanisme d'inhibition des alertes info |
bruit technique, sans intérêt humain |
Le Watchdog est malin : « pas de nouvelles = mauvaises nouvelles ». Une chaîne d'alerting qui ne dit jamais rien peut être cassée sans qu'on le sache. Le Watchdog se déclenche en permanence justement pour prouver que la chaîne est vivante.
⚠️ Le piège qui fait la différence en entretien
FastAPITargetDown s'écrit up == 0. Intuitivement : « si la cible vaut 0, alerte ».
Mais tout dépend de comment la cible disparaît.
up est une métrique que Prometheus crée pour chaque cible qu'il scrape. Et une
cible n'existe que s'il y a un endpoint (un pod avec une IP derrière le Service).
| Situation | Ce qui arrive à la série up |
up == 0 se déclenche ? |
|---|---|---|
Scale à 0 (--replicas=0) |
plus aucun pod → plus aucune cible → la série disparaît | NON |
| Pod présent mais planté (CrashLoop) | la cible existe, le scrape échoue → la série vaut 0 | OUI |
La nuance : quelque chose qui n'existe plus == 0 ne matche rien (il n'y a
aucune série à comparer). Alors que série présente qui vaut 0 matche.
Scale à 0 : up │ 1 1 1 1 ╳ (la ligne s'ARRÊTE) → up == 0 : rien à évaluer
CrashLoop : up │ 1 1 1 1 0 0 0 (la ligne TOMBE à 0) → up == 0 : VRAI
Conséquence : up == 0 détecte très bien « un pod mort qui ne répond pas »,
mais pas la disparition totale (scale-à-0, deployment supprimé). Pour couvrir ce
cas, on ajoute la règle FastAPITargetMissing (#93) bâtie sur absent() :
absent(up{namespace="fastapi", endpoint="http"})
absent() se déclenche précisément quand la série n'existe pas. C'est le complément de
FastAPITargetDown (up == 0) : les deux règles ensemble couvrent les deux faces de la
panne (cible disparue vs cible présente qui ne répond pas).
À retenir : en alerting, « absent » et « égal à zéro » sont deux choses différentes. C'est une des erreurs les plus fréquentes des règles
up == 0.
Où est le secret du webhook Slack ?
L'URL du webhook Slack est un secret : elle ne doit jamais être dans Git. Même chaîne que le reste du projet (ESO + IRSA) :
AWS Secrets Manager (fastapi-eks/alertmanager-slack)
│ ESO + IRSA (least-privilege)
▼
Secret K8s (alertmanager-slack) ──monté dans──► Alertmanager
lu via slack_configs.api_url_file (jamais en clair dans Git)
C'est le même pattern que le mot de passe Grafana (#76). Voir Comprendre l'observabilité et l'ADR External Secrets Operator + IRSA.
Bonus : valider sans tout casser
- Tester le routage sans provoquer de panne :
amtool alert addinjecte une alerte synthétique → on vérifie qu'elle arrive bien dans Slack (firing puis resolved), et que Watchdog/InfoInhibitor n'y arrivent pas. - Valider les règles en local (sans cluster) :
promtool check rulesvérifie la syntaxe desPrometheusRuleavant de merger. - Provoquer une vraie alerte (test de bout en bout) : voir le runbook de validation, section Alerting.