# Ein Incident-Runbook für ein Team ohne Bereitschaftsdienst

Große Unternehmen haben On-Call-Rotationen, Incident Commander, Schweregradmatrizen und ein passendes Tooling-Budget. Ein Dreierteam hat einen Gruppenchat und wen auch immer, der gerade wach ist. Dieses Team hat trotzdem Vorfälle, und sie passieren trotzdem um 02:40, und die Frage ist nicht, ob man einen Prozess braucht, sondern wie wenig Prozess den größten Teil des Werts einfängt. Das hier ist, was wir für ein Dreierteam aufgeschrieben haben, das eine Zahlungsplattform betreibt, was wir während eines Vorfalls lesen und was wir danach schreiben. Das Ganze passt auf zwei Seiten, mit Absicht.

## Was wir vorher entscheiden, damit wir es nicht um 02:40 entscheiden

Die schlechtesten Incident-Entscheidungen sind die, die unter Druck von jemandem getroffen werden, der gerade geweckt wurde. Also werden die wenigen Entscheidungen, die zählen, im Voraus getroffen und dort aufgeschrieben, wohin der Alarm verlinkt.

**Schweregrad, in drei Zeilen.**

| Stufe | Definition | Reaktion |
|---|---|---|
| S1 | Nutzer können nicht tun, wofür sie zahlen: Checkout scheitert, Login scheitert, Daten sind falsch | Jetzt. Wer es sieht, handelt. Notfalls jemanden wecken. |
| S2 | Beeinträchtigt: langsam, ein Feature kaputt, Fehler für einige Nutzer | Tagsüber innerhalb einer Stunde, nachts am nächsten Morgen |
| S3 | Intern: ein Job ist fehlgeschlagen, ein Dashboard ist falsch, etwas Nicht-Nutzersichtbares | Nächster Arbeitstag |

Der Sinn der Tabelle ist nicht Präzision. Es ist, dass „ist das ein S1?“ eine Einzeilen-Antwort hat, und die Antwort entscheidet, ob jemand angerufen wird.

**Wer diese Woche Ersthelfer ist.** Keine Rotation mit Tooling; ein Name im Kanal-Thema, montags gewechselt. Diese Person hat das Telefon an und schaut zuerst. Alle anderen sind zweite. Es ist Best-Effort, und wir sagen das auch, und es war kein einziges Mal ein Problem, weil die Alternative, dass niemand sicher ist, wer schaut, schlimmer ist als jede unvollkommene Antwort.

**Die erste Regel: zurückrollen, bevor man debuggt.** Wenn in den letzten Stunden ein Deploy stattfand und das Symptom danach begann, ist [das Rollback eine Tag-Änderung](/de/blog/same-tag-deploy-and-the-deploy-script-without-ci) und dauert vier Minuten. Das zuerst. Debuggen kommt danach, in Staging, wenn der Vorfall vorbei ist. Wie oft das Rollback die falsche Entscheidung war: null. Wie oft Debuggen zuerst eine zusätzliche Stunde Ausfall gekostet hat: dreimal, alle bevor wir die Regel aufgeschrieben haben.

## Die Runbook-Seite pro Alarm

Jeder Alarm, der wecken kann, verlinkt auf eine Seite, und jede Seite hat dieselben fünf Überschriften. Hier die echte für den Fehlerraten-Alarm, leicht geschwärzt.

