7 Punkte von dongho42 2 시간 전 | Noch keine Kommentare. | Auf WhatsApp teilen

Einleitung

Mit dem Wachstum des Service nahm auch die Zahl der Signale zu, die im Betrieb überprüft werden müssen. In diesem Artikel stelle ich vor, wie wir Alerts als Code verwalten und den Reaktionsfluss bis hin zu Slack und PagerDuty standardisiert haben.

Das ursprüngliche Ziel war einfach: Alerts leichter erstellen, ansprechender versenden und klar machen, wer sie sehen muss. Im weiteren Betrieb haben wir dann zusätzlich grouped Alerts, wiederholte Definitionen, die Automatisierung von Reaktionen und sogar die Stabilität des Monitoring-Systems selbst weiter verbessert.


Motivation

Es gibt viele Möglichkeiten, die Verfügbarkeit eines Service zu erhöhen und die Auswirkungen auf Nutzer zu verringern.

Bei dieser Arbeit lag der Fokus auf der Verbesserung des Alert-Systems.

Alerts sind eher eine Betriebsschnittstelle, die zwischen Störungsprävention und Störungsreaktion vermittelt. Werden Risikosignale früher erkannt, kann man eingreifen, bevor sie zu einer tatsächlichen Störung führen. Und selbst nach dem Auftreten einer Störung können die Verantwortlichen sie schneller bemerken und früher mit der Reaktion beginnen.

Auch die gewünschte Richtung der Verbesserung war damals klar: Risikosignale besser erfassen, dafür sorgen, dass die Verantwortlichen sie schneller bemerken, den Übergang direkt zu Untersuchung und Reaktion schaffen und wiederkehrende Reaktionsabläufe reduzieren.

Wir haben nicht von Anfang an alles quantitativ gemessen, aber das Problembewusstsein war eindeutig: Alerts sollten nicht bloß Benachrichtigungen sein, sondern ein Betriebssystem, das Störungen verhindert und mit der Reaktion verbindet.


Die Rolle von Alerts

Für einen stabilen Service ist es wichtig, Störungen zu verhindern, aber genauso wichtig ist es, Anzeichen von Anomalien im laufenden Betrieb schnell zu erkennen.

Alerts übernehmen an dieser Stelle zwei Aufgaben. Vor dem Auftreten einer Störung helfen sie dabei, Risikosignale schnell zu erkennen und noch vor einer tatsächlichen Störung vorbeugend zu handeln. Nach dem Auftreten einer Störung informieren sie die Verantwortlichen über das Problem und verknüpfen direkt mit den nächsten Schritten wie Context, Runbook, Dashboard, Log und Silence, die für die Lageeinschätzung nötig sind.

Mit anderen Worten: Alerts sind nicht einfach nur Benachrichtigungen, die "Es gibt ein Problem" melden, sondern eher eine Betriebsschnittstelle, die Prävention und Reaktion bei Störungen verbindet.


Schwachstellen der bisherigen Alerts

Bei den bisherigen Alerts gab es vor allem drei große Schwachstellen. Sie waren schwer zu erstellen, auch nach dem Empfang nicht sofort leicht verständlich und es war nicht klar, wer reagieren und sie verwalten sollte.

Alerts waren schwer zu erstellen

Damals waren an Erstellung und Zustellung von Alerts viele Systeme beteiligt, darunter Grafana, Slack, PagerDuty, CloudWatch, EventBridge und Lambda. Auch die Datenquellen waren vielfältig: NewRelic, VictoriaMetrics, Steampipe, OpenSearch, Druid und MySQL.

Auch die Arbeitsweise unterschied sich je nach Alert. Manche Alerts wurden direkt aus Grafana an Slack gesendet, andere hängten hinter einen CloudWatch Alarm noch eine Lambda-Funktion, wieder andere bewerteten den Zustand von AWS-Ressourcen über Abfragen mit Steampipe. Wenn eine PagerDuty-Integration nötig war, mussten zusätzlich eigene Einstellungen berücksichtigt werden.

Das Problem war der Mangel an organisationsweiten Konventionen. Es war nicht ausreichend festgelegt, wo welcher Alert verwaltet werden sollte, ob er nur an Slack oder auch an PagerDuty gehen sollte, welche Beschreibungen und Links in die Nachricht gehören und wo das verantwortliche Team sowie der Zustellweg verwaltet werden sollten.

