Aller au contenu

Tp slides

Introduction


Qu'est-ce qu'Alertmanager ?

Alertmanager est le composant de gestion des alertes de l'écosystème Prometheus

Il prend en charge :

  • La réception des alertes envoyées par Prometheus (ou d'autres sources)
  • Le regroupement (grouping) d'alertes similaires
  • Le routage vers les bons destinataires
  • La déduplication pour éviter le spam
  • La suppression via inhibitions et silences



Alertmanager ne génère pas d'alertes — il les gère.


Ce qu'Alertmanager n'est PAS

  • ❌ Un moteur de règles (c'est Prometheus)
  • ❌ Un outil de visualisation (c'est Grafana)
  • ❌ Un système de stockage de métriques
  • ❌ Un remplacement à un on-call management (OpsGenie, PagerDuty ont plus de fonctionnalités)

Concepts Fondamentaux


Le cycle de vie d'une alerte

Prometheus évalue une règle
   État : PENDING  ◄── for: 5m  (délai avant firing)
   État : FIRING   ──► envoi à Alertmanager
   État : RESOLVED ──► envoi de résolution à Alertmanager

Les alertes sont envoyées toutes les evaluation_interval tant qu'elles sont actives


Les Labels

Les alertes sont identifiées par des labels (paires clé/valeur)

# Exemple de règle Prometheus
groups:
  - name: infra
    rules:
      - alert: HighCPU
        expr: cpu_usage_percent > 90
        for: 5m
        labels:
          severity: critical
          team: platform
        annotations:
          summary: "CPU élevé sur {{ $labels.instance }}"
          description: "CPU à {{ $value }}% depuis 5 min"



Les labels servent au routing. Les annotations servent aux messages


Grouping (Regroupement)

Regroupe des alertes similaires en une seule notification

Alertes reçues :
  - InstanceDown{instance="web-01", env="prod"}
  - InstanceDown{instance="web-02", env="prod"}
  - InstanceDown{instance="db-01",  env="prod"}

Avec group_by: [alertname, env]
  Une seule notification : "3 instances down en prod"

Réduit drastiquement le bruit lors d'incidents majeurs


Les trois délais de groupe

Paramètre Rôle Défaut
group_wait Attendre d'autres alertes avant le 1er envoi 30s
group_interval Délai entre deux notifications d'un même groupe 5m
repeat_interval Délai avant de re-notifier si rien n'a changé 4h
t=0s   → Alerte A reçue → attendre group_wait...
t=30s  → Notification envoyée (A)
t=35s  → Alerte B reçue (même groupe)
t=5m35s → Notification envoyée (A + B)  ← group_interval
t=4h35m → Re-notification si toujours actif ← repeat_interval

Inhibition

Supprime des alertes moins importantes quand une alerte critique est active

Si NodeDown{env="prod"} est FIRING
  → Inhiber toutes les alertes avec {env="prod"}
     sauf NodeDown elle-même

Exemple concret : Un nœud est down → inutile de notifier que ses services sont aussi down


Silences

Mute temporairement des alertes manuellement (maintenance, incidents connus)

  • Définis via l'UI web ou l'API
  • Ciblés par matchers (labels)
  • Associés à un auteur et un commentaire
  • Durée limitée avec expiration automatique

Routing des Alertes


L'arbre de routage

Le routing est une arborescence de nœuds :

route (root)
 ├── route (match: severity=critical)
 │    ├── route (match: team=platform)
 │    └── route (match: team=backend)
 └── route (match: severity=warning)
      └── route (match: env=staging)

Chaque alerte descend l'arbre et est envoyée au premier nœud correspondant (sauf si continue: true)


Nœud de route — Tous les paramètres

route:
  receiver: 'default'         # Receiver si aucun enfant ne correspond
  group_by: ['alertname']     # Labels de groupement
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h

  routes:
    - matchers:               # Nouvelle syntaxe (v0.22+)
        - name: severity
          value: critical
          isRegex: false
      receiver: 'pagerduty'
      continue: false         # Stoppe la descente après match

Matchers — Syntaxes

Syntaxe moderne (recommandée)

matchers:
  - name: severity
    value: critical
  - name: env
    value: prod|staging
    isRegex: true

Syntaxe PromQL-like (dans match et match_re)

match:
  severity: critical
  team: platform

match_re:
  service: "^(api|auth|gateway)$"

Exemple complet de routage

route:
  receiver: 'slack-general'
  group_by: ['alertname', 'env']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 12h

  routes:
    - matchers:
        - name: severity
          value: critical
      receiver: 'pagerduty-critical'
      group_wait: 10s
      repeat_interval: 1h
      routes:
        - matchers:
            - name: team
              value: database
          receiver: 'pagerduty-dba'

    - matchers:
        - name: env
          value: staging
      receiver: 'slack-staging'
      continue: true          # Notifie staging ET continue

    - matchers:
        - name: severity
          value: warning
      receiver: 'slack-warnings'

continue: true — Cas d'usage

Par défaut, la descente s'arrête au premier match

continue: true permet de matcher plusieurs routes :

Alerte: {severity=critical, team=platform, env=prod}

route:
  routes:
    - match: {env: prod}
      receiver: audit-log    ◄── continue: true
      continue: true
    - match: {severity: critical}
      receiver: pagerduty    ◄── match aussi !

Utile pour logger toutes les alertes prod tout en routant vers les bons receivers


Receivers & Intégrations


Vue d'ensemble des receivers

Receiver Usage
email_configs Notifications par email
slack_configs Messages Slack
pagerduty_configs Incidents PagerDuty
opsgenie_configs Incidents OpsGenie
webhook_configs HTTP générique
victorops_configs VictorOps / Splunk On-Call
wechat_configs WeChat Enterprise
msteams_configs Microsoft Teams (v0.26+)
sns_configs Amazon SNS
telegram_configs Telegram

Email

receivers:
  - name: 'email-ops'
    email_configs:
      - to: 'ops-team@example.com'
        from: 'alertmanager@example.com'
        smarthost: 'smtp.example.com:587'
        auth_username: 'alertmanager'
        auth_password: 'secret'
        require_tls: true

        # HTML ou texte
        html: '{{ template "email.html" . }}'
        headers:
          Subject: '[{{ .Status | toUpper }}] {{ .GroupLabels.alertname }}'

        # Envoyer aussi les résolutions
        send_resolved: true

Slack

receivers:
  - name: 'slack-critical'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/T.../B.../XXX'
        channel: '#alerts-critical'
        username: 'Alertmanager'
        icon_emoji: ':fire:'
        send_resolved: true

        title: '{{ template "slack.title" . }}'
        text: |
          {{ range .Alerts }}
          *Alert:* {{ .Annotations.summary }}
          *Severity:* `{{ .Labels.severity }}`
          *Instance:* {{ .Labels.instance }}
          {{ end }}

        # Couleur selon le statut
        color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}'

PagerDuty

receivers:
  - name: 'pagerduty-prod'
    pagerduty_configs:
      - routing_key: '<INTEGRATION_KEY>'
        severity: '{{ .CommonLabels.severity }}'
        description: >
          {{ .CommonAnnotations.summary }}

        # Détails supplémentaires
        details:
          firing: '{{ .Alerts.Firing | len }}'
          resolved: '{{ .Alerts.Resolved | len }}'
          env: '{{ .CommonLabels.env }}'

        send_resolved: true

Webhook (générique)

receivers:
  - name: 'custom-webhook'
    webhook_configs:
      - url: 'https://my-service.example.com/alerts'
        send_resolved: true
        http_config:
          bearer_token: 'my-secret-token'
        max_alerts: 0  # 0 = illimité

Microsoft Teams (v0.26+)

receivers:
  - name: 'teams-ops'
    msteams_configs:
      - webhook_url: 'https://outlook.office.com/webhook/...'
        title: '{{ template "teams.title" . }}'
        text: '{{ template "teams.text" . }}'
        send_resolved: true

Templates de messages

Alertmanager utilise le moteur de templates Go text/template

# templates/slack.tmpl

{{ define "slack.title" }}
  [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}]
  {{ .GroupLabels.SortedPairs.Values | join " " }}
  {{ if gt (len .CommonLabels) (len .GroupLabels) }}
    ({{ with .CommonLabels.Remove .GroupLabels.Names }}{{ .Values | join " " }}{{ end }})
  {{ end }}
{{ end }}

{{ define "slack.text" }}
  {{ range .Alerts }}
  • *{{ .Annotations.summary }}*
    {{ .Annotations.description }}
  {{ end }}
{{ end }}

Fonctions de templates utiles

Fonction Description
toUpper / toLower Changement de casse
title Première lettre en maj
join " " Jointure de liste
len Longueur
humanizeDuration Durée lisible
humanize Nombre lisible
.Alerts.Firing Alertes actives
.Alerts.Resolved Alertes résolues
.CommonLabels Labels communs
.GroupLabels Labels de groupe

Inhibition & Silences


Inhibition — Principe

inhibit_rules:
  - source_matchers:   # L'alerte qui inhibe
      - name: alertname
        value: NodeDown
      - name: env
        value: prod

    target_matchers:   # Les alertes inhibées
      - name: env
        value: prod

    # Labels qui doivent correspondre entre source et target
    equal:
      - 'instance'
      - 'env'

equal : la règle ne s'applique que si ces labels ont la même valeur dans source et target


Exemples d'inhibition

Cluster down → ignorer les pods

inhibit_rules:
  - source_matchers:
      - name: alertname
        value: KubernetesNodeNotReady
    target_matchers:
      - name: alertname
        value: KubernetesPodNotReady
    equal: ['node']

Critique inhibe warning

inhibit_rules:
  - source_matchers:
      - name: severity
        value: critical
    target_matchers:
      - name: severity
        value: warning
    equal: ['alertname', 'service', 'env']

Silences

Via l'UI Web (port 9093)

  1. Ouvrir http://alertmanager:9093
  2. Cliquer "New Silence"
  3. Définir les matchers
  4. Choisir la durée
  5. Ajouter auteur + commentaire

Silences via API

# Créer un silence
curl -X POST http://alertmanager:9093/api/v2/silences \
  -H "Content-Type: application/json" \
  -d '{
    "matchers": [
      {"name": "env", "value": "staging", "isRegex": false},
      {"name": "severity", "value": "warning", "isRegex": false}
    ],
    "startsAt": "2024-01-15T22:00:00Z",
    "endsAt":   "2024-01-16T06:00:00Z",
    "createdBy": "john.doe",
    "comment":   "Maintenance nuit"
  }'

