Aller au contenu
medium

04 — Alerting : Alertmanager et notifications

32 min de lecture

Vous avez maintenant des métriques dans Prometheus et des dashboards dans Grafana. Mais personne ne regarde les dashboards 24/7. Vous avez besoin d’être notifié automatiquement quand quelque chose ne va pas.

C’est le rôle de l’alerting. Dans ce module, vous allez apprendre à créer des règles d’alerte pertinentes et à configurer Alertmanager pour envoyer les notifications aux bonnes personnes.

À la fin de ce module, vous saurez :

  1. Expliquer l’architecture de l’alerting Prometheus (qui fait quoi)
  2. Créer des règles d’alerte dans Prometheus
  3. Configurer Alertmanager pour router et notifier
  4. Envoyer des alertes vers Slack, email, ou webhook
  5. Gérer les silences (maintenance) et les inhibitions
  6. Appliquer les bonnes pratiques d’alerting
  1. Prometheus fonctionne

    Fenêtre de terminal
    kubectl get pods -n observability | grep -E 'prometheus-server|kube-state-metrics|node-exporter'

    Les pods doivent être en Running.

  2. L’application OpenTelemetry Demo génère du trafic

    Fenêtre de terminal
    kubectl get pods -n otel-demo | head -10

    Plusieurs pods en Running.

  3. Vous êtes dans le répertoire du lab

    Fenêtre de terminal
    cd ~/lab-observability

L’alerting Prometheus implique deux composants distincts :

Architecture Alerting

Pourquoi deux composants ?

Prometheus (les règles)Alertmanager (les notifications)
“Quelque chose ne va pas""Qui prévenir et comment”
Évalue des conditions PromQLGère les destinataires
Détecte que la latence > 500msEnvoie un message Slack à l’équipe backend
Ne sait pas qui contacterNe sait pas ce qui ne va pas

Cette séparation permet :

  • De changer les destinataires sans modifier les règles
  • D’avoir un seul Alertmanager pour plusieurs Prometheus
  • De gérer les silences et regroupements indépendamment

Comprendre le cycle de vie vous évitera beaucoup de confusion :

Cycle de vie des alertes

ÉtatSignificationLes notifications partent ?
InactiveLa condition est fausse❌ Non
PendingLa condition est vraie, mais pas depuis assez longtemps (for pas atteint)❌ Non
FiringLa condition est vraie depuis la durée for✅ Oui
ResolvedLa condition redevient fausse après avoir été firing✅ Oui (optionnel)

Exemple concret :

alert: HighLatency
expr: http_latency > 500
for: 5m # ← L'alerte doit être vraie pendant 5 min avant de "firing"
  • T+0min : latence passe à 600ms → Pending
  • T+3min : latence toujours à 600ms → Toujours Pending (pas encore 5 min)
  • T+5min : latence toujours à 600ms → Firing (notification envoyée)
  • T+6min : latence redescend à 200ms → Resolved (notification “resolved”)

Le chart prometheus-community/prometheus inclut Alertmanager. Vérifions qu’il est activé et configurons-le pour notre lab.

  1. Examinez la configuration

    Fenêtre de terminal
    cat 04-alerting/helm-values/alertmanager.yaml

    Ce que vous voyez :

    alertmanager:
    enabled: true
    persistentVolume:
    enabled: true
    size: 2Gi
    config:
    global:
    resolve_timeout: 5m
    route:
    receiver: 'default'
    group_by: ['alertname', 'severity']
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 4h
    receivers:
    - name: 'default'
    webhook_configs:
    - url: 'https://webhook.site/VOTRE-UUID'
    send_resolved: true

    Cette configuration :

    • Active Alertmanager
    • Configure un receiver webhook pour les tests
    • Groupe les alertes par nom et sévérité
  2. Appliquez la configuration

    Fenêtre de terminal
    helm upgrade prometheus prometheus-community/prometheus \
    -n observability \
    -f 02-prometheus/helm-values/prometheus-minimal.yaml \
    -f 04-alerting/helm-values/alertmanager.yaml \
    --wait

    Ce que vous devez voir :

    Release "prometheus" has been upgraded.
  3. Vérifiez qu’Alertmanager tourne

    Fenêtre de terminal
    kubectl get pods -n observability | grep alertmanager

    Ce que vous devez voir :

    prometheus-alertmanager-0 1/1 Running 0 1m
  4. Accédez à l’interface Alertmanager

    Fenêtre de terminal
    kubectl port-forward svc/prometheus-alertmanager 9093:9093 -n observability

    Ouvrez http://localhost:9093

    Ce que vous voyez : L’interface Alertmanager avec (probablement) aucune alerte pour l’instant.