Dadurch wurden Alerts zwar nach Bedarf erstellt, aber mit der Zeit zersplitterten sowohl ihre Erstellung als auch ihre Verwaltung immer stärker.

Alerts waren schwer zu überblicken

Nur weil ein Alert erstellt war, bedeutete das nicht automatisch, dass die Slack-Nachricht tatsächlich immer gut lesbar war. Je nach Ersteller und System unterschieden sich Format und Informationsqualität, manche Alerts hatten lange und komplizierte Titel, und interne Werte wie Value oder Labels wurden teils unverändert offengelegt.

Selbst wenn Links vorhanden waren, war nicht immer klar, was man zuerst prüfen sollte. Und auch wenn es Buttons für Dashboard oder Log gab, funktionierte die tatsächliche Verknüpfung nicht immer. Zudem fehlte oft der Context des Alerts, sodass die Verantwortlichen Service, Cluster, Ressource oder Zeitbereich erst erneut suchen mussten.

In Störungssituationen fühlen sich schon wenige Minuten sehr lang an. Deshalb musste man beim Erhalt eines Alerts sofort erfassen können, um welches Problem es geht, wie wichtig es ist, welcher Service und welche Ressource betroffen sind, wo zuerst nachgesehen werden sollte und was der nächste Schritt ist.

Es war schwer, die Reaktionsverantwortung für Alerts zu steuern

Wenn ein Alert ausgelöst wurde, war oft auch unklar, wer ihn prüfen und darauf reagieren sollte. Wenn weder verantwortliches Team noch zuständige Person ersichtlich waren, musste die Person, die den Alert sah, zuerst klären: "Muss ich mir das ansehen?", "Wen sollte ich fragen?" Schon diese kurze Einschätzung kann in einer Störungssituation zu Verzögerungen führen.

Wichtig war dabei nicht nur die Verantwortung nach dem Auslösen eines Alerts, sondern auch, wer den Alert selbst besitzt und verwaltet. Es musste ebenfalls sichtbar sein, zu welchem Team-Service der Alert gehört, wer Bedingungen ändern darf, wie Nachricht oder Schwellenwerte überprüft werden und wer veraltete Alerts bereinigt.

Zusammengefasst wollten wir folgende Probleme verbessern:

  • Die Art, Alerts zu erstellen und zu verwalten, war zersplittert
  • Selbst nach dem Empfang eines Alerts war seine Bedeutung nicht auf einen Blick erfassbar
  • Wenn ein Alert ausgelöst wurde, war unklar, wer ihn prüfen und darauf reagieren sollte
  • Auch welches Team den Alert selbst besitzen und verwalten sollte, war nicht eindeutig

Was wir wie verbessert haben

Die Verbesserungsrichtung bestand aus drei Punkten: die Art der Alert-Erstellung standardisieren, in Slack-Nachrichten die nötigen Informationen in einer einheitlichen Struktur bereitstellen und die Struktur so ordnen, dass für jeden Alert Verantwortliche und Zustellweg sichtbar sind.

Erstellung und Verwaltung von Alerts standardisieren

Zunächst haben wir Erstellung und Verwaltung der Alerts in einem Ansatz gebündelt. Die Auswertung und Ausführung von Alert-Regeln wurden auf Grafana vereinheitlicht, die Integrationen zwischen Grafana, Slack und PagerDuty wurden über ein Terraform Module abstrahiert, und alle Alert-Definitionen werden nun als IaC im Verzeichnis alerts/ des internen alerts-Repositories verwaltet. Auch die Anbindung von Slack-Kanälen, die PagerDuty-Integration, das Nachrichtenformat und die Erzeugung gemeinsamer Buttons übernimmt nun ein gemeinsames Modul.

Dadurch mussten sich die Autoren von Alerts nicht mehr mit der gesamten Alert-Pipeline im Detail auskennen, sondern konnten sich stärker darauf konzentrieren, welche Bedingungen erkannt werden sollen, wie wichtig ein Alert ist, wer ihn prüfen soll und welche Informationen für die Reaktion nötig sind.

