Seite 14 im Runbook sagt: „Dienst neu starten.“ Um 03:12 war Seite 14 falsch. Der Dienst, den ich neu gestartet habe, war nicht der Dienst, der das Problem hatte, und der Hostname in der Anleitung existierte seit einem halben Jahr nicht mehr. Ich habe 40 Minuten damit verbracht, ein System zu reparieren, das nicht kaputt war, und in dieser Zeit lief der eigentliche Fehler weiter.

03:12 – Der Alarm

Der Alarm hieß DiskUsageHigh und kam zum dritten Mal in dieser Nacht. Ich hatte ihn beim ersten Mal um 02:31 gesehen, mir die Metrik angeschaut, gesehen, dass sie bei 91 Prozent lag und langsam stieg, und beschlossen, dass das nicht dringend ist. Beim zweiten Mal um 02:58 habe ich das Gleiche gedacht. Beim dritten Mal habe ich mich angezogen, weil ich wusste, dass ich sonst nicht mehr schlafe.

Das war der erste Fehler, und er lag nicht bei mir, sondern in der Regel: kein for. Der Alarm hat gefeuert, sobald der Wert über der Schwelle lag, und bei einer Metrik, die alle 30 Sekunden schwankt, heißt das: Seiten flattern, und wer gerufen wird, lernt, sie zu ignorieren. Ich habe in dieser Nacht drei Seiten bekommen, von denen zwei niemand hätte schicken müssen.

03:20 – Seite 14

Foto eines ausgedruckten Runbooks auf einem Schreibtisch bei Nacht, Seite 14 mit einem rot markierten Befehl, daneben ein Laptop mit einem Terminalfenster
Mein Ausdruck von Seite 14, inzwischen mit Bleistift korrigiert. Der Befehl in der Mitte lief auf einem Host, den es nicht mehr gab.

Der Runbook-Eintrag war zwei Jahre alt und bestand aus vier Schritten: SSH auf worker-03, systemctl status ingest prüfen, systemctl restart ingest, im Dashboard schauen, ob die Queue sinkt. Schritt eins hat mich fünf Minuten gekostet, weil der Hostname nicht mehr auflösbar war – die Worker waren in der Zwischenzeit in Container gewandert und hießen anders. Schritt zwei hat gezeigt: Der Dienst lief, die Queue war normal. Ich habe ihn trotzdem neu gestartet, weil ich dachte, ich hätte etwas übersehen, und dann zehn Minuten gewartet, ob es besser wird.

Es wurde nicht besser, weil das Problem woanders lag: Auf einem der Datenbankknoten war die Platte voll, und zwar mit WAL-Dateien, die nicht archiviert wurden, weil ein Cronjob seit dem letzten Deploy still fehlschlug. Der Alarm hatte recht, die Anleitung zeigte auf den falschen Ort, und ich hatte keine Möglichkeit, das in der Anleitung zu sehen, weil dort kein Datum stand und kein Hinweis, wofür der Schritt gedacht ist.

Der Alarm, der zu oft kam

Am nächsten Tag habe ich die Regel neu geschrieben. Der wichtigste Teil ist nicht die Schwelle, sondern for: Fünf Minuten über der Schwelle, bevor jemand geweckt wird, außer bei einem Wert, der sofort kritisch ist. Dazu ein Link auf das Runbook direkt in der Alarmnachricht, weil ich um 03:12 nicht danach suche, sondern klicke.

- alert: DiskUsageHigh
  expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.15
  for: 5m
  labels:
    severity: page
  annotations:
    summary: "Platte auf {{ $labels.instance }} unter 15 Prozent frei"
    runbook: "runbooks/disk-usage.md#schritte"
    dashboard: "dashboards/node-disk"

Die zweite Änderung war unangenehmer: Ich habe alle Runbook-Einträge durchgesehen und bei jedem eine Zeile ergänzt, wann er zuletzt geprüft wurde und für welchen Fall er gedacht ist. 31 Einträge, davon 9 älter als ein Jahr. Zwei verwiesen auf Hosts, die es nicht mehr gab, einer auf eine Datenbank, die umbenannt worden war. Das war eine Stunde Arbeit an einem Samstag und hätte in dieser Nacht 30 Minuten gekostet.

Die dritte Änderung war ein Test: ein Skript, das jede im Alarm referenzierte Runbook-Datei öffnet und prüft, ob die Überschrift existiert. Es läuft wöchentlich und schickt eine Nachricht, wenn ein Link ins Leere zeigt. Das Skript ist zwölf Zeilen lang und hat seitdem zwei kaputte Links gefunden. Ein Runbook, das niemand testet, ist eine Behauptung über die Vergangenheit.

Was ich über On-Call gelernt habe

  • Ein Alarm ohne for ist kein Alarm, sondern ein Geräusch. Wer dreimal pro Nacht geweckt wird, glaubt beim vierten Mal nicht mehr daran.
  • Ein Runbook braucht ein Datum und einen Zweck. Ohne beides kann ich nicht unterscheiden, ob der Schritt falsch ist oder nur alt.
  • Der erste Schritt im Runbook sollte „prüfen, ob das wirklich das Problem ist“ heißen, nicht „neu starten“.
  • Wer um 3 Uhr nachts gerufen wird, klickt und liest nicht. Alles, was ich in der Nacht brauche, muss in der Alarmnachricht stehen oder einen Klick entfernt sein.

Der eigentliche Fehler in dieser Nacht war nicht der volle Datenträger. Der war ein normales Betriebsproblem mit einer bekannten Lösung. Der Fehler war, dass die Anleitung, die mir helfen sollte, mich 40 Minuten in die falsche Richtung geschickt hat, und dass ich ihr gefolgt bin, weil sie da war und ich müde war.

Fazit

Ein Runbook ist Code, der nicht kompiliert wird: Niemand merkt, wenn er falsch ist. Seit dieser Nacht steht bei jedem Eintrag ein Datum, und der Alarm trägt den Link. Das hat mich eine Stunde am Samstag gekostet und wahrscheinlich eine Nacht im Januar gespart. Wann hast du das letzte Mal in deine Alarmierungsanleitung geschaut, ohne dass ein Alarm dich dazu gezwungen hat?