Avant de créer des règles, comprenons leur structure :

groups:
- name: nom_du_groupe # Groupe logique de règles
interval: 30s # Fréquence d'évaluation (optionnel)
rules:
- alert: NomAlerte # ① Nom unique de l'alerte
expr: up == 0 # ② Expression PromQL (condition)
for: 2m # ③ Durée avant firing
labels: # ④ Labels ajoutés à l'alerte
severity: critical
team: platform
annotations: # ⑤ Informations humaines
summary: "Target {{ $labels.instance }} is down"
description: "The target {{ $labels.job }}/{{ $labels.instance }} has been down for more than 2 minutes."
runbook: "https://wiki.example.com/runbooks/target-down"

Décortiquons chaque partie :

PartieRôleBonnes pratiques
alertIdentifie l’alerteUtiliser PascalCase, être descriptif : HighLatencyCheckout
exprCondition PromQLDoit retourner des séries (pas une valeur scalaire)
forDélai anti-faux-positif1-5 min pour les warnings, jusqu’à 10 min pour les critiques lents
labelsMétadonnées pour le routingseverity, team, service
annotationsTexte pour les humainssummary (court), description (détaillé), runbook (lien)

Les templates dans les annotations :

Vous pouvez utiliser des variables dans les annotations :

VariableDescriptionExemple
{{ $labels.xyz }}Valeur du label xyz{{ $labels.instance }}10.0.1.5:9090
{{ $value }}Valeur de l’expression{{ $value | printf “%.2f” }}0.85
{{ .Labels }}Tous les labels
{{ .Annotations }}Toutes les annotations

Nous allons créer un fichier de règles et l’ajouter à Prometheus.

Créez le fichier 04-alerting/rules/infrastructure.yaml :

groups:
- name: infrastructure
rules:
# ============================================
# Alerte 1 : Un target ne répond plus
# ============================================
- alert: TargetDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Target {{ $labels.job }}/{{ $labels.instance }} is down"
description: |
The target {{ $labels.instance }} in job {{ $labels.job }}
has been down for more than 2 minutes.
Possible causes:
- The application has crashed
- Network issue between Prometheus and target
- The /metrics endpoint is not responding
runbook: "https://wiki.example.com/runbooks/target-down"
# ============================================
# Alerte 2 : Mémoire haute
# ============================================
- alert: HighMemoryUsage
expr: |
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "Memory usage above 85% on {{ $labels.instance }}"
description: |
The node {{ $labels.instance }} is using more than 85% of its memory.
Current usage: {{ $value | printf "%.1f" }}%
Check for memory leaks or consider scaling.
value: "{{ $value | printf \"%.1f\" }}%"
# ============================================
# Alerte 3 : CPU haute
# ============================================
- alert: HighCPUUsage
expr: |
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 10m
labels:
severity: warning
annotations:
summary: "CPU usage above 80% on {{ $labels.instance }}"
description: |
The node {{ $labels.instance }} has been using more than 80% CPU
for the last 10 minutes.
value: "{{ $value | printf \"%.1f\" }}%"
# ============================================
# Alerte 4 : Disque bientôt plein
# ============================================
- alert: DiskSpaceLow
expr: |
(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes) < 0.10
for: 5m
labels:
severity: critical
annotations:
summary: "Disk space below 10% on {{ $labels.instance }}:{{ $labels.mountpoint }}"
description: |
The filesystem {{ $labels.mountpoint }} on {{ $labels.instance }}
has less than 10% free space.
Consider cleaning up or expanding the disk.
<Aside type="note" title="Filtre fstype">
Le filtre `fstype!~"tmpfs|overlay"` exclut les filesystems virtuels. Sur Minikube ou Docker Desktop, vous pourriez avoir d'autres types de FS. Ajustez selon votre environnement.
</Aside>