Im Repository wurden außerdem Schreibweise, Verzeichnisstruktur, erforderliche Felder und empfohlene Konventionen gemeinsam verwaltet. Da Alerts als Code verwaltet werden, bleiben Reviews und Änderungshistorien auch auf Ebene von PRs und Commits erhalten.

Verzeichnisstruktur für Alerts

Alle Alerts wurden so organisiert, dass sie der Struktur {main-category}/{sub-category}/{severity}/{alert-name}.yml folgen.

Zum Beispiel:

  • infra/kubernetes/critical/pod-unhealthy.yml
  • data/airflow/warning/task-failed.yml
  • finops/aws/warning/cost-increase.yml

Anhand dieser Struktur lässt sich schon am Dateipfad erkennen, zu welchem Bereich ein Alert gehört und mit welchem Schweregrad er behandelt wird. Sie lässt sich außerdem nutzen, um Alerts eines bestimmten Bereichs gesammelt zu betrachten, doppelte oder veraltete Alerts zu prüfen oder Slack-Kanäle, PagerDuty Service und CODEOWNERS daran zu koppeln.

Art der Alert-Definition

Jede Alert-Datei enthält gemeinsam Informationen wie datasource, query, threshold, condition und message.

Wir haben keine neue eigene DSL eingeführt. Stattdessen war es eher eine YAML-Darstellung der als JSON serialisierten Inhalte von Grafana Alerts. Dadurch ließ sich nahezu jeder Alert, der in Grafana definiert werden konnte, in derselben Struktur als IaC abbilden.

In letzter Zeit nutzen wir auch LLMs. Wenn jemand in natürlicher Sprache beschreibt, "unter welchen Bedingungen er mit welcher Nachricht einen Alert erhalten möchte", erstellt das LLM unter Bezug auf bestehende Beispiele und Konventionen einen ersten Entwurf einer Alert-Definition im YAML-Format. So können sich die Autoren von Alerts stärker darauf konzentrieren, was erkannt werden soll und warum es nötig ist, statt auf komplexe Serialisierungsformate.

Alert-Nachrichten so gestalten, dass sie sofort verständlich sind und direktes Handeln ermöglichen

Wir haben auch Alert-Nachrichten als eine Art Schnittstelle betrachtet. In Störungssituationen bleibt oft keine Zeit, eine Nachricht in Ruhe zu interpretieren. Deshalb sollte man bei jedem Alert an derselben Stelle dieselbe Art von Informationen finden können.

Deshalb wurde die Struktur der Slack-Nachrichten konsistent vereinheitlicht. Der Titel enthält den Alert-Namen, den Status und den Schweregrad, und der Textkörper enthält eine unmittelbar verständliche Beschreibung für Menschen sowie zuständige Person, Team, Service, Region, Ressourcennamen und wichtige Labels. Auch die Buttons wurden in gemeinsame und optionale Buttons aufgeteilt, sodass standardmäßig IaC, PagerDuty, Silence bereitgestellt werden und nur bei Bedarf Runbook, Dashboard, Log angezeigt werden.

Die gemeinsamen Buttons wurden vom System automatisch erzeugt und verknüpft, und auch alle Statusänderungen eines Alerts wurden im Slack-Thread protokolliert. So ließ sich in einem einzigen Verlauf sehen, wer den Alert acknowledged hat, ob er in Slack oder in PagerDuty bearbeitet wurde, wann er resolved wurde und welche Notizen während der Reaktion hinterlassen wurden.

Dadurch sah die Darstellung in Slack am Ende ähnlich aus, unabhängig davon, wer welchen Alert erstellt hatte, und die Teammitglieder konnten schneller entscheiden, worauf sie schauen mussten.

Verantwortungsstruktur für Alerts klar machen

Genauso wichtig wie das unmittelbare Verständnis eines Alerts war es, sichtbar zu machen, wer die Verantwortung trägt und ihn prüfen muss.

Dafür wurden die Tag- und Label-Informationen der Ressourcen im Reaktionsfluss genutzt. Statt für jeden Alert direkt ein zuständiges Team oder eine zuständige Person festzulegen, wurden Metadaten wie Service, Team, Ressource und Umgebung verwendet, damit in Slack-Nachrichten automatisch das passende Team und die passende Person erwähnt werden.

