Alertes téléphoniques Prometheus Alertmanager : ne sonner que pour le critique

Alertmanager n'a pas de récepteur vocal. Transformez vos alertes Prometheus en appel pour la seule sévérité critique : config webhook, conditions et le piège Watchdog.

Mis à jour

Table des matières

Alertmanager n'a pas de récepteur vocal. Pour recevoir un appel quand une alerte Prometheus se déclenche, ajoutez un récepteur webhook_configs pointant vers un canal Echobell dont le type d'abonnement est Appel. Ce guide couvre le YAML exact, la condition qui empêche les alertes résolues de vous appeler, le routage par sévérité, et l'alerte Watchdog qui, sinon, fera sonner votre téléphone toutes les quatre heures indéfiniment.

Prometheus est la pile de métriques par défaut de la plupart des infrastructures construites cette dernière décennie, et Alertmanager est vraiment bon sur les parties difficiles : dédupliquer les alertes, les regrouper, les mettre en silence pendant la maintenance, et inhiber le bruit en aval quand une dépendance en amont tombe.

La seule chose qu'il ne fera pas, c'est réveiller quelqu'un.

Pourquoi Alertmanager ne peut pas faire sonner votre téléphone

Alertmanager fournit des récepteurs pour e-mail, Slack, PagerDuty, OpsGenie, Discord, Telegram, Pushover, Webex, MS Teams et une douzaine d'autres. Tous délivrent un message, et les messages sont soumis au bouton silence, au mode Ne pas déranger et aux modes de concentration d'iOS. À 03:00, cela veut dire que l'alerte arrive et qu'il ne se passe rien.

Il n'existe pas de voice_configs. Les options sur lesquelles les gens finissent par tomber :

  • PagerDuty / OpsGenie / Splunk On-Call — ils appellent bel et bien, et ce sont des plateformes complètes de gestion d'incidents, avec la tarification par siège qui va avec. La bonne réponse si vous avez besoin de rotations et d'arbres d'escalade ; disproportionné si vous voulez juste qu'un téléphone sonne. (OpsGenie est d'ailleurs en fin de vie, ce qui explique pourquoi tant d'équipes réévaluent cette couche en ce moment.)
  • Passerelles SMS comme Sachet — vous faites tourner un service de plus, vous payez une passerelle au message, et un SMS reste un message. Sur iOS, un texto ne perce pas le mode Concentration sauf si l'expéditeur figure dans votre liste d'autorisations.
  • Bricolage Twilio — écrire un petit récepteur de webhooks, acheter un numéro, payer à l'appel, et vous voilà propriétaire d'un morceau d'infrastructure de production dont le seul rôle est de faire sonner un téléphone.

Le récepteur webhook générique est la porte de sortie. Il publie un JSON documenté vers n'importe quelle URL, et c'est tout ce qu'il vous faut.

Ce qu'il vous faut

  • Un Prometheus + Alertmanager en fonctionnement et l'accès pour éditer alertmanager.yml
  • Echobell installé (App Store / Google Play)
  • Dix minutes

Ce guide a été écrit avec Alertmanager 0.31. Le payload du webhook est en version: "4" depuis des années, les versions 0.2x se comportent donc de façon identique.

Votre Alertmanager a besoin d'un HTTPS sortant vers hook.echobell.one. Il n'a pas besoin d'être joignable depuis internet : un Alertmanager dans un cluster, un VPC ou un homelab fonctionne très bien.

Étape 1 — Créer un canal qui vous appelle

Dans Echobell, créez un canal nommé par exemple Prometheus Critical. Réglez son type de notification d'abonnement sur Appel. C'est le réglage qui compte : les alertes de type Appel arrivent sous forme d'écran d'appel entrant et sonnent malgré le mode Concentration et Ne pas déranger d'iOS, ce qu'une notification push ne fait pas.

Configurez les modèles pour lire directement le payload d'Alertmanager :

Title: 🔴 {{commonLabels.alertname}} on {{commonLabels.instance}}
Body: {{commonAnnotations.summary}}
{{commonAnnotations.description}}

Et, dans les Paramètres avancés, un modèle de lien pour que l'enregistrement de la notification ouvre directement le graphe :

{{alerts[0].generatorURL}}

Copiez ensuite l'URL du webhook du canal :

https://hook.echobell.one/t/<channel-token>

Traitez cette URL comme un secret — quiconque la détient peut faire sonner votre téléphone.