Avant de créer des règles sur l’application OTel Demo, découvrons les métriques disponibles.

Créez le fichier 04-alerting/rules/application.yaml :

groups:
- name: otel-demo-application
rules:
# ============================================
# Alerte : Collector OTel down
# ============================================
- alert: OtelCollectorDown
expr: up{job="otel-collector"} == 0
for: 2m
labels:
severity: critical
team: platform
annotations:
summary: "OpenTelemetry Collector is down"
description: |
The OpenTelemetry Collector is not responding.
All application metrics may be missing.
Check: kubectl get pods -n otel-demo -l app.kubernetes.io/name=opentelemetry-collector
# ============================================
# Alerte : Latence P99 trop haute
# ============================================
- alert: HighLatency
expr: |
histogram_quantile(0.99,
sum by (service_name, le) (
rate(otel_http_server_duration_seconds_bucket[5m])
)
) > 0.5
for: 5m
labels:
severity: warning
team: backend
annotations:
summary: "P99 latency above 500ms for {{ $labels.service_name }}"
description: |
The service {{ $labels.service_name }} has a P99 latency above 500ms.
This means 1% of users experience latency > 500ms.
Current P99: {{ $value | printf "%.3f" }}s
value: "{{ $value | printf \"%.3f\" }}s"
# ============================================
# Alerte : Taux d'erreur trop haut (calcul en %)
# ============================================
- alert: HighErrorRate
expr: |
(
sum by (service_name) (
rate(otel_http_server_duration_seconds_count{http_status_code=~"5.."}[5m])
)
/
sum by (service_name) (
rate(otel_http_server_duration_seconds_count[5m])
)
) * 100 > 1
for: 5m
labels:
severity: critical
team: backend
annotations:
summary: "Error rate above 1% for {{ $labels.service_name }}"
description: |
The service {{ $labels.service_name }} returns more than 1% of 5xx errors.
This directly impacts users.
Current error rate: {{ $value | printf "%.2f" }}%
value: "{{ $value | printf \"%.2f\" }}%"
# ============================================
# Alerte : Plus aucune requête (service cassé ?)
# ============================================
- alert: NoTraffic
expr: |
sum by (service_name) (
rate(otel_http_server_duration_seconds_count[5m])
) == 0
for: 10m
labels:
severity: warning
team: platform
annotations:
summary: "No HTTP traffic for {{ $labels.service_name }}"
description: |
The service {{ $labels.service_name }} has not received any HTTP request
in the last 10 minutes. Either the service is broken or traffic
is being routed elsewhere.