# Lister les silences
curl http://alertmanager:9093/api/v2/silences

# Supprimer un silence
curl -X DELETE http://alertmanager:9093/api/v2/silences/{silenceID}

Silences via amtool

# Installer amtool
go install github.com/prometheus/alertmanager/cmd/amtool@latest

# Configurer
cat ~/.config/amtool/config.yml
# alertmanager.url: http://alertmanager:9093

# Créer un silence
amtool silence add \
  alertname=HighCPU \
  env=staging \
  --duration=2h \
  --author="john.doe" \
  --comment="Tests de charge"

# Lister
amtool silence query

# Expirer un silence
amtool silence expire <id>

Bonnes Pratiques & Troubleshooting


L'API d'Alertmanager

Endpoint Méthode Description
/api/v2/alerts GET Lister les alertes actives
/api/v2/alerts POST Pousser des alertes manuellement
/api/v2/alertgroups GET Lister les groupes
/api/v2/silences GET/POST Gérer les silences
/api/v2/silences/{id} GET/PUT/DELETE Opérations sur un silence
/api/v2/status GET État du cluster
/-/healthy GET Health check
/-/ready GET Readiness check
/-/reload POST Rechargement config

Valider la configuration

# Vérifier la syntaxe du fichier de config
./amtool check-config alertmanager.yml