Étape 2 — Ajouter un récepteur webhook

Dans alertmanager.yml :

route:
  group_by: ["alertname", "cluster", "service"]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: echobell-critical

receivers:
  - name: echobell-critical
    webhook_configs:
      - url: "https://hook.echobell.one/t/<channel-token>"
        send_resolved: false

Rechargez avec curl -X POST http://localhost:9093/-/reload ou SIGHUP.

Notez le send_resolved: false. La valeur par défaut d'un récepteur webhook est true, contrairement à la plupart des autres récepteurs d'Alertmanager : l'omettre signifie que votre téléphone sonne quand le service casse et sonne à nouveau quand il se répare tout seul. C'est ce second appel qui apprend aux gens à ignorer le premier. L'étape 4 montre comment récupérer l'avis de rétablissement sans la sonnerie.

Étape 3 — Comprendre ce qui arrive réellement

Alertmanager regroupe les alertes, puis POSTe un payload par groupe :

{
  "version": "4",
  "groupKey": "{}:{alertname=\"HighErrorRate\"}",
  "truncatedAlerts": 0,
  "status": "firing",
  "receiver": "echobell-critical",
  "groupLabels": { "alertname": "HighErrorRate" },
  "commonLabels": { "alertname": "HighErrorRate", "severity": "critical" },
  "commonAnnotations": { "summary": "Error rate above 5% for 10m" },
  "externalURL": "http://alertmanager.internal:9093",
  "alerts": [
    {
      "status": "firing",
      "labels": { "alertname": "HighErrorRate", "instance": "api-7d9f:8080" },
      "annotations": { "summary": "Error rate above 5% for 10m" },
      "startsAt": "2026-09-04T02:41:07.351Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "generatorURL": "http://prometheus:9090/graph?g0.expr=...",
      "fingerprint": "a1b2c3d4e5f60718"
    }
  ]
}

Echobell lit le corps JSON tel quel : tous ces champs sont donc disponibles dans les modèles et les conditions. L'accès imbriqué fonctionne avec les deux syntaxes — {{commonLabels.severity}} ou {{alerts[0].labels["instance"]}}.

Deux propriétés de ce payload commandent tout le reste :

Le status de premier niveau vaut firing dès qu'une alerte du groupe est active. Il ne passe à resolved que lorsque toutes les alertes du groupe sont résolues. C'est donc un critère de filtrage très propre.

commonLabels ne contient que les labels partagés par toutes les alertes du groupe. C'est la surprise la plus fréquente. Si group_by est assez large pour qu'un webhook porte HighErrorRate sur trois instances différentes, commonLabels.instance est absent et {{commonLabels.instance}} s'affiche comme une chaîne vide. Une section plus bas explique comment gérer cela.

Étape 4 — Envoyer les rétablissements en push discret

Vous voulez toujours savoir quand quelque chose se rétablit — vous ne voulez simplement pas être appelé pour ça. Ajoutez un second canal Echobell nommé Prometheus Recovered, réglez-le sur le type Normal, donnez-lui ces modèles :

Title: ✅ {{commonLabels.alertname}} resolved
Body: {{commonAnnotations.summary}}

et, dans les Paramètres avancés, cette condition :

status == "resolved"

Les conditions sont des expressions évaluées avant toute livraison. Si l'expression est fausse, Echobell accepte la requête et n'envoie rien.

Pointez ensuite le même récepteur vers les deux canaux — un récepteur peut contenir plusieurs webhook_configs :

receivers:
  - name: echobell-critical
    webhook_configs:
      # Fait sonner le téléphone. Uniquement en cas de déclenchement.
      - url: "https://hook.echobell.one/t/<calling-channel-token>"
        send_resolved: false
      # Push discret. La condition du canal écarte la moitié « firing ».
      - url: "https://hook.echobell.one/t/<recovery-channel-token>"
        send_resolved: true

Le canal de rétablissement reçoit les payloads firing et resolved, et jette les premiers. Résultat : la panne sonne, le rétablissement arrive en push que vous lirez le matin.

Étape 5 — Router par sévérité, pas tout envoyer

Une route fourre-tout qui envoie chaque alerte vers un canal d'appel est une machine à produire des appels ignorés. Découpez par sévérité dans Alertmanager, là où l'arbre de routage a sa place :