La méthode la plus fiable pour un lab Helm est d’inclure les règles directement dans les values.

  1. Ajoutez les règles dans les values Helm

    Éditez 02-prometheus/helm-values/prometheus-minimal.yaml et ajoutez la section serverFiles :

    serverFiles:
    alerting_rules.yml:
    groups:
    - name: infrastructure
    rules:
    - alert: TargetDown
    expr: up == 0
    for: 2m
    labels:
    severity: critical
    annotations:
    summary: "Target {{ $labels.job }}/{{ $labels.instance }} is down"
    - alert: HighMemoryUsage
    expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
    for: 5m
    labels:
    severity: warning
    annotations:
    summary: "Memory usage above 85% on {{ $labels.instance }}"
    - name: otel-demo-application
    rules:
    - alert: OtelCollectorDown
    expr: up{job="otel-collector"} == 0
    for: 2m
    labels:
    severity: critical
    annotations:
    summary: "OpenTelemetry Collector is down"
  2. Appliquez avec Helm upgrade

    Fenêtre de terminal
    helm upgrade prometheus prometheus-community/prometheus \
    -n observability \
    -f 02-prometheus/helm-values/prometheus-minimal.yaml \
    -f 04-alerting/helm-values/alertmanager.yaml \
    --wait

    Helm déclenche un rollout du pod Prometheus qui charge automatiquement les nouvelles règles.

  3. Vérifiez que les règles sont chargées

    Ouvrez l’interface Prometheus (http://localhost:9090) et allez dans Status → Rules.

    Ce que vous devez voir : Vos groupes infrastructure et otel-demo-application avec leurs règles.

Cette page montre toutes les règles chargées :

  • État de chaque règle : inactive, pending, firing
  • Dernière évaluation : quand la règle a été vérifiée
  • Durée d’évaluation : combien de temps le calcul a pris

Cliquez sur Alerts dans le menu.

Cette page montre les alertes non inactives (pending ou firing) :

Ce que vous pourriez voir :

AlerteÉtatSignification
HighMemoryUsagePending (2m30s)La mémoire est haute depuis 2m30s, mais le seuil for: 5m n’est pas atteint
TargetDownFiringUn target est down depuis plus de 2 minutes

Alertmanager reçoit les alertes de Prometheus. Maintenant, configurons-le pour envoyer des notifications utiles.

Le routing détermine quel receiver reçoit quelle alerte.

route:
receiver: 'default' # Receiver par défaut
group_by: ['alertname'] # Grouper les alertes de même nom
group_wait: 30s # Attendre 30s avant d'envoyer (grouper les alertes)
group_interval: 5m # Intervalle minimum entre groupes
repeat_interval: 4h # Répéter si toujours firing après 4h
routes: # Sous-routes (ordre important !)
- match:
severity: critical
receiver: 'critical-alerts' # Les critiques vont ici
continue: false # Ne pas continuer aux autres routes
- match:
team: backend
receiver: 'backend-team' # Les alertes de l'équipe backend vont ici

Comment le routing fonctionne :

  1. Une alerte arrive avec ses labels
  2. Alertmanager parcourt les routes dans l’ordre
  3. Première correspondance (match) trouvée → utilise ce receiver
  4. Si continue: true, continue à chercher d’autres correspondances
  5. Si aucune correspondance, utilise le receiver par défaut

Voici comment envoyer les alertes vers Slack :

  1. Créez un webhook Slack

    • Allez sur https://api.slack.com/apps
    • Créez une nouvelle app ou utilisez une existante
    • Activez “Incoming Webhooks”
    • Créez un webhook pour votre channel (ex: #alerts)
    • Copiez l’URL webhook
  2. Mettez à jour la configuration Alertmanager

    Éditez 04-alerting/helm-values/alertmanager.yaml :

    alertmanager:
    enabled: true
    config:
    global:
    resolve_timeout: 5m
    # Si vous utilisez Slack via webhook
    slack_api_url: 'https://hooks.slack.com/services/XXX/YYY/ZZZ'
    route:
    receiver: 'slack-default'
    group_by: ['alertname', 'severity']
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 4h
    routes:
    # Les alertes critiques vont dans un channel dédié
    - match:
    severity: critical
    receiver: 'slack-critical'
    receivers:
    - name: 'slack-default'
    slack_configs:
    - channel: '#alerts'
    send_resolved: true
    title: '{{ if eq .Status "firing" }}🔥{{ else }}✅{{ end }} {{ .CommonAnnotations.summary }}'
    text: |
    {{ range .Alerts }}
    *Alert:* {{ .Annotations.summary }}
    *Description:* {{ .Annotations.description }}
    *Severity:* {{ .Labels.severity }}
    {{ end }}
    - name: 'slack-critical'
    slack_configs:
    - channel: '#alerts-critical'
    send_resolved: true
    title: '🚨 CRITICAL: {{ .CommonAnnotations.summary }}'
    text: |
    {{ range .Alerts }}
    *Alert:* {{ .Annotations.summary }}
    *Description:* {{ .Annotations.description }}
    {{ end }}
  3. Appliquez

    Fenêtre de terminal
    helm upgrade prometheus prometheus-community/prometheus \
    -n observability \
    -f 02-prometheus/helm-values/prometheus-minimal.yaml \
    -f 04-alerting/helm-values/alertmanager.yaml \
    --wait

Parfait pour tester. Utilisez webhook.site pour voir les requêtes en temps réel :

receivers:
- name: 'webhook-test'
webhook_configs:
- url: 'https://webhook.site/VOTRE-UUID-UNIQUE'
send_resolved: true
  1. Allez sur https://webhook.site
  2. Copiez l’URL unique générée
  3. Les alertes apparaîtront sur cette page en temps réel

Pendant une maintenance planifiée, vous ne voulez pas recevoir des centaines d’alertes pour des choses que vous savez déjà en cours.

Les silences suppriment temporairement les notifications.

  1. Ouvrez Alertmanager (http://localhost:9093)

  2. Cliquez sur SilencesNew Silence

  3. Configurez le silence :

    ChampValeurExplication
    StartMaintenantQuand le silence commence
    EndDans 2 heuresQuand le silence se termine
    Matchersalertname=HighMemoryUsageQuelles alertes silencer
    CreatorVotre nomQui a créé le silence
    Comment”Maintenance RAM node-1”Pourquoi
  4. Cliquez sur Create

Ce qui se passe : Les alertes HighMemoryUsage ne génèrent plus de notifications, mais sont toujours visibles dans Prometheus et Alertmanager (avec la mention “Silenced”).

Utile pour les scripts de maintenance automatisés :

Fenêtre de terminal
# Créer un silence d'une heure pour toutes les alertes du service checkout
curl -X POST http://localhost:9093/api/v2/silences \
-H "Content-Type: application/json" \
-d '{
"matchers": [
{"name": "service_name", "value": "checkout", "isRegex": false}
],
"startsAt": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
"endsAt": "'$(date -u -d '+1 hour' +%Y-%m-%dT%H:%M:%SZ)'",
"createdBy": "maintenance-script",
"comment": "Déploiement checkout v2.3.1"
}'
✅ Faire❌ Éviter
Documenter la raison du silenceSilencer sans commentaire
Mettre une durée limitéeSilencer indéfiniment
Silencer au plus précisSilencer tout severity=warning
Vérifier après la maintenanceOublier de supprimer le silence

Les inhibitions — supprimer le bruit automatiquement

Section intitulée « Les inhibitions — supprimer le bruit automatiquement »

Scénario : Un node entier tombe en panne. Vous recevez :

  • 1 alerte “NodeDown”
  • 10 alertes “PodDown” (pour chaque pod sur ce node)
  • 15 alertes “ServiceUnavailable”

C’est du bruit. Si le node est down, évidemment les pods aussi.

Les inhibitions suppriment automatiquement les alertes redondantes.

inhibit_rules:
# Si un node est down, ne pas alerter sur ses pods
- source_match:
alertname: 'NodeDown'
target_match:
alertname: 'PodDown'
equal: ['node'] # L'inhibition s'applique si le label 'node' correspond
# Si un service est down, ne pas alerter sur la latence de ce service
- source_match:
alertname: 'ServiceDown'
target_match:
alertname: 'HighLatency'
equal: ['service_name']

Comment ça marche :

  1. source_match : l’alerte “parente” qui déclenche l’inhibition
  2. target_match : les alertes qui seront supprimées
  3. equal : les labels qui doivent correspondre entre source et target

Testons tout le pipeline de bout en bout.

  1. Créez une alerte de test qui se déclenche immédiatement

    Ajoutez cette règle temporaire :

    - alert: TestAlert
    expr: vector(1) == 1 # Toujours vrai
    for: 1m
    labels:
    severity: warning
    team: platform
    annotations:
    summary: "This is a test alert"
    description: "Testing the alerting pipeline. Please ignore."

    Appliquez avec le ConfigMap et redémarrez Prometheus.

  2. Vérifiez dans Prometheus → Alerts

    • T+0 : L’alerte apparaît en Pending
    • T+1min : L’alerte passe en Firing

    Ce que vous devez voir : L’alerte TestAlert en rouge (firing).

  3. Vérifiez dans Alertmanager

    Ouvrez http://localhost:9093

    Ce que vous devez voir : L’alerte TestAlert dans la liste.

  4. Vérifiez la notification

    • Si webhook.site : Rafraîchissez la page, l’alerte doit apparaître
    • Si Slack : Vérifiez votre channel
    • Si autre : Vérifiez la destination configurée
  5. Créez un silence

    • Dans Alertmanager → Silences → New Silence
    • Matcher : alertname=TestAlert
    • Durée : 10 minutes
    • Commentaire : “Testing silences”
  6. Vérifiez que le silence fonctionne

    L’alerte doit maintenant afficher “Silenced” dans Alertmanager.

  7. Supprimez la règle de test

    Retirez la règle TestAlert des values et appliquez avec helm upgrade.

❌ Mauvais (cause)✅ Bon (symptôme)
“CPU > 80%""Latence P99 > 500ms"
"Mémoire > 85%""Taux d’erreur > 1%"
"Connexions DB > 100""Temps de réponse DB > 200ms”

Pourquoi ? Les utilisateurs ne se soucient pas de votre CPU. Ils se soucient que le site soit lent.

# ❌ Pas actionnable - que dois-je faire ?
annotations:
summary: "CPU is high"
# ✅ Actionnable - je sais quoi vérifier
annotations:
summary: "CPU above 85% on {{ $labels.instance }}"
description: |
Check for:
- Runaway processes: top -c
- Recent deployments: kubectl rollout history
- Memory pressure leading to swapping
runbook: "https://wiki.example.com/runbooks/high-cpu"
  • 5-10 alertes critiques maximum
  • Trop d’alertes = fatigue d’alerte = alertes ignorées

La règle : “Si je reçois cette alerte à 3h du matin, dois-je me lever ?“

  • Déclenchez manuellement au moins une fois par mois
  • Vérifiez que les bonnes personnes reçoivent
  • Vérifiez que le runbook est à jour
CauseDiagnosticSolution
Expression incorrecteTestez expr dans Prometheus GraphCorrigez la syntaxe
Délai for trop longL’alerte est en PendingRéduisez ou attendez
Règle non chargéeStatus → RulesVérifiez les values Helm
Labels/métriques inexistantsTestez dans ExploreDécouvrez les vrais labels avec count by (...)
CauseDiagnosticSolution
Alertmanager ne reçoit pasUI Alertmanager videVérifiez la config Prometheus alerting
Routing incorrectConfig AlertmanagerTestez avec receiver default
Receiver mal configuréLogs Alertmanagerkubectl logs -n observability -l app.kubernetes.io/name=alertmanager
URL webhook invalidewebhook.site ne reçoit rienVérifiez que l’URL est accessible depuis le cluster
CauseSolution
Seuils trop basAjustez les seuils
Pas de groupageAjoutez group_by
Pas d’inhibitionsConfigurez les inhibitions
Métriques/labels mal ciblésVérifiez avec count by (...)
  1. Alertmanager est déployé et accessible

    Fenêtre de terminal
    kubectl get pods -n observability | grep alertmanager

    Le pod est en Running.

  2. Les règles sont chargées

    Prometheus → Status → Rules : vos groupes sont visibles.

  3. Le receiver fonctionne

    Déclenchez une alerte test et vérifiez la notification.

  4. Vous savez créer un silence

    Créez et supprimez un silence depuis l’UI.

  1. Prometheus évalue les règles d’alerte, Alertmanager route et notifie
  2. Une alerte passe par les états : Inactive → Pending → Firing → Resolved
  3. Le routing dirige les alertes vers les bons receivers
  4. Les silences gèrent les maintenances planifiées
  5. Les inhibitions réduisent le bruit automatiquement
  6. Une bonne alerte est actionnable avec un runbook

Vous avez maintenant un pipeline d’alerting complet. Mais les métriques ne sont qu’un des trois piliers de l’observabilité. Dans le prochain module, nous ajoutons les logs avec Loki.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.