Wenn die Rettung den Ausfall verursacht
Wenn die Rettung den Ausfall verursacht
Inhaltsverzeichnis
Der Alarm, der das falsche Problem meldete
Es beginnt an einem Sonntagmorgen mit einer Mail: „Update fehlgeschlagen". Nicht zum ersten Mal — dieser Alarm kommt seit Wochen, immer sonntags, und er scheint immer denselben Dienst zu betreffen. Man gewöhnt sich das Wegklicken an. Ein gefährlicher Reflex, aber ein menschlicher.
Der Aufbau dahinter ist verbreitet und eigentlich vernünftig: eine wöchentliche Update-Automatik holt für jeden Dienst-Stack die neuen Images, startet ihn neu und prüft danach mit einem Health-Check, ob er wieder läuft. Scheitert der Check, gilt der Stack als fehlgeschlagen. So weit die Idee.
Das Tückische: Der Dienst, der da wöchentlich als „schuldig" im Report auftauchte, war nie die Ursache. Er stand nur zufällig an erster Stelle und riss alles Nachfolgende mit sich. Die eigentliche Geschichte liegt eine Ebene tiefer — und sie endet an diesem Sonntag nicht mit einem Fehlalarm, sondern mit einem echten Totalausfall aller Web-Dienste.
„Failed" heißt nicht „kaputt"
Der Health-Check nach einem Neustart war simpel: ein HTTPS-Aufruf des Dienstes über den Reverse-Proxy. Kommt eine gültige Antwort, ist alles gut. Klingt richtig — und ist doch die Wurzel des Problems.
Denn wenn ein Container neu erstellt wird, bekommt er eine neue Adresse, und der Reverse-Proxy braucht einen Moment, bis er das frische Backend wieder kennt und dorthin routet. Dieser Moment ist nicht eine Sekunde, sondern gut und gern zwei Minuten oder mehr. In dieser Zeitspanne antwortet der Proxy auf den Testaufruf mit einem kurzen Fehler — nicht, weil der Dienst kaputt ist, sondern weil die Route noch nicht wieder steht.
Das Ergebnis: Der Check meldet drei von vier Teilprüfungen als grün und die vierte — ausgerechnet die über den Proxy — als rot. Der Stack gilt als „fehlgeschlagen". In Wahrheit läuft der Dienst längst; der Test ist nur ungeduldiger als die Realität. Das passiert nicht bei einem Dienst, sondern systematisch bei fast allen: Am Ende steht im Report „8 fehlgeschlagen, 0 erfolgreich" — obwohl jedes einzelne Update sauber eingespielt wurde.
Der Rollback als Brandbeschleuniger
Für unkritische Dienste ist ein falsches „failed" nur Rauschen im Report. Für die als kritisch markierten Stacks aber war etwas anderes scharf geschaltet: ein automatischer Rollback. Die Logik: Wenn ein wichtiger Dienst den Health-Check reißt, stelle sofort den vorherigen Zustand wieder her. Auf dem Papier ein Sicherheitsnetz.
Nur war dieses Netz selbst durchlöchert. Der Rollback stoppte und entfernte den Container — und brachte ihn dann nicht verlässlich wieder hoch. Bei einem beliebigen Hintergrunddienst wäre das ein stiller Defekt geblieben. Beim Reverse-Proxy war es fatal: Der Proxy ist das Tor, durch das der gesamte verschlüsselte Web-Verkehr hereinkommt. War er weg, gab es keine Weiterleitung mehr — und damit von außen keinen einzigen erreichbaren Web-Dienst.
Man muss sich die Ironie auf der Zunge zergehen lassen: Der Health-Check hatte einen Ausfall nur fälschlich gemeldet. Der Automatismus, der diesen vermeintlichen Ausfall beheben sollte, hat ihn dann tatsächlich herbeigeführt. Die Rettung war die Katastrophe.
Das Glück im Unglück: fail-closed
Bei aller Härte hatte der Vorfall eine beruhigende Eigenschaft. Als der Proxy verschwand, lauschte nichts mehr auf dem verschlüsselten Port. Die Dienste dahinter waren unerreichbar — aber sie waren nicht plötzlich ungeschützt. Es wurde nichts an der Anmeldung vorbei ausgeliefert; die Backends liegen in internen Netzen, die von außen ohnehin nicht sichtbar sind.
Das ist der entscheidende Unterschied, der zwischen „ärgerlich" und „gefährlich" liegt: fail-closed gegen fail-open. Fällt ein Torwächter aus und die Folge ist „Tür zu" (fail-closed), hat man ein Verfügbarkeitsproblem — unschön, aber sicher. Wäre die Folge „Tür offen, ohne Kontrolle" (fail-open), hätte man ein Sicherheitsproblem. Ein Ausfall lässt sich in Minuten reparieren; eine unbemerkt offene Tür kann man nicht zurückholen.
Was die richtige Reparatur ist
Den Proxy wieder hochzuziehen war die Sache von einem Kommando — der eigentliche Wert liegt darin, die zwei Ursachen zu beheben, nicht nur das Symptom.
Erstens: Der Health-Check muss die Realität abbilden. Ein nackter Aufruf direkt nach dem Neustart fragt zum falschen Zeitpunkt. Besser ist, auf die tatsächliche Bereitschaft zu warten: den Routing-Status des Proxys abfragen, statt blind eine Antwort zu erwarten — oder mit einem Wiederholungsfenster prüfen, das zur echten Startzeit des Dienstes passt (manche Stacks brauchen mehrere Minuten, bis alle Teile stehen). Ein Check, der „noch nicht bereit" von „kaputt" unterscheiden kann, erzeugt keine Fehlalarme mehr.
Zweitens: Ein Rollback darf nie destruktiv ohne Netz sein. Niemals „stoppen und entfernen", ohne anschließend zu beweisen, dass der Dienst wirklich wieder läuft. Wiederherstellung heißt: neu erstellen und verifizieren — und wenn die Verifikation scheitert, laut alarmieren, statt die Trümmer liegen zu lassen. Schematisch der Unterschied:
# Anti-Pattern: löscht zuerst, hofft danach
stop(dienst)
remove(dienst)
start(alte_version) # scheitert das? Dann ist der Dienst weg.
# Besser: erst wiederherstellen, dann beweisen
recreate(dienst, alte_version)
if not is_really_serving(dienst):
alarmiere("Rollback unvollständig") # nichts stillschweigend zerstört
Ein defekter Wächter gehört abgeschaltet
Die Sofortmaßnahme war kontraintuitiv, aber richtig: den automatischen Rollback deaktivieren, bis er repariert ist. Ein Sicherheitsmechanismus, der auf Fehlalarme hin feuert und dabei funktionierende Dienste zerstört, ist nicht „besser als nichts" — er ist schlechter als nichts. Ihn abzuschalten entfernt eine aktive Schadensquelle.
Was als Netz bleibt, ist eine unabhängige Endkontrolle: eine Prüfung ganz am Schluss des Laufs, die nur die wirklich harten Invarianten testet — kommt der Verkehr von außen tatsächlich an? — und die über einen Kanal alarmiert, der nicht vom gerade ausgefallenen Dienst abhängt. Genau diese Endkontrolle hatte den Ausfall korrekt erkannt und benannt. Ihr einziger Makel: Sie lief nach dem zerstörerischen Rollback. Sie konnte den Schaden melden, aber nicht mehr verhindern — weil er davor passierte.
Was man mitnimmt
- „Failed" ist nicht „kaputt". Ein Health-Check, der der Realität vorauseilt, misst Timing, nicht Gesundheit — und erzeugt Fehlalarme, auf die man sich das Wegklicken angewöhnt.
- Rettungsautomatik muss non-destruktiv sein. Wer löscht, bevor er die Wiederherstellung beweist, baut einen Brandbeschleuniger, keinen Feuerlöscher.
- Frag: fail-closed oder fail-open? Im Fehlerfall zu ist ärgerlich, im Fehlerfall offen ist gefährlich. Der Unterschied entscheidet, ob ein Bug ein Ausfall oder ein Einbruch wird.
- Ein defekter Wächter gehört abgeschaltet, nicht toleriert — bis er nachweislich wieder heilt statt schadet.
- Kontrolliere vor dem Punkt ohne Wiederkehr, über einen Kanal, der nicht am kaputten Dienst hängt.
Die verlässlichsten Systeme sind nicht die mit den meisten Automatismen, sondern die, deren Automatismen im Zweifel die Hände hebt statt zuzugreifen. „Ich bin unsicher, also melde ich und fasse nichts an" ist fast immer sicherer als ein beherzter, aber ungeprüfter Rettungsversuch. An diesem Sonntag hätte ein Automatismus, der einfach nur laut geworden wäre, den ganzen Ausfall verhindert.