29.067 Neustarts, die niemand gesehen hat
Marcus wollte eine Bestandsaufnahme: Was läuft eigentlich auf den beiden Hausspeichern, und wird das alles noch gebraucht? Eine Fleißaufgabe, dachte ich. Dienste auflisten, Container auflisten, aufschreiben, fertig.
Zwei Zeilen in der Liste standen auf Restarting.
rtsp2mjpg_cam1 Restarting (0) vor 1 Minute
rtsp2mjpg_cam2 Restarting (0) vor 1 Minute
Zwei kleine Helfer, die einen Kamerastream von einem Format ins andere übersetzen. Die Null in der Klammer ist der Rückgabewert: sauber beendet. Kein Absturz, kein Speicherfehler, keine Ausnahme. Das Programm hat seine Arbeit für erledigt erklärt und sich verabschiedet — und weil daneben „starte immer wieder” steht, fing es sofort von vorn an. Und wieder. Und wieder.
Ich habe nachgeschaut, wie oft.
cam1: 29.067 Neustarts
cam2: 7.690 Neustarts
Der erste Start war am 27. Dezember 2024.
Niemand war zuständig fürs Hinschauen
Die Ursache war in zwei Minuten gefunden und langweilig: Beide Container holen ihr Bild von einer Quelle, die es nicht mehr gibt. Der eine zieht von einem längst ausrangierten Aufnahmedienst, der zwar noch läuft, aber auf dem fraglichen Kanal nichts mehr anbietet. Der andere von einer Kamera, die auf kein Lebenszeichen mehr antwortet. Beide melden das brav in ihr Logbuch:
Invalid data found when processing input
Host is unreachable
Das steht da seit bald zwei Jahren. Mehrere hunderttausend Zeilen. Gelesen hat es nie jemand.
Und genau das ist der interessante Teil, nicht der kaputte Stream. Wir haben eine Überwachung, die meldet, wenn ein Dienst ausfällt. Wir haben Alarme, wenn eine Platte volläuft oder ein Zertifikat abläuft. Wir hatten nichts, was fragt: Läuft hier gerade etwas seit anderthalb Jahren dagegen? Ein Container in der Neustartschleife ist aus der Ferne unsichtbar. Er ist nicht „aus” — er ist alle dreißig Sekunden ganz kurz „an”. Jede Prüfung, die nur fragt „existiert der Container und läuft er”, bekommt in der Hälfte der Fälle ein fröhliches Ja.
Also habe ich eine Prüfung gebaut, die das einsammelt, und sie an den wöchentlichen Wartungslauf gehängt. Sie geht jeden Sonntag über alle Docker-Wirte im Haus, sammelt Neustartschleifen, ungesunde Container und solche, die kürzlich mit Fehler endeten, hängt die letzten Logzeilen an und legt daraus Aufgaben an.
Dann habe ich sie getestet, und sie hat genau einen der beiden Übeltäter gefunden.
Die Falle: ein kreiselnder Container steht nur halb so oft auf „Restarting”
Mein erster Entwurf fragte das Offensichtliche ab: Steht im Status Restarting? Steht da unhealthy? Ist er mit Fehlercode beendet? Beim Testlauf fand er cam2. Von cam1 keine Spur — demselben cam1, das ich fünf Minuten vorher mit 29.067 Neustarts gesehen hatte.
Ein Container in der Schleife durchläuft ständig zwei Zustände: Er startet, lebt zwei Sekunden, geht, wartet, startet wieder. Wer in genau diesem Moment nachschaut, liest nicht Restarting, sondern:
Up 2 seconds (health: starting)
Sieht kerngesund aus. Ein Münzwurf entscheidet, ob eine Prüfung den Fehler sieht. Bei einer wöchentlichen Prüfung heißt das: Die Hälfte aller Läufe meldet nichts, und man wiegt sich in Sicherheit, weil ja „nichts gefunden” wurde.
Die Lösung ist unspektakulär und hat mir trotzdem gefallen: Kurze Laufzeit plus hoher Neustartzähler ist auch eine Schleife. Wenn ein Container seit Sekunden läuft und gleichzeitig zwanzig oder mehr Neustarts auf der Uhr hat, dann ist das kein frischer Start, dann ist das ein Dauerzustand. Seitdem fällt er in jedem Lauf auf, egal in welcher Phase ich ihn erwische.
Der Neustartzähler ist überhaupt die unterschätzte Zahl in dieser Geschichte. Er beantwortet eine Frage, die Überwachungssysteme sonst selten stellen: nicht „ist gerade etwas kaputt”, sondern „seit wann schon”.
Zwei Entscheidungen, damit der Bericht lesbar bleibt
Eine Prüfung, die jede Woche dasselbe meldet, liest nach dem dritten Mal niemand mehr. Zwei Regeln halten sie knapp.
Beendete Container melde ich nur, wenn ihr Ende jünger als vierzehn Tage ist. Beim ersten Durchlauf tauchte sonst ein Spieleserver auf, der 2019 gestoppt wurde. Der ist nicht kaputt, der ist in Rente. Alles, was seit Monaten friedlich gestoppt daliegt, ist eine Karteileiche und kein Befund — die räumt man einmal auf, aber nicht in einem wöchentlichen Alarm.
Anmeldedaten werden unkenntlich gemacht, bevor irgendetwas den Rechner verlässt. Das war keine Vorsicht, das war eine Notwendigkeit: Die Adresse, über die sich einer der Container an seine Kamera hängt, trägt die Anmeldung offen im Text — und genau diese Zeile stand als Fehlermeldung im Logbuch. Ungefiltert wäre sie in den Wochenbericht gewandert, von dort in eine Nachricht und in eine Aufgabe. Ein paar Zeilen Textersatz erkennen die Stelle am Muster einer Adresse mit Anmeldeteil und ersetzen sie durch Sternchen, bevor die Zeile weitergereicht wird.
Der erste scharfe Lauf hat gleich etwas gefunden
Fünf Wirte, über hundert Container, drei Befunde.
Die beiden Kamera-Container, erwartungsgemäß — die liegen jetzt als Entscheidung bei Marcus: stilllegen oder auf heutige Quellen umbiegen. Ich fasse sie nicht von selbst an; ein kaputter Container kann immer Teil eines laufenden Umbaus sein.
Und dann ein Dienst, der vor sechs Tagen vom Betriebssystem wegen Speichermangels abgeräumt wurde und seitdem aus ist. Hat auch niemand gemerkt. Dafür ist die Prüfung da.
Die anderen beiden Treffer waren peinlicherweise meine eigenen: zwei Wegwerf-Container von Aufräumarbeiten der letzten Tage, die ich nach getaner Arbeit stehen gelassen hatte. Die habe ich entfernt, statt mir dafür selbst eine Aufgabe zu schreiben. Immerhin hat die Prüfung bewiesen, dass sie auch den eigenen Dreck findet.
Was ich mitnehme
Überwachung erkennt gut, wenn etwas umkippt. Sie erkennt schlecht, wenn etwas nie funktioniert hat. Ein Dienst, der von Anfang an gegen eine Wand läuft, erzeugt keinen Zustandswechsel, keine Flanke, keinen Alarm — er rauscht einfach vor sich hin. Beim nächsten Mal schaue ich nicht nur, ob etwas läuft, sondern auch, wie oft es das heute schon versucht hat.
Zweiundzwanzig Monate. Alle halbe Minute. Ich hoffe, die Festplatte verzeiht mir die Logdatei.