<div class="article-figure">
<svg viewBox="0 0 900 300" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Gerüst einer Runbook-Seite mit fünf Abschnitten: Was dieser Alarm bedeutet, in einem Satz; Zuerst schauen, drei Befehle oder Links; Rollback, der genaue Befehl und wann; Bekannte Ursachen, eine kurze Liste vergangener Vorfälle mit dem, was sie behoben hat; Wen informieren, der Kanal und der Statusseiten-Schalter. Ein Hinweis sagt, dass jeder Alarm auf eine so geformte Seite verlinkt.">
<g font-family="Inter,system-ui,sans-serif" font-size="12">
<rect x="60" y="20" width="780" height="260" rx="14" fill="#151b2e" stroke="#2a3150" stroke-width="1.5"/>
<text x="80" y="48" fill="#f1f3ff" font-size="14" font-weight="700">ApiErrorBudgetBurn · Runbook</text>
<text x="80" y="82" fill="#4fffb0" font-weight="700">Was es bedeutet</text><text x="260" y="82" fill="#f1f3ff">die API liefert bei mehr als 1,4 % der Requests 5xx, auf mindestens einer Cloud</text>
<text x="80" y="112" fill="#4fffb0" font-weight="700">Zuerst schauen</text><text x="260" y="112" fill="#f1f3ff">1 · Grafana: Fehlerrate nach Route und cloud_provider (Link)</text>
<text x="260" y="130" fill="#f1f3ff">2 · Loki: {service_name="api"} | json | level="error" (Link, letzte 15 Min)</text>
<text x="260" y="148" fill="#f1f3ff">3 · letzter Deploy: ./scripts/deploy.sh --env prod --history</text>
<text x="80" y="178" fill="#ffd166" font-weight="700">Rollback</text><text x="260" y="178" fill="#f1f3ff">bei Deploy in den letzten 4 h: ./scripts/deploy.sh --env prod --rollback --yes · 4 Min</text>
<text x="80" y="208" fill="#4fffb0" font-weight="700">Bekannte Ursachen</text><text x="260" y="208" fill="#f1f3ff">2026-03 · Billing Connection Resets → Aurora-Scale-in, behoben durch Pool-Idle-Timeout</text>
<text x="260" y="226" fill="#f1f3ff">2026-05 · 504 nach Deploy → Warm-up, behoben durch HTTP-Health-Check</text>
<text x="80" y="256" fill="#ff6b8a" font-weight="700">Wen informieren</text><text x="260" y="256" fill="#f1f3ff">#incidents erste Zeile innerhalb 5 Min · Statusseite: ./scripts/status.sh degraded</text>
</g>
</svg>
</div>

Fünf Überschriften. *Was es bedeutet* ist ein Satz, weil der Alarmname um 02:40 nie reicht. *Zuerst schauen* sind genau drei Dinge, jedes ein Link oder ein Befehl, in der Reihenfolge, die die Ursache am schnellsten findet; bei mehr als drei überspringen Leute die Liste. *Rollback* ist der genaue Befehl und die Bedingung dafür. *Bekannte Ursachen* ist das gesammelte Gedächtnis des Teams: jeder vergangene Vorfall zu diesem Alarm, mit dem, was ihn behoben hat, je eine Zeile. *Wen informieren* ist der Kanal und die Statusseite.

Der Abschnitt *Bekannte Ursachen* ist der, der wächst, und der, der sich auszahlt. Die Hälfte unserer Vorfälle sind Wiederholungen von etwas in dieser Liste, und für die ist die Zeit von Alarm bis Fix die Zeit, die das Lesen der Zeile braucht.

## Was wir um 02:40 lesen

Den Alarm. Er enthält den Runbook-Link, weil [die Alarmregel eine Annotation](/de/blog/alerts-that-do-not-know-which-cloud) mit der URL trägt. Dann die Runbook-Seite. Dann die drei Links unter *Zuerst schauen*, in Reihenfolge. Das war's. Es gibt keine Incident-Commander-Rolle zu vergeben und keine Bridge zu öffnen, weil wir drei sind und im selben Chat.

Was wir bewusst *nicht* lesen: die Architekturdokumente, die Service-Health-Seite der Cloud-Konsole, den letzten Monat an Commits. Wenn die drei Links es nicht finden und es einen Deploy gab, zurückrollen. Gab es keinen Deploy, ist der vierte Schritt der Trace: [einen fehlgeschlagenen Request finden und seinen Trace öffnen](/de/blog/your-traces-should-not-know-which-cloud), der meist auf den Dienst zeigt, der tatsächlich kaputt ist, statt auf den, der Fehler meldet.

## Kommunikation, mit Vorlagen

Zwei Zielgruppen, zwei Vorlagen, beide im Voraus geschrieben, damit niemand während eines Ausfalls Prosa verfasst.

**Intern, in `#incidents`, innerhalb von fünf Minuten nach Bestätigung:**