Auch die Weiterleitungswege wurden innerhalb derselben Regeln strukturiert. Auf Basis der Klassifizierung und severity eines Alerts wurden Slack-Kanal, PagerDuty Service und Escalation Policy automatisch verknüpft. Alerts auf Warning-Niveau wurden nur an Slack-Kanäle gesendet, während kritische Alerts mit hohem Nutzer-Impact oder großer Ausfallwahrscheinlichkeit zusätzlich ein PagerDuty Incident erzeugten.

Auch CODEOWNERS wurde mit genutzt. Die Alert-Dateien wurden je nach Kategorie und Service-Bereich in Verzeichnisse aufgeteilt, und in CODEOWNERS wurde pro Pfad das zuständige Team festgelegt, sodass im Repository sichtbar wurde, welches Team welchen Alert-Bereich besitzt.

Dadurch wurde die Verantwortlichkeit für Alerts letztlich an zwei Stellen verwaltet. Wenn ein Alert tatsächlich ausgelöst wurde, wurden auf Basis von Tags und Labels das zuständige Team und die zuständige Person erwähnt, und wenn die Alert-Definition geändert wurde, ließ sich anhand der Verzeichnisstruktur und von CODEOWNERS prüfen, zu welchem Team dieser Bereich gehört.

Die Rolle des Alert-Proxy

Damit diese Struktur in der Praxis funktioniert, war eine zwischengeschaltete Schicht nötig, die Alerts interpretiert und weiterleitet. Deshalb wurde zwischen Grafana, Slack und PagerDuty ein AWS-Lambda-basierter Proxy platziert.

Grafana wertet die Alert-Regeln aus und sendet Webhooks. Der Proxy nimmt diese Webhooks entgegen und interpretiert den Alert-Kontext wie category, severity, label, annotation und fingerprint. Anschließend entscheidet er, an welchen Slack-Kanal gesendet wird, welches PagerDuty Incident erstellt wird, wer erwähnt wird, welche Buttons angehängt werden, wie bestehende Slack-Threads aktualisiert werden und wie der Ack/Resolve-Lebenszyklus verwaltet wird.

Wenn also das Terraform-Modul und die Verzeichnisstruktur standardisierten, „wie Alerts definiert werden sollen“, dann übernahm der Proxy die Aufgabe, diese Definitionen so zu verbinden, dass sie im tatsächlichen Betriebsablauf auf dieselbe Weise erscheinen und funktionieren.

Dank des Proxy konnten Slack-Nachrichtenformat, Verantwortlichen-Mentions, PagerDuty-Integration, Slack-Thread-Updates und Ack/Resolve-Interaktionen zentral und konsistent verwaltet werden. Dadurch ließen sich spätere Erweiterungen wie grouped Alert, custom action button, die Anbindung von AI-Agenten oder ein gemeinsames Alert-Modell ebenfalls leichter ausbauen.


Was außerdem noch unbefriedigend war

Nach der ersten Verbesserung wurden die Alert-Definitionen als IaC verwaltet, und auch Slack-Nachrichten sowie Weiterleitungswege funktionierten nach konsistenten Regeln. Doch ein Alert-System war kein Werkzeug, das man einmal baut und dann als erledigt betrachtet. Nach fast einem Jahr Betrieb zeigte sich mit wachsender Zahl von Alerts eine Reihe neuer Probleme: wie mehrere Instanzen innerhalb desselben Alerts dargestellt werden sollten, wie sich wiederkehrende Alert-Definitionen verwalten lassen, wie man Menschen nach dem Lesen eines Alerts tatsächlich zu den nächsten Schritten führt und wie sich die Stabilität des Alert-Systems selbst absichern und überprüfen lässt.

Schwer überschaubar, wenn derselbe Alert gleichzeitig für mehrere Ziele auslöst

Weil sich Alerts leichter erstellen ließen, stieg ihre Zahl ganz natürlich. Besonders unangenehm war dabei der Fall, dass eine einzelne Alert-Regel gleichzeitig für mehrere Ziele auslöste.

In Grafana werden selbst bei derselben Regel unterschiedliche Label-Werte wie region, name, node, pod oder app jeweils als eigene Alert-Instanz behandelt. Wenn es zum Beispiel einen Pod-unhealthy-Alert gibt und mehrere Pods gleichzeitig in den unhealthy-Zustand geraten, entsteht für jeden Pod eine eigene Alert-Instanz.

