Derselbe Fehler zweimal — fünfzehn Stunden beim ersten Mal, zwölf Minuten beim zweiten
Ein Befehl, dem ein einziges Feld fehlte, hat die Verwaltungsschicht meines Servers abgeschossen — zum zweiten Mal innerhalb von elf Tagen. Beim ersten Mal kostete mich das einen Neustart und fünfzehn Stunden Prüflauf. Beim zweiten Mal zwölf Minuten. Der Unterschied war nicht Glück, sondern eine Erklärung.
Ein Unraid-Server besteht aus zwei Schichten, die man im Alltag nie auseinanderhält. Unten arbeitet der Kern: Er betreibt den Plattenverbund, hält die Daten zusammen und tut das völlig unbeeindruckt davon, ob jemand zuschaut. Darüber liegt ein Verwaltungsdienst — er zeichnet die Oberfläche, verwaltet die Freigaben, überwacht die Platten und steuert, wann sie schlafen gehen.
Ich wollte eine neue Freigabe anlegen, per Kommandozeile statt über die Oberfläche. Der Befehl war fast vollständig; ein Feld fehlte. Der Verwaltungsdienst bemängelte das korrekt im Protokoll — und starb im selben Atemzug. Dass ein fehlender Parameter einen Dienst umbringt, ist ein Fehler auf Herstellerseite. Ausgelöst habe ich ihn.
Der Patient lebt, nur der Arzt ist weg
Die erste Frage bei so etwas ist nicht „wie repariere ich das", sondern „wie schlimm ist es". Die Antwort war erfreulich: Der Plattenverbund lief weiter, alle Freigaben waren eingehängt, einundzwanzig Container liefen, der Dateidienst antwortete, ein Schreibtest ging durch. Verloren war ausschließlich die Verwaltungsebene — Oberfläche, Freigabenverwaltung, Plattenüberwachung.
Das ist die gute Nachricht und die Falle zugleich. Kein Zeitdruck, nichts brennt. Aber es gibt auch keinen sauberen Weg mehr, das System herunterzufahren: Genau der läuft über den Dienst, der gerade gestorben ist. Und daran hängt der Preis. Wer in diesem Zustand einfach neu startet, hat den Verbund nie ordentlich angehalten — beim nächsten Start läuft dann ein Prüflauf über alle Platten. Bei neun Terabyte sind das rund fünfzehn Stunden. Genau diese Rechnung hatte ich elf Tage zuvor schon einmal bezahlt.
Warum der Neustart scheitern musste
Beim ersten Mal hatte ich versucht, den Dienst einfach wieder zu starten. Er protokollierte zwei, drei Zeilen — und war weg. Kein Fehler, keine Erklärung, nichts. Nach mehreren Anläufen blieb nur der Neustart des ganzen Servers, mit allem, was daran hing. Die Frage, warum der Dienst sich weigerte, blieb offen. Das war der eigentliche Fehler des Tages — teurer als der Befehl, der alles auslöste.
Diesmal habe ich zuerst diese Frage beantwortet, und zwar mit dem billigsten Werkzeug, das es dafür gibt: zwei Protokolle nebeneinander. Einmal der letzte erfolgreiche Start nach einem Neustart des Servers, einmal mein gescheiterter Versuch. Die beiden Spuren laufen Zeile für Zeile parallel — bis auf eine einzige, die im Fehlerfall fehlt.
In dieser Zeile lädt der Dienst beim Hochfahren den Treiber des Plattenverbunds und übergibt ihm dabei, wo die Beschreibung des Verbunds liegt. Aus dieser Übergabe baut er seine eigene Geräteliste auf — welche Platte welche Rolle hat, wie groß sie ist, wie sie heißt. Läuft der Verbund aber bereits, ist der Treiber längst geladen. Der Dienst überspringt den Schritt als erledigt, seine Liste bleibt leer, und beim ersten Zugriff darauf steigt er wortlos aus.
Damit war klar: Den Verwaltungsdienst bei laufendem Verbund neu zu starten, ist nicht schwierig, sondern ausgeschlossen. Die Bestätigung steht im System selbst — das mitgelieferte Stopp-Skript entlädt am Ende genau diesen Treiber. Es rechnet also fest damit, dass ein Start ohne frisch geladenen Treiber nicht funktioniert.
Der Weg zurück: zwölf Minuten
Aus der Erklärung fiel der Ablauf von selbst heraus. Container anhalten, Dateidienst stoppen, sämtliche Einhängungen lösen, die Schicht beenden, die aus den einzelnen Platten die gemeinsamen Freigaben zusammensetzt — und dann den Verbund über den Kern anhalten, ordentlich, mit Bestätigung im Zustandsregister. Erst danach den Treiber entladen, den Verwaltungsdienst starten und den Verbund wieder hochfahren.
Der wichtigste Teil daran ist nicht die Reihenfolge, sondern eine Einsicht, die beim ersten Mal gefehlt hat: Ein sauberer Stopp nimmt auch einem späteren Neustart die Strafe. Die Stunden Prüflauf zahlt man nicht fürs Neustarten, sondern für die Art, wie vorher angehalten wurde. Wer in diesem Zustand steckt, sollte deshalb in jedem Fall zuerst sauber stoppen — selbst wenn er danach doch booten will. Der Verbund kam anschließend ohne Prüflauf und ohne einen einzigen Fehler zurück.
Für alle, die gerade im selben Zustand stecken
Derselbe Ablauf in Befehlen — der Verwaltungsdienst heißt emhttpd,
der Treiber des Verbunds md-mod, und die Schicht, die aus den Platten
die Freigaben zusammensetzt, shfs. Den Aufruf, der den Dienst
umbringt, schreibe ich bewusst nicht aus.
/etc/rc.d/rc.docker stop
/etc/rc.d/rc.samba stop
umount /var/lib/docker /mnt/user0 /mnt/cache /mnt/disk*
kill $(pgrep -x shfs) # löst /mnt/user meist gleich mit
umount /mnt/user # falls nicht
mdcmd stop # warten, bis mdState=STOPPED
rmmod md-mod
/usr/local/sbin/emhttp start
emcmd "cmdStart=Start"
Die vorletzte Zeile ist der Punkt, an dem der erste Anlauf gescheitert war:
Ohne rmmod läuft der Start ins Leere, weil der Treiber schon geladen
ist und der Dienst den Schritt überspringt, aus dem er seine Geräteliste bezieht.
„Gestartet" war gelogen
Ganz glatt ging der Wiederanlauf trotzdem nicht, und dieser Teil ist der lehrreichste. Der erste Startbefehl kam von einem Dienst, der selbst gerade erst keine halbe Minute alt war. Er quittierte mit einem internen Fehler, der Verbund startete trotzdem — aber die Schicht, die die Freigaben zusammensetzt, wurde dabei übersprungen.
Die Statusanzeige meldete brav „gestartet". Tatsächlich fehlte die Hälfte. Der Dienst legte daraufhin die Verzeichnisse für die Container-Daten an der Stelle an, an der sonst die Freigaben liegen — und die lag in diesem Moment im Arbeitsspeicher. Docker startete auf einem leeren Datenbestand. Aus einundzwanzig laufenden Containern wurden null.
Der Schreck hielt genau so lange, bis ich nachgesehen hatte: Verschwunden war nichts. Der echte Bestand lag unberührt auf der SSD, 224 Gigabyte, Zeitstempel von vor zehn Tagen. Verloren gegangen war nur der Weg dorthin. Die Heilung bestand darin, Docker sofort wieder anzuhalten, das falsche Verzeichnis zu lösen, die Rückstände aus dem Arbeitsspeicher zu löschen — die Stelle muss wirklich leer sein, sonst wiederholt sich das Spiel — und den Stopp-Start-Zyklus einmal sauber zu durchlaufen, jetzt über den gesunden Dienst.
Was ich mir dabei angewöhnt habe: nicht mehr die Statusmeldung zu prüfen,
sondern die Wirkung. „Gestartet" ist eine Behauptung des Systems über sich selbst.
Ob die Freigaben wirklich da sind, verrät pgrep -c shfs:
Die Antwort muss 2 lauten, einmal für die Freigaben selbst und
einmal für die Sicht ohne Cache. Alles andere heißt, dass die halbe Miete fehlt.
Was ich daraus mitgenommen habe
- Wer an einer Verwaltungsschicht vorbei direkt auf der Kommandozeile arbeitet, sollte vorher wissen, wie er sie zurückholt. Die Oberfläche ist nicht nur Bequemlichkeit, sie ist auch ein Geländer.
- „Neustart hilft nicht" ist manchmal keine Pechsträhne, sondern Zwangsläufigkeit. Zwei Protokolle nebeneinanderzulegen — einmal Erfolg, einmal Fehlschlag — beantwortet das in Minuten und ersetzt stundenlanges Probieren.
- Sauber herunterfahren lohnt sich auch dann, wenn man gleich wieder hochfahren will. Der Aufpreis entsteht beim Anhalten, nicht beim Starten.
- Eine Statusanzeige ist kein Beweis. Prüfen Sie die Wirkung, nicht die Meldung — in diesem Fall lagen zwischen beiden einundzwanzig Container.
- Und die Ironie zum Schluss: Weil ohnehin ein Neustart des Verbunds anstand, hat der Server die neue Freigabe beim Hochfahren ganz von allein übernommen. Der Befehl, der den ganzen Ausfall ausgelöst hat, wäre nie nötig gewesen.
Diese Art zu arbeiten — erst verstehen, warum etwas nicht geht, und einen Ausfall nicht mit einem Neustart zudecken — ist das, was ich mitbringe, wenn in einer Firma ein System steht und die Uhr läuft. Wenn Sie so einen Fall haben, schreiben Sie mir.
Transparenz: Diese Notiz ist mit KI-Unterstützung geschrieben — auf Basis meiner eigenen Aufzeichnungen und Systeme, inhaltlich von mir geprüft. Die redaktionelle Verantwortung liegt bei mir.
Die Konfigurationen hier stammen aus meinem privaten Homelab. Sie sind ungeprüft für Produktivsysteme — Eingriffe in Speicher- und Systemverwaltung gehören vorher in eine Testumgebung.