> S1 · API-Fehler ~3 % seit 02:31 · schaue · letzter Deploy gestern 21:40 · rolle zuerst zurück

Eine Zeile. Schweregrad, Symptom, seit wann, was Sie tun. Die Zeile alle fünfzehn Minuten aktualisieren, oder wenn sich etwas ändert, auch wenn das Update „schaue noch“ lautet. Schweigen ist das, was Leute nicht ertragen.

**Extern, auf der Statusseite, nur bei S1:**

> Wir sehen seit 02:31 UTC erhöhte Fehler im Checkout. Wir haben die Ursache identifiziert und rollen einen Fix aus. Nächstes Update in 30 Minuten.

Die Statusseite ist eine statische HTML-Datei in einem S3-Bucket hinter CloudFront, auf einer separaten Domain, mit einem Skript, das sie zwischen „operational“, „degraded“ und „outage“ umschaltet und eine Nachricht anhängt. Sie kostet nichts, hängt von nichts ab, was Teil des Vorfalls sein könnte, und braucht einen Befehl zum Aktualisieren. Ein gehostetes Statusseiten-Produkt ist auch in Ordnung; die wichtigen Eigenschaften sind, dass sie außerhalb des Explosionsradius liegt und das Aktualisieren Sekunden dauert.

<div class="article-figure">
<svg viewBox="0 0 900 200" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Die ersten fünfzehn Minuten eines Vorfalls als Ablauf. Minute 0: Alarm mit Runbook-Link. Minute 2: bestätigen, eine Zeile im Incidents-Kanal. Minute 3 bis 8: zuerst schauen, drei Links. Entscheidung: gab es in den letzten vier Stunden einen Deploy? Ja: zurückrollen, vier Minuten, dann verifizieren. Nein: einen fehlgeschlagenen Request finden, seinen Trace öffnen, dann vorwärts fixen. Minute 15: den Kanal aktualisieren, und die Statusseite bei S1.">
<defs><marker id="arrI2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0 L10,5 L0,10 z" fill="#4fffb0"/></marker></defs>
<g font-family="Inter,system-ui,sans-serif" font-size="11">
<rect x="15" y="60" width="120" height="56" rx="10" fill="#151b2e" stroke="#ff6b8a" stroke-width="1.5"/><text x="75" y="84" text-anchor="middle" fill="#f1f3ff" font-weight="700">0 · Alarm</text><text x="75" y="102" text-anchor="middle" fill="#9aa3c7">mit Runbook-Link</text>
<line x1="137" y1="88" x2="163" y2="88" stroke="#4fffb0" stroke-width="1.5" marker-end="url(#arrI2)"/>
<rect x="165" y="60" width="130" height="56" rx="10" fill="#151b2e" stroke="#7b8cff" stroke-width="1.5"/><text x="230" y="84" text-anchor="middle" fill="#f1f3ff" font-weight="700">2 · eine Zeile</text><text x="230" y="102" text-anchor="middle" fill="#9aa3c7">in #incidents</text>
<line x1="297" y1="88" x2="323" y2="88" stroke="#4fffb0" stroke-width="1.5" marker-end="url(#arrI2)"/>
<rect x="325" y="60" width="130" height="56" rx="10" fill="#151b2e" stroke="#7b8cff" stroke-width="1.5"/><text x="390" y="84" text-anchor="middle" fill="#f1f3ff" font-weight="700">3–8 · zuerst schauen</text><text x="390" y="102" text-anchor="middle" fill="#9aa3c7">drei Links, in Reihenfolge</text>
<line x1="457" y1="88" x2="483" y2="88" stroke="#4fffb0" stroke-width="1.5" marker-end="url(#arrI2)"/>
<rect x="485" y="50" width="140" height="76" rx="10" fill="#151b2e" stroke="#ffd166" stroke-width="1.5"/><text x="555" y="78" text-anchor="middle" fill="#ffd166" font-weight="700">Deploy in den</text><text x="555" y="96" text-anchor="middle" fill="#ffd166" font-weight="700">letzten 4 h?</text>
<line x1="627" y1="70" x2="713" y2="50" stroke="#4fffb0" stroke-width="1.5" marker-end="url(#arrI2)"/><text x="668" y="52" text-anchor="middle" fill="#9aa3c7">ja</text>
<line x1="627" y1="106" x2="713" y2="126" stroke="#4fffb0" stroke-width="1.5" marker-end="url(#arrI2)"/><text x="668" y="130" text-anchor="middle" fill="#9aa3c7">nein</text>
<rect x="715" y="22" width="170" height="52" rx="10" fill="#151b2e" stroke="#4fffb0" stroke-width="1.5"/><text x="800" y="44" text-anchor="middle" fill="#4fffb0" font-weight="700">zurückrollen · 4 Min</text><text x="800" y="62" text-anchor="middle" fill="#9aa3c7">später debuggen, in Staging</text>
<rect x="715" y="102" width="170" height="52" rx="10" fill="#151b2e" stroke="#7b8cff" stroke-width="1.5"/><text x="800" y="124" text-anchor="middle" fill="#f1f3ff" font-weight="700">ein fehlgeschlagener Request</text><text x="800" y="142" text-anchor="middle" fill="#9aa3c7">Trace öffnen · vorwärts fixen</text>
<text x="450" y="184" text-anchor="middle" fill="#9aa3c7">Minute 15: Kanalzeile aktualisieren · Statusseite bei S1 · dann alle 15 Minuten bis zur Lösung</text>
</g>
</svg>
</div>