Grafana hatte zwar bereits eine Alert-Grouping-Funktion, aber bloßes Gruppieren reichte nicht aus. Entscheidend war, den Zustand der gruppierten Alerts so darzustellen, dass Betreiber ihn leicht verstehen konnten. Wichtig war also, welche Ziele sich in der Gruppe befanden, welche noch firing waren, welche gerade resolved wurden, ob neue Ziele hinzugekommen waren und ob die Zustandsänderungen innerhalb derselben Gruppe in einem einzigen Verlauf zusammenliefen.

Immer mehr sich wiederholende Alert-Definitionen

Mit zunehmender Zahl an Alert-Definitionen stieß auch der Ansatz an Grenzen, YAML zu kopieren und nur kleine Änderungen vorzunehmen. Alerts wie SQS lag, CloudWatch error log, Pod OOM, ALB 5xx oder Lambda error/throttle wurden immer wieder erstellt, und anfangs reichte es, eine bestehende Datei zu kopieren und Namen, Query, Threshold und Labels anzupassen.

Mit wachsender Dateizahl wurde es jedoch schwieriger, gemeinsames Verhalten zu ändern, und es entstanden Unterschiede bei Dashboard-Links, der Zusammensetzung der Labels oder der Darstellung von Thresholds, obwohl die Alerts eigentlich denselben Zweck hatten. Daher wurde eine Struktur erforderlich, in der sich wiederkehrende Muster wiederverwenden lassen.

Auch nach dem Lesen eines Alerts war der Weg zur nächsten Aktion noch weit

Dass Slack-Nachrichten mit Buttons für Runbook, Dashboard, IaC und PagerDuty versehen wurden, half zwar, aber in der tatsächlichen Störungsbehebung reichten Links allein oft nicht aus. Besonders Runbooks waren klar nützlich, doch es war nicht einfach, für jeden Alert ein gutes Runbook bereitzustellen und es fortlaufend aktuell zu halten.

Zudem wiederholten sich in der realen Reaktion ständig ähnliche Untersuchungen, etwa Kubernetes-Logs prüfen, den Pod-Status prüfen, die Rollout-History prüfen, SQS- oder Lambda-Metriken prüfen oder Error-Logs nachsehen. Diese Arbeiten fanden größtenteils außerhalb der Slack-Nachricht statt, und die zuständige Person musste Labels und Werte aus dem Alert ablesen, in andere Tools übertragen und die Ergebnisse anschließend wieder im Slack-Thread teilen.

Letztlich ließ sich durch die erste Verbesserung ein Alert zwar besser lesen, doch Untersuchung und Reaktion blieben weiterhin zu großen Teilen außerhalb der Alert-Nachricht.

Mehr SPOFs im Monitoring-System

Mit der Neuordnung des Alert-Systems nahmen auch die Punkte zu, die zu einem SPOF werden konnten. Definition und Deployment der Alert-Regeln bündelten sich im Alerts-Repository und in Terraform, die Auswertung der Alert-Regeln lag bei Grafana, und Slack-Nachrichten, PagerDuty Incidents sowie der Ack/Resolve-Lebenszyklus wurden vom Proxy verwaltet.

Dass die Rollen klarer wurden, war eine gute Veränderung, doch zugleich stieg die Wahrscheinlichkeit, dass beim Ausfall einer dieser Stellen der gesamte Alert-Fluss beeinträchtigt würde. Noch schwieriger war, dass solche Ausfälle nach außen hin kaum sichtbar sein können. Wenn der Weg, über den Probleme anderer Systeme gemeldet werden, stillschweigend stoppt, kann es passieren, dass selbst bei einer echten Störung niemand etwas bemerkt.

Am Ende führte das zu der Frage: „Wer überwacht eigentlich das Monitoring-System?“


Die zweite Verbesserung

Mit der ersten Verbesserung stand zwar das Grundgerüst des Alert-Systems, doch je einfacher das Erstellen und Versenden von Alerts wurde, desto stärker verschoben sich auch die Probleme, die im Betrieb sichtbar wurden.

