Retour au cours

infra / monitoring-observabilite

Alerting avec Prometheus et Alertmanager

Leçon 71 exercice

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éPrometheusAlertmanager
Évaluer une condition PromQLOuiNon
Regrouper des alertes similairesNonOui
Router vers Slack/PagerDuty/emailNonOui
Dédupliquer des alertes en doublonNonOui

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

yaml
# 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 }}"
yaml
# 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"]
bash
# 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 actives

Ré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_rules supprime le bruit en cascade (pas besoin d'alerter sur la latence d'un service déjà signalé comme down).
  • Toujours valider avec promtool/amtool avant déploiement : une règle malformée peut silencieusement désactiver tout l'alerting.

Exercices pratiques

1 disponible
1

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.

Résoudre l’exercice →