# Résultat attendu
Checking 'alertmanager.yml'  SUCCESS
Found:
 - global config
 - route
 - 3 inhibit rules
 - 5 receivers
 - 2 templates

# Rechargement à chaud (sans redémarrage)
curl -X POST http://alertmanager:9093/-/reload

Tester le routage

# Simuler une alerte et voir quel receiver sera notifié
amtool config routes test \
  --config.file=alertmanager.yml \
  severity=critical \
  team=platform \
  env=prod

# Résultat
Routing tree:
.
└── default-route  receiver: slack-general
    └── child-route  receiver: pagerduty-critical   MATCH

Envoyer une alerte manuellement (test)

# Via amtool
amtool alert add \
  alertname=TestAlert \
  severity=warning \
  env=staging \
  --annotation=summary="Test depuis amtool" \
  --end=$(date -d '+1h' --iso-8601=seconds)

# Via API
curl -X POST http://alertmanager:9093/api/v2/alerts \
  -H "Content-Type: application/json" \
  -d '[{
    "labels": {
      "alertname": "TestAlert",
      "severity": "warning",
      "env": "staging"
    },
    "annotations": {
      "summary": "Test manuel"
    },
    "endsAt": "2024-01-15T12:00:00Z"
  }]'

☕️ Si tu souhaites soutenir mon travail, tu peux m'offrir un café ici.