In der zweiten Verbesserung wurde auf vier Punkte fokussiert: Zustandsänderungen übersichtlich in einer Ansicht zusammenzuführen, wenn dieselbe Alert-Regel gleichzeitig für mehrere Ziele auslöst, wiederkehrende Alert-Definitionen als gemeinsame Muster wiederverwendbar zu machen, Runbooks zu ergänzen und wiederkehrende Untersuchungen sowie begrenzte Gegenmaßnahmen über Slack-Buttons zu verknüpfen und die Stabilität der Alert-Definitionen, ihrer Auswertung und der Weiterleitungswege, die zu einem SPOF werden können, zu messen und zu überprüfen.

Grouped Alerts richtig behandeln

Zunächst wurde die Darstellung von gruppierten Alerts verbessert. Wenn bei derselben Alert-Regel mehrere Instanzen gleichzeitig auslösen und jede als eigene Nachricht gesendet wird, wird der Slack-Channel unübersichtlich; fasst man dagegen alles nur zu einer Gruppe zusammen, übersieht man leicht, welche Ressourcen tatsächlich betroffen sind.

Der Kern war, zu gruppieren, ohne den Zustand innerhalb der Gruppe zu verlieren. In Slack wird ein gruppierter Alert als eine repräsentative Nachricht angezeigt, zusammen mit den aktuell betroffenen Zielen. Wenn neue Ziele hinzukommen oder bestehende gelöst werden, bleiben diese Änderungen im selben Thread erhalten. Wenn viele Zustandsänderungen auf einmal auftreten, werden mehrere Änderungen gebündelt angezeigt. Auch die PagerDuty-Seite wurde so angepasst, dass sie auf dasselbe Problem verweist wie der gruppierte Alert in Slack.

Dadurch lassen sich mehrere Alerts mit derselben Ursache in Slack letztlich als ein einziger Verlauf betrachten.

Wiederkehrende Alert-Definitionen reduzieren

Einfach zu kopieren und leicht zu verändern erhöht mit wachsender Zahl von Alerts sowohl den Wartungsaufwand als auch die Fehleranfälligkeit. Um das zu verringern, wurden global/templates und matrix ergänzt.

global/templates ist eine Funktion, mit der sich wiederkehrende Alert-Strukturen als gemeinsames Template definieren lassen, und matrix erzeugt aus demselben Alert mehrere Varianten über Kombinationen aus Region, Queue, Datasource und Service.

Wiederkehrende Muster wie SQS queue lag, CloudWatch error log, Pod OOM in mehreren Clustern, ALB 5xx, Lambda error/throttle sowie ECS memory/CPU/max-capacity wurden als Templates angelegt, und nur die variierenden Werte wie Queue-Name, Region, Cluster, Threshold oder Dashboard-Variablen werden in der Matrix eingetragen.

So konnten gemeinsame Nachrichtenstruktur, Buttons, die Behandlung von Runbook-/Dashboard-Links und die Handhabung von Datasources zentral angepasst werden. Gleichzeitig wurden Inkonsistenzen und Wartungskosten reduziert, die mit einer größeren Zahl von Alerts sonst zunehmen.

Direkt aus Slack-Nachrichten mit der Reaktion beginnen

Als Nächstes wurde der Funktionsumfang innerhalb der Slack-Nachricht erweitert. Runbook- und Dashboard-Links bleiben wichtig, aber wiederkehrende Abfragen oder begrenzte Gegenmaßnahmen, die sich ständig ähneln, sollten direkt in der Slack-Nachricht abgefangen werden.

Dafür wurde zusätzlich zu den bestehenden Buttons ein custom action button eingeführt. Wenn in message.actions der Alert-YAML ein Befehl definiert ist, erscheint er als Button in der Slack-Nachricht. Beim Klick führt der Proxy den Befehl über eine separate Lambda invocation aus und hinterlässt im selben Slack-Thread als Kommentar, wer welchen Button gedrückt hat und was das Ergebnis der Ausführung war.

Über diese Buttons können Aufgaben wie Log-Abfragen, das Prüfen des Kubernetes-Rollout-Status, ein rollout restart in eingeschränkten Situationen, die Ausführung einzelner Befehle oder auch die sequenzielle Ausführung mehrerer Befehle bereitgestellt werden.