route:
  group_by: ["alertname", "cluster", "service"]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: echobell-warning

  routes:
    # Watchdog n'atteint jamais un humain. Voir l'étape 6.
    - matchers:
        - alertname = "Watchdog"
      receiver: "null"

    - matchers:
        - severity = "critical"
      receiver: echobell-critical
      group_wait: 10s
      repeat_interval: 1h

receivers:
  - name: "null"

  - name: echobell-critical
    webhook_configs:
      - url: "https://hook.echobell.one/t/<calling-channel-token>"
        send_resolved: false

  - name: echobell-warning
    webhook_configs:
      - url: "https://hook.echobell.one/t/<normal-channel-token>"
        send_resolved: true

Les routes sont évaluées de haut en bas et la première correspondance gagnecontinue vaut false par défaut. L'ordre compte donc : la route Watchdog doit se placer au-dessus de tout ce qui pourrait l'avaler.

Si vous préférez garder un seul canal et filtrer côté Echobell, la condition équivalente est :

status == "firing" && commonLabels.severity == "critical"

Le faire dans Alertmanager est généralement préférable, car severity pilote alors aussi group_wait et repeat_interval. Le faire dans Echobell vaut mieux quand vous ne pouvez pas faire merger un changement de configuration aujourd'hui.

Étape 6 — Le piège Watchdog

Si vous utilisez kube-prometheus-stack, vous avez une alerte nommée Watchdog dont l'expression est vector(1). Elle est conçue pour se déclencher en permanence : elle existe pour qu'un système externe puisse remarquer que Prometheus lui-même s'est arrêté. La configuration par défaut la route vers un récepteur null.

Pointez une route fourre-tout vers un canal d'appel sans l'exclure et Watchdog appellera votre téléphone à chaque repeat_interval, indéfiniment, dès maintenant. C'est la raison numéro un pour laquelle les gens concluent que les alertes téléphoniques « ne marchent pas ».

Gardez la route null de l'étape 5. Puis, éventuellement, faites-en quelque chose d'utile : transformez Watchdog en véritable dead man's switch.

    - matchers:
        - alertname = "Watchdog"
      receiver: deadmansswitch
      group_wait: 0s
      group_interval: 1m
      repeat_interval: 50s

receivers:
  - name: deadmansswitch
    webhook_configs:
      - url: "https://hc-ping.com/<your-check-uuid>"
        send_resolved: false