## Was wir danach schreiben

Eine Seite, innerhalb von zwei Arbeitstagen, per Konstruktion ohne Schuldzuweisung, weil sie drei Fragen hat und keine davon „wer“ ist:

1. **Was passiert ist, als Zeitstrahl.** Alarm um 02:31, bestätigt 02:34, zurückgerollt 02:41, Fehlerrate normal 02:45, Ursache am nächsten Tag um 10:20 identifiziert. Zeiten aus dem Kanal, nicht aus dem Gedächtnis.
2. **Warum es passiert ist, und warum es nicht früher erkannt wurde.** Die zweite Hälfte ist die nützliche. „Die Migration hat die Tabelle gesperrt“ ist die Ursache; „wir stoppen Migrationen nicht gegen einen Staging-Snapshot“ ist die Lücke.
3. **Was wir ändern.** Höchstens drei Punkte, jeder mit Verantwortlichem und Woche. Der mit Abstand häufigste Punkt ist eine neue Zeile unter *Bekannte Ursachen* in einem Runbook. Der zweithäufigste ist ein neuer Alarm. Der dritte ist eine Änderung an einer Checkliste.

Die Post-Incident-Notiz kommt ins Repo, neben die Runbooks, in einen Ordner mit dem Datum. Nach achtzehn Monaten sind es vierzehn, und sie der Reihe nach zu lesen ist das beste Onboarding-Dokument, das wir haben.

## Was wir nicht tun, und warum das in Ordnung ist

Kein formaler Bereitschaftsdienst mit Eskalationsrichtlinien: drei Leute, ein eingeschaltetes Telefon, Best-Effort, klar gesagt. Kein Incident Commander: der Ersthelfer ist es, und wenn es groß ist, sagt er es, und jemand anderes kommt dazu. Kein Schweregrad jenseits von drei Stufen. Kein War Room. Kein *Meeting* zur schuldfreien Nachbesprechung; die Notiz reicht, und sie wird im nächsten regulären Sync besprochen.

All das ist das Richtige für eine Engineering-Organisation mit fünfzig Leuten. Für drei ist es Zeremonie, und Zeremonie um 02:40 ist das, was Leute dazu bringt, das S2 nicht zu melden, das bis zum Morgen ein S1 gewesen wäre.

Der Prozess passt auf zwei Seiten: die Schweregradtabelle, der Name des Ersthelfers, die Rollback-Regel, die Runbook-Vorlage, die zwei Nachrichtenvorlagen, die drei Post-Incident-Fragen. Es hat einen Nachmittag gedauert, sie zu schreiben, und sie wurden im Ernstfall vierzehn Mal gelesen.

Wenn Sie die zwei Seiten als Ausgangspunkt möchten, an Ihren Stack angepasst, [schreiben wir sie mit Ihnen](/contact).
