infra / monitoring-observabilite
Alerting avec Prometheus et Alertmanager
Explication
Ce que vous allez apprendre
- Écrire des règles d'alerte PromQL avec la clause
for:pour éviter le bruit - Comprendre la séparation des responsabilités entre Prometheus (détection) et Alertmanager (routage)
- Regrouper et dédupliquer des alertes similaires avec
group_by - Router des alertes différentes vers des canaux différents selon leur sévérité
- Supprimer le bruit en cascade avec les règles d'inhibition
Dans quel contexte ?
Les dashboards Grafana sont maintenant en place, mais personne ne les regarde à 3h du matin un dimanche. Une équipe SRE veut être prévenue automatiquement sur Slack pour les incidents mineurs, et réveillée via PagerDuty pour les incidents critiques — sans recevoir dix notifications séparées pour un seul et même incident.
D'abord, il faut comprendre que deux outils différents interviennent, avec deux rôles distincts
Prometheus lui-même sait détecter qu'une condition est vraie (via une expression PromQL), mais il ne sait pas envoyer un Slack ou réveiller quelqu'un. C'est Alertmanager, un second binaire séparé, qui reçoit les alertes déclenchées par Prometheus et décide où et comment les notifier.
Cette séparation permet à plusieurs instances Prometheus d'envoyer leurs alertes vers un seul et même Alertmanager, centralisant ainsi tout le routage de notifications au même endroit.
| Responsabilité | Prometheus | Alertmanager |
|---|---|---|
| Évaluer une condition PromQL | Oui | Non |
| Regrouper des alertes similaires | Non | Oui |
| Router vers Slack/PagerDuty/email | Non | Oui |
| Dédupliquer des alertes en doublon | Non | Oui |
Une fois cette séparation comprise, il faut écrire la première règle
Une règle d'alerte combine une expression PromQL et une durée minimale, for:. Sans cette durée, un simple pic transitoire de quelques secondes déclencherait une alerte, créant un bruit permanent que plus personne ne prend au sérieux au bout de quelques semaines.
Prérequis
Cette leçon suppose que tu sais déjà écrire des expressions PromQL de base (taux d'erreur, latence P95) — voir les deux leçons dédiées à PromQL.
Il reste un problème une fois plusieurs alertes définies : éviter le spam de notifications
Si dix instances d'un même service dépassent leur seuil d'erreur en même temps, sans regroupement, Alertmanager enverrait dix notifications Slack quasi identiques. group_by résout ça : toutes les alertes partageant les mêmes valeurs pour les labels listés sont fusionnées en une seule notification.
Piège fréquent
Oublier group_wait fait qu'Alertmanager envoie une notification dès la toute première alerte reçue, sans attendre de voir si d'autres alertes du même groupe arrivent dans la foulée. Un group_wait: 30s laisse le temps aux alertes corrélées de se regrouper avant l'envoi.
Maintenant, une subtilité utile en production : le routage conditionnel
Toutes les alertes ne méritent pas la même urgence. La section routes d'Alertmanager permet de rediriger les alertes severity: critical vers PagerDuty (qui peut réveiller quelqu'un via un appel téléphonique), tout en gardant les alertes warning sur un simple canal Slack consulté en journée.
Bonne pratique
Valide systématiquement tes fichiers avec promtool check rules et amtool check-config avant tout déploiement. Une règle d'alerte malformée peut, dans le pire des cas, faire échouer silencieusement le chargement de TOUTES les règles d'un fichier, désactivant ainsi tout l'alerting sans avertissement visible.
Le dernier mécanisme à connaître : l'inhibition
Quand un serveur entier tombe (InstanceDown), il devient inutile — voire contre-productif — de recevoir en plus des alertes de latence ou d'erreur sur ce même serveur : ce ne sont que des symptômes de la même cause. Les inhibit_rules suppriment automatiquement ces alertes secondaires tant que l'alerte source reste active.
Maintenant que l'alerting sur les métriques est en place, il manque encore une pièce du puzzle : que faire quand une alerte dit "quelque chose ne va pas" mais qu'il faut lire le détail exact de l'erreur ? C'est le rôle des logs centralisés, sujet de la prochaine leçon.
Commandes & code
Alerting avec Prometheus et Alertmanager
# rules/alerting_rules.yml — les règles vivent DANS Prometheus, l'envoi/routage vit dans Alertmanager
groups:
- name: api_alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/ sum(rate(http_requests_total[5m])) by (service) > 0.05
for: 5m # doit rester vrai 5 MINUTES avant de déclencher (évite le bruit)
labels:
severity: critical
annotations:
summary: "Taux d'erreur élevé sur {{ $labels.service }}"
description: "{{ $value | humanizePercentage }} d'erreurs 5xx depuis 5 minutes"
- alert: HighLatencyP95
expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) > 1
for: 10m
labels:
severity: warning
annotations:
summary: "Latence P95 > 1s"
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} est injoignable depuis 2 minutes"
- alert: DiskWillFillIn4Hours
expr: predict_linear(node_filesystem_free_bytes[6h], 4 * 3600) < 0
for: 15m
labels:
severity: warning
annotations:
summary: "Disque plein prévu sous 4h sur {{ $labels.instance }}"# alertmanager.yml — routage, regroupement et déduplication des alertes
global:
resolve_timeout: 5m
route:
receiver: "default-slack"
group_by: ["alertname", "service"] # regroupe les alertes similaires en UNE notification
group_wait: 30s # attend 30s de voir arriver d'autres alertes du même groupe
group_interval: 5m # délai avant de renvoyer une notif pour un groupe déjà notifié
repeat_interval: 4h # renvoie un rappel si l'alerte est toujours active après 4h
routes:
- match:
severity: critical
receiver: "pagerduty-oncall"
continue: true # continue d'évaluer les routes suivantes en plus de celle-ci
- match:
severity: warning
receiver: "default-slack"
receivers:
- name: "default-slack"
slack_configs:
- api_url: "https://hooks.slack.com/services/XXX"
channel: "#alerts"
title: "{{ .GroupLabels.alertname }}"
text: "{{ range .Alerts }}{{ .Annotations.summary }}\n{{ end }}"
- name: "pagerduty-oncall"
pagerduty_configs:
- routing_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
inhibit_rules:
# Si InstanceDown est actif, inhibe HighErrorRate/HighLatency du MÊME service (évite le bruit en cascade)
- source_match:
alertname: InstanceDown
target_match_re:
alertname: "HighErrorRate|HighLatencyP95"
equal: ["service"]# Valider les règles et la config avant de déployer
promtool check rules rules/alerting_rules.yml
amtool check-config alertmanager.yml
# Tester une alerte manuellement (silence de test, expire après 1h)
amtool silence add alertname="HighErrorRate" --duration=1h --comment="maintenance planifiée"
amtool alert query # liste les alertes activesRésumé
- Les règles d'alerte (
expr+for) vivent dans Prometheus ; le routage, regroupement et notification vivent dans Alertmanager : deux responsabilités séparées. for:évite les faux positifs sur un pic transitoire ;group_by/group_waitévitent le spam de notifications individuelles.inhibit_rulessupprime le bruit en cascade (pas besoin d'alerter sur la latence d'un service déjà signalé comme down).- Toujours valider avec
promtool/amtoolavant déploiement : une règle malformée peut silencieusement désactiver tout l'alerting.
Exercices pratiques
Mission : trop d'alertes, pas assez de sommeil
Objectif : Écrire une règle d'alerte robuste et configurer Alertmanager pour router, regrouper et inhiber correctement les notifications d'un incident en cascade.
Contexte
Cette nuit, un serveur entier est tombé (InstanceDown). L'équipe a reçu 14 notifications Slack séparées : une pour InstanceDown, et treize autres pour HighErrorRate et HighLatencyP95 sur ce même serveur devenu injoignable. Ta mission : corriger la configuration pour qu'un seul incident ne génère plus qu'une poignée de notifications pertinentes.