Echobell ne peut pas être le dead man's switch lui-même : il alerte quand une requête arrive, pas quand elle cesse d'arriver. Envoyez donc le ping Watchdog à un service conçu pour détecter le silence (Healthchecks.io, Cronitor, Dead Man's Snitch), puis pointez le webhook « check tombé » de ce service vers votre canal d'appel Echobell. Un appel signifie alors « la supervision elle-même est morte », c'est-à-dire l'alerte pour laquelle vous voulez le plus être réveillé, et celle que personne ne configure.

Régler pour ne pas crier au loup

Trois réglages d'Alertmanager font l'essentiel du travail, plus un de Prometheus :

RéglageCe qu'il fait
for:Règle d'alerteDurée pendant laquelle la condition doit tenir avant de se déclencher. Votre première défense contre un hoquet de deux secondes.
group_waitRouteAttente avant la première notification, pour regrouper d'autres alertes. 30s par défaut ; descendez à 10s pour le critique.
group_intervalRouteÉcart minimal avant de notifier de nouvelles alertes dans un groupe existant. 5m par défaut.
repeat_intervalRouteFréquence de rappel d'une alerte non résolue. 4h par défaut : une panne nocturne vous appelle à 03:00, puis à nouveau à 07:00.

repeat_interval mérite réflexion. Quatre heures, c'est long pour laisser quelque chose cassé ; vingt minutes, c'est la garantie que vous finirez par désactiver le canal. Une heure sur le critique est un bon point de départ.

Si vous voulez qu'un appel manqué soit réessayé immédiatement plutôt qu'au prochain repeat_interval, activez Réessayer l'appel échoué dans les réglages de l'app Echobell.

Ne sonner qu'en dehors des heures ouvrées

En journée, vous regardez probablement déjà un tableau de bord. Les variables temporelles système d'Echobell (toutes en UTC) permettent à un canal de se comporter différemment selon l'heure, sans seconde route dans Alertmanager :

status == "firing" && (hour >= 17 || hour < 9)

Cela ne vous appelle qu'en dehors de 09:00–17:00 UTC. Pointez un second canal de type Normal sur la plage inverse pour les push de journée :

status == "firing" && hour >= 9 && hour < 17

Ajoutez dayOfWeek >= 1 && dayOfWeek <= 5 pour traiter aussi le week-end comme hors horaires. N'oubliez pas que tout est calculé en UTC — décalez selon votre fuseau. Traitement plus complet dans notifications par fenêtre temporelle avec les conditions UTC.

Gérer le problème du commonLabels vide

Quand un groupe contient des alertes provenant de plusieurs instances, commonLabels.instance disparaît et le titre de votre notification devient 🔴 HighErrorRate on .

Trois solutions, par ordre de préférence :

  1. Mettre le label dans group_by. Si group_by inclut instance, toutes les alertes d'un groupe le partagent et commonLabels.instance est toujours présent. Le coût : davantage de notifications — une par instance au lieu d'une par nom d'alerte.
  2. Lire la première alerte. {{alerts[0].labels.instance}} est toujours renseigné. Ce n'est qu'une parmi d'autres, alors associez-la à un compteur : {{alerts[0].labels.instance}} (+{{alerts.length}} alertes).
  3. Concevoir le libellé pour qu'il reste lisible à vide. Echobell n'a pas d'opérateur de valeur par défaut — {{a || "unknown"}} affiche le texte littéral true, pas un repli — alors écrivez Instance: {{commonLabels.instance}} sur sa propre ligne, où une valeur vide se voit comme telle plutôt que de casser une phrase.

Garder le payload petit

Un groupe couvrant cent pods produit un gros corps JSON, et Echobell rejette les corps de déclenchement au-delà de 1 Mio avec un HTTP 413. Plafonnez-le dans Alertmanager :

      - url: "https://hook.echobell.one/t/<channel-token>"
        send_resolved: false
        max_alerts: 20

Alertmanager envoie alors au plus vingt alertes et renseigne truncatedAlerts avec le nombre qu'il a écarté, que vous pouvez afficher dans le corps :

Body: {{commonAnnotations.summary}}
Alerts: {{alerts.length}} (+{{truncatedAlerts}} tronquées)

Partager l'alerte avec votre équipe

Un canal Echobell se partage par lien d'abonnement, et chaque abonné choisit son propre type de notification. La même route peut donc faire sonner le téléphone de l'ingénieur d'astreinte tout en arrivant en push normal pour les autres — sans tarification par siège, et sans règles de routage supplémentaires dans Alertmanager.

Cela colle aussi à la raison pour laquelle beaucoup d'équipes auto-hébergent Prometheus : vos métriques et règles d'alerte restent sur votre infrastructure, et Echobell conserve le contenu et l'historique des notifications sur l'appareil plutôt que sur ses serveurs.

Ce que cette configuration ne vous donne pas

Être honnête sur la frontière vous évite une mauvaise migration plus tard. Echobell est une couche de livraison, pas une plateforme de gestion d'incidents. Il n'a pas :

  • de plannings d'astreinte ni de passations follow-the-sun
  • d'arbres d'escalade qui appellent une deuxième personne si la première ne répond pas
  • de chronologies d'incident, de suivi d'acquittement ni d'outillage de post-mortem

Si votre équipe en a besoin, il vous faut PagerDuty, Grafana Cloud IRM ou équivalent. Ce que ceci couvre, c'est le trou précis laissé par Alertmanager : transformer une alerte active en téléphone qui sonne vraiment. Pour un opérateur solo, une petite équipe ou un homelab, c'est généralement tout le besoin.

Dépannage

Rien n'arrive du tout. Regardez d'abord les logs d'Alertmanager (level=error component=dispatcher), puis vérifiez que la route mène bien à votre récepteur : amtool config routes test severity=critical alertname=HighErrorRate vous dit dans quel récepteur une alerte atterrirait, sans attendre qu'elle se déclenche.

Echobell renvoie HTTP 404. Le token du canal est faux, ou le canal a été supprimé. Un token inconnu donne un 404, pas un succès silencieux.

Echobell renvoie 200 avec "notificationTriggered": false. Votre condition a été évaluée à faux. Le corps de la réponse porte aussi "conditionsMet": false, le moyen le plus rapide de distinguer « ma condition est mauvaise » de « mon webhook n'est jamais arrivé ». Vérifiez status == "firing" par rapport à ce qu'Alertmanager a réellement envoyé — le status de premier niveau, pas alerts[0].status.

HTTP 413. Le payload a dépassé 1 Mio. Réglez max_alerts comme ci-dessus.

HTTP 405. Le canal a POST Only activé et quelque chose a envoyé un GET. Alertmanager fait du POST, donc cela signifie en général que vous avez testé l'URL dans un navigateur.

Le titre comporte un trou. commonLabels ne contenait pas ce label pour ce groupe. Voir la section ci-dessus.

Ça ne sonne pas, mais la notification arrive. Le type de notification de l'abonnement est Normal ou Urgent, pas Appel. Le type se choisit par abonné : vérifiez sur l'appareil qui ne sonne pas.

Tester sans casser la production. Ajoutez une règle avec expr: vector(1), un alertname distinctif et severity: critical, laissez-la se déclencher une fois, puis supprimez-la. Ou déclenchez-en une à la main :

curl -X POST http://localhost:9093/api/v2/alerts -H 'Content-Type: application/json' -d '[
  {"labels":{"alertname":"EchobellTest","severity":"critical"},
   "annotations":{"summary":"Testing the phone call path"}}
]'

Questions fréquentes

Prometheus Alertmanager peut-il passer un appel nativement ?

Non. Alertmanager dispose de récepteurs e-mail, Slack, PagerDuty, OpsGenie et bien d'autres, mais il n'existe ni récepteur vocal ni récepteur SMS. Les appels nécessitent de router le récepteur webhook générique vers un service capable de les passer, comme Echobell, ou de payer une plateforme de gestion d'incidents.

L'appel passe-t-il outre le mode Ne pas déranger ?

Oui. Le type de notification Appel d'Echobell se présente comme un appel entrant, qui sonne malgré le mode Concentration et Ne pas déranger d'iOS. Les détails et les réglages sont dans comment contourner iOS Focus Mode pour les alertes critiques.

Est-ce que ça marche avec un Alertmanager derrière un pare-feu ou dans Kubernetes ?

Oui. Le webhook est une requête HTTPS sortante depuis Alertmanager : il lui suffit d'atteindre hook.echobell.one. Votre Alertmanager n'a besoin ni d'adresse publique ni d'ingress.

Comment arrêter d'être appelé quand une alerte se résout ?

Mettez send_resolved: false sur la configuration webhook qui pointe vers votre canal d'appel. Le récepteur webhook vaut true par défaut, contrairement à la plupart des autres récepteurs d'Alertmanager : c'est donc de l'opt-out et non de l'opt-in. Pour continuer à recevoir les rétablissements discrètement, ajoutez un second canal avec la condition status == "resolved".

Pourquoi mon téléphone sonne-t-il toutes les quatre heures pour la même alerte ?

C'est repeat_interval, dont la valeur par défaut est 4h. Alertmanager renotifie une alerte toujours active à cette cadence. Réglez-le par route — 1h sur le critique est un choix courant. Si les appels ont commencé juste après l'ajout d'une route fourre-tout, le coupable est plus probablement l'alerte Watchdog, toujours active ; voir l'étape 6.

Plusieurs personnes peuvent-elles être appelées pour la même alerte ?

Oui. Partagez le canal avec vos collègues et chaque abonné choisit son type de notification. Tous ceux qui sont abonnés au canal d'appel sont appelés, sans coût par siège.

Faut-il filtrer la sévérité dans Alertmanager ou dans les conditions Echobell ?

Préférez Alertmanager : router là-bas vous laisse aussi régler group_wait et repeat_interval par sévérité, et l'arbre de routage reste versionné avec le reste de la configuration. Utilisez les conditions Echobell quand vous ne pouvez pas modifier la config Alertmanager, ou pour des filtres qu'Alertmanager ne connaît pas — comme l'heure de la journée.

Conclusion

L'installation tient en un récepteur, un send_resolved: false et un arbre de routage qui tient tout ce qui n'est pas severity: critical à l'écart du canal d'appel. Elle laisse vos règles d'alerte, vos regroupements, vos silences et vos inhibitions exactement en l'état, et comble l'écart entre « Prometheus a remarqué » et « un humain a remarqué ».

Téléchargez Echobell pour iPhone ou récupérez-le sur Google Play, puis déclenchez l'alerte EchobellTest ci-dessus avant de confier quoi que ce soit de réel à ce chemin.


À lire aussi