Der wichtigste Punkt war Sicherheit. Wenn ein Button-Name auf ! endet, wird ein Slack confirm dialog angezeigt. Label-Werte wie ${labels.namespace} oder ${labels.pod} werden in Befehle eingesetzt, dabei aber mit shell quoting verarbeitet, um command injection zu verhindern. Für Aufgaben mit zusätzlichen Berechtigungen wird über actionRole eine IAM role assumed. Nicht erlaubte Rollen werden per fail-closed behandelt, und sowohl Webhooks als auch Slack-Interaktionen werden jeweils über Bearer token, HMAC-SHA256-Signatur und replay protection verifiziert.

Mit einem AI-Agenten integrieren

Auch der Prozess, nach Eingang eines Alerts die nötigen Informationen zusammenzutragen, sollte verkürzt werden. Deshalb wurde der interne AI-Agent abot in den Alert-Ablauf eingebunden.

Wenn in der Slack-Nachricht der abot-Button gedrückt wird, sammelt der Proxy den Alert-Namen, die Beschreibung, Labels, Werte, den IaC-Link sowie zusätzlichen Kontext, den der Nutzer im Modal eingibt, und sendet eine Analyseanfrage. abot arbeitet mit der OAuth-basierten Identität der Person, die den Button gedrückt hat, sodass bei Abfragen aus Grafana, AWS oder Kubernetes nur Informationen geholt werden, die diese Person tatsächlich sehen darf.

Das Analyseergebnis wird als Kommentar im selben Slack-Thread hinterlassen. Festgehalten wird dabei auch, welche Metriken und Logs geprüft wurden, welche Möglichkeiten zuerst verdächtig erscheinen und welche Hinweise sich für die RCA eignen könnten. Dadurch ließ sich die Zeit reduzieren, die sonst für das erneute Sammeln von Informationen über mehrere Systeme hinweg nötig wäre.

Das Monitoring-System selbst überwachen

In der zweiten Verbesserung wurde auch der Prozess selbst, in dem Alerts definiert, ausgewertet und zugestellt werden, zum Beobachtungsziel gemacht.

Zunächst wurden Betriebsmetriken des Proxys gesammelt. Erfasst wurden unter anderem die Zeit bis zum Ack, die Zeit bis zum Resolve, die Anzahl aktuell aktiver Alerts, wie lange Alerts offen bleiben und wie oft derselbe Alert erneut ausgelöst wurde. Zusätzlich wurde ein Watchdog ergänzt, der erkennt, wenn Lambda sich einem Timeout nähert. Falls der Proxy während der Verarbeitung fehlschlägt, werden ein vollständiger Stack Trace und die ursprüngliche Event-Payload mitprotokolliert.

Allerdings hat ein Verfahren, bei dem der Proxy selbst meldet, seine Grenzen. Wenn der Proxy stirbt, bevor er überhaupt diese Benachrichtigung senden kann, kann ein Alert, der eigentlich hätte verschickt werden müssen, komplett ausfallen.

Deshalb wurden außerhalb des Proxys Erkennungsmechanismen eingerichtet, die sich auf unterschiedliche Systeme stützen. Einer davon basiert auf Grafana: Metriken, die der Proxy sendet, werden dort als Alerts in der Monitoring-Domäne ausgewertet, um Anomalien sichtbar zu machen. Da Grafana und VictoriaMetrics jedoch auf demselben EKS laufen, kann nichts erkannt werden, wenn EKS oder Grafana komplett ausfallen.

Der andere Mechanismus war ein deadman switch. Wenn Grafana normal läuft, sendet es /api/health als Heartbeat, und dieser Heartbeat wird von einem von EKS unabhängigen CloudWatch empfangen. Ein CloudWatch alarm beurteilt einen ausgefallenen oder fehlenden Heartbeat als Störung und alarmiert in diesem Fall direkt PagerDuty und Slack, ohne über Grafana oder den Proxy zu gehen.

Damit liegen das erkennende und das erkannte System auf unterschiedlicher Infrastruktur. Solange also nicht EKS und CloudWatch gleichzeitig ausfallen, kann ein Ausfall des Monitoring-Systems erkannt werden.


Weitere Verbesserungsaufgaben

