Alertmanager: Routing für viele Teams
Routes, Inhibition und weniger Alert-Müll.
von PlatPrep
3:47 Uhr. Das Telefon klingelt. Eine Alert-Notification — aus einem Cluster in einer Region, die seit Monaten nicht mehr in Produktion sein sollte. Jemand hatte vergessen, die Alert-Rules zu deaktivieren.
Das ist kein Prometheus-Problem. Das ist ein Alertmanager-Routing-Problem.
Alertmanager ist oft das vergessene Stück im Monitoring-Stack. Prometheus sammelt, Grafana visualisiert — aber Alertmanager entscheidet: wer bekommt welchen Alert, wann, in welchem Format, mit welcher Dringlichkeit. Diese Entscheidungen stehen in einer Konfigurationsdatei, die viele Teams einmal aufgesetzt und danach nie mehr systematisch gepflegt haben.
Der Routing-Baum, richtig gebaut
Das Routing-Modell ist baumförmig: Ein Alert traversiert den Baum von oben nach unten und landet beim ersten Sub-Route, dessen Matcher passen — oder beim Default-Receiver der Wurzel. Ein Setup, das für mehrere Teams gut funktioniert, sieht so aus:
route:
receiver: default
group_by: ["alertname", "cluster", "namespace"]
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
routes:
- matchers:
- environment != "production"
receiver: low-prio-slack
- matchers:
- team = "checkout"
routes:
- matchers:
- severity = "critical"
receiver: checkout-pagerduty
- receiver: checkout-slack
mute_time_intervals:
- nachts
Zwei Dinge daran sind bewusst gewählt. Erstens fängt die Non-Production-Route ganz oben alles ab, was nicht aus Produktion kommt — egal von welchem Team. Genau das hätte den 3:47-Uhr-Anruf aus dem Intro verhindert. Zweitens braucht jeder Alert ein team-Label, gesetzt direkt in den Prometheus-Alert-Rules oder per Relabeling. Fehlt es, landet der Alert beim Default-Receiver — und der wird erfahrungsgemäß zur Müllhalde, die niemand liest. Ein eigener Alert auf “Alerts ohne team-Label” lohnt sich.
Die drei Timing-Parameter werden notorisch verwechselt. group_wait ist die Wartezeit, bevor die erste Notification für eine neue Alert-Gruppe rausgeht — damit zusammengehörige Alerts (zehn Pods desselben Deployments) in einer Nachricht landen statt in zehn. group_interval bestimmt, wie schnell über neue Alerts in einer bereits feuernden Gruppe informiert wird. Und repeat_interval legt fest, wann ein unverändert feuernder Alert erneut zugestellt wird. Ein repeat_interval von einer Stunde klingt nach Gründlichkeit, bedeutet aber: bei einem sechsstündigen Incident wirst du sechsmal für dasselbe Problem angerufen. Zwölf oder 24 Stunden sind für die meisten Setups vernünftiger.
Wer einen Alert an mehrere Empfänger gleichzeitig schicken will — etwa Critical-Alerts zusätzlich in einen zentralen Incident-Kanal — nutzt continue: true auf der Route. Ohne das Flag stoppt das Matching nach dem ersten Treffer.
Inhibition: weniger Lärm bei großen Ausfällen
Wenn ein kompletter Cluster down ist, willst du nicht zwanzig einzelne Service-Alerts. Eine Inhibition Rule unterdrückt nachgelagerte Alerts, solange der Ursachen-Alert feuert:
inhibit_rules:
- source_matchers:
- alertname = "ClusterDown"
target_matchers:
- severity =~ "warning|info"
equal: ["cluster"]
Das equal-Feld ist der Teil, der gern vergessen wird: Source- und Target-Alert müssen denselben Wert im cluster-Label haben. Ohne equal unterdrückt ein ClusterDown in Frankfurt auch die Warnings aus Dublin — und du merkst erst Stunden später, dass dort ebenfalls etwas brennt.
Für Geplantes sind Silences das richtige Werkzeug: kein Auskommentieren von Alert-Rules, kein Abschalten von Receivern, sondern eine Silence mit Matcher und Ablaufzeit für das Maintenance-Fenster. Für wiederkehrende Ruhezeiten — Slack-Warnings, die nachts niemand lesen soll — sind time_intervals die sauberere Lösung, weil sie deklarativ in der Config stehen statt als manuell gesetzte Silence, die jemand vergisst zu erneuern.
Config testen statt hoffen
Die Routing-Konfiguration gehört unter Versionskontrolle und durch eine CI-Pipeline. amtool macht beides leicht:
amtool check-config alertmanager.yml
amtool config routes test --config.file=alertmanager.yml \
team=checkout severity=critical environment=production
Der zweite Befehl beantwortet die Frage “wo landet dieser Alert?” deterministisch — statt sie im nächsten Incident empirisch zu klären. In der PR-Pipeline ausgeführt, fängt das die klassischen Fehler ab: Route-Reihenfolge vertauscht (first match wins!), Tippfehler im Label-Namen, Matcher der nie greift.
Noch ein Betriebsdetail, das regelmäßig für doppelte Pages sorgt: Alertmanager läuft in Produktion mit zwei oder drei Replicas, die sich über ein Gossip-Protokoll synchronisieren und Notifications deduplizieren. Wenn die Replicas einander nicht erreichen — falsche --cluster.peer-Adressen, NetworkPolicy dazwischen — sendet jede Instanz unabhängig. Jeder Alert kommt dann zwei- oder dreifach an, und das Team lernt schnell, Alerts zu ignorieren. Das Gegenteil von dem, was Alerting erreichen soll.
Wie man Alerts schreibt, die überhaupt pageworthy sind, ist ein eigenes Thema — dazu mehr unter SLOs und Error Budgets in der Praxis und im Prometheus-Lernpfad. Aber selbst die besten Alert-Rules helfen nichts, wenn das Routing sie um 3:47 Uhr an die falsche Person schickt.