Die zweite Verbesserungsrunde ist abgeschlossen, aber es gibt weiterhin Punkte, die noch verbessert werden müssen.

Die gesammelten Betriebsmetriken richtig nutzen

Da der Proxy Betriebsmetriken der Alerts sammelt, lassen sich Fragen inzwischen datenbasiert beantworten, etwa welche Alerts in welchem Channel wie häufig ausgelöst werden, ob bestimmte Verantwortliche oder Teams übermäßig viele Alerts erhalten oder ob es Alerts gibt, die ohne jede Interaktion nur firing und auto resolve wiederholen.

Doch Daten sehen zu können und darauf basierend Alerts tatsächlich zu verfeinern, sind zwei verschiedene Dinge. Bisher wurden Anpassungen wie das Tuning von Thresholds, das Zusammenfassen ähnlicher Alerts, das Entfernen unnötiger Alerts, das Reduzieren von noisy alerts oder Verbesserungen mit dem Ziel, Erkennungs- und Lösungszeiten wirklich zu verkürzen, noch nicht ernsthaft angegangen.

Alert-IaC verbessern

Derzeit werden Alert-Definitionen zwar per CI/CD aus dem Alerts-Repository ausgerollt, hängen aber noch von der Ressource grafana_rule_group des Grafana Terraform provider ab. Das Problem ist, dass in PRs selbst bei einer Änderung an nur einer Regel oft die gesamte Rule Group als verändert erscheint, wodurch Diffs schwer lesbar werden. Außerdem gilt interval_seconds auf Ebene der Rule Group, sodass für unterschiedliche Auswertungsintervalle pro Alert die Groups kleinteilig aufgespalten werden müssen.

In Grafana gibt es inzwischen eine neue Alerting-API, mit der sich Alert-Regeln wie Kubernetes-Ressourcen behandeln lassen, und auch im Terraform provider wurde die Ressource grafana_apps_rules_alertrule_v0alpha1 ergänzt. Da sie noch alpha ist, wird eine sofortige Einführung vorerst zurückgestellt, aber sobald sie stable wird, soll ein Wechsel vom bisherigen grafana_rule_group geprüft werden.

Die Erwartungen sind klar. Rule Group und Rule getrennt definieren, einen sauberen Diff erhalten, in dem bei Änderungen an nur einer Rule auch nur diese Änderung klar sichtbar wird, das Auswertungsintervall pro Rule fein granular steuern und Monitoring-Ressourcen effizienter nutzen.


Zum Schluss

Das anfängliche Ziel war einfach. Alerts leichter erstellen, sie beim Eingang auf einen Blick verständlich machen und klar festlegen, wer dafür verantwortlich ist.

In der ersten Verbesserungsrunde wurden die Alert-Definitionen als IaC zusammengeführt, die Slack-Nachrichten und Zustellpfade standardisiert, Verantwortlichen-Mentions mit CODEOWNERS verknüpft und das Lifecycle-Management für Slack/PagerDuty über den Proxy geordnet.

Die Probleme, die sich im laufenden Betrieb gezeigt haben, wurden in der zweiten Verbesserungsrunde angegangen. Alerts, die aus derselben Regel in großer Zahl ausgelöst werden, werden gebündelt angezeigt, wiederkehrende Definitionen wurden mit Template und Matrix reduziert, in Slack-Nachrichten kann direkt mit Untersuchung und Gegenmaßnahmen begonnen werden, und es wurde ein Mechanismus geschaffen, der erkennt, wenn das Monitoring-System selbst ausfällt.

Dadurch ist das Erstellen, Versenden und Bearbeiten von Alerts einfacher geworden als zuvor.

Allerdings ist es nicht dasselbe, Daten sichtbar zu machen und den Betrieb auf Basis dieser Daten tatsächlich zu verbessern. Wenn es bisher darum ging, das Alert-System zu standardisieren und messbar zu machen, bleibt nun die Aufgabe, diese Kennzahlen anzusehen und sie tatsächlich zu reduzieren und weiter zu verfeinern.


Dieser Artikel enthält aus Platzgründen einige Inhalte nicht. Wenn Sie mehr Details interessieren, empfehlen wir, auch den Originalartikel zu lesen.

Noch keine Kommentare.

Noch keine Kommentare.