Teil 6 von 6
Was, wenn heute Nacht etwas kaputtgeht?
Sonntag, kurz nach fünf, und ein Update hat einen Dienst zerlegt. Wie mein Homelab so eine Nacht übersteht, und wer mir Bescheid sagt, wenn es das nicht allein schafft.
Sonntag, kurz nach fünf Uhr morgens. Ich schlafe noch, mein Homelab nicht. Jede VM schaut gerade nach, ob es für ihre Programme neue Versionen gibt, und spielt sie ein. Angenommen, Immich, meine Fotoverwaltung, bekommt ein Update, und danach kommt der Dienst nicht mehr hoch. Oder schlimmer, eine ganze VM startet nicht mehr.
Ganz am Anfang der Serie, in Teil 1, stand die Frage, was passiert, wenn der Server heute Nacht stirbt. Seitdem haben wir gesehen, wie Anfragen sicher nach Hause kommen, wie ein Brief ins Archiv wandert, wie aus einer Textdatei eine VM wird und wer diesen Code ausführt. Dieser letzte Teil kümmert sich um die schlechte Nacht. Die Frage von damals zerfällt dabei in zwei kleinere: Was kann ich zurückholen? Und wer sagt mir überhaupt, dass ich es muss?
Welcher Schaden, welche Sicherung?
Eine Sicherung, ein Backup, ist eine Kopie, aus der ich einen früheren Zustand zurückholen kann. Welche Kopie die richtige ist, hängt davon ab, was kaputt ist. Eine VM, die nicht mehr startet, braucht etwas anderes als eine Datenbank, die ein Update verdorben hat. Ich plane Sicherungen deshalb vom Schaden her, und so sind drei Ebenen entstanden, die sich bewusst überlappen.
Zwei Wörter aus Teil 4 helfen dabei. Ein Dienst läuft bei mir in Docker-Containern, verschlossenen Kisten für Programme, und die Kisten eines Dienstes zusammen heißen Stack. Die Tabelle zeigt die drei Ebenen, wann sie laufen und wogegen sie helfen.
| Ebene | Wann | Wohin | Hilft, wenn … |
|---|---|---|---|
| 1 · ganze VM | täglich 01:00 | Backup-Server bei Hetzner | eine VM nicht mehr startet |
| 2 · jeder Stack einzeln | täglich 03:30 | auf der VM und verschlüsselt bei Hetzner | die Daten eines Stacks falsch oder weg sind |
| 3 · Update mit Rückweg | sonntags 05:00 | auf der VM | ein Update einen Stack kaputt macht |
Hetzner ist ein Anbieter, bei dem ich zwei kleine Server und Online-Speicher miete, also das „außer Haus“ dieser Serie. Im Bild steht oben mein Server zu Hause, unten Hetzner, und die Nummern 1 bis 3 markieren die drei Ebenen.
Gehen wir sie von grob nach fein durch.
Ebene 1: ganze VMs
Die gröbste Ebene sichert jede VM als Ganzes, jede Nacht um 01:00. Das Ziel ist ein Proxmox Backup Server, kurz PBS, das Sicherungsprogramm aus dem Hause Proxmox. Meiner läuft auf einem der beiden Server bei Hetzner.
Der PBS zerlegt die Festplatten einer VM in Blöcke, sogenannte Chunks, und speichert jeden Block nur einmal, auch wenn er in hundert Sicherungen vorkommt. Das ist ein bisschen wie ein Lager, das von zehn gleichen Umzugskisten nur eine aufhebt und sich merkt, wo sie überall hingehört. Bevor ein Chunk das Haus verlässt, verschlüsselt ihn mein Server mit einem Schlüssel, den nur er hat. Hetzner sieht nur Zeichensalat, und auch die Verbindung dorthin ist verschlüsselt. Der Job ist auf 80 MB/s gedrosselt und sichert erst die kleinen VMs, zum Schluss die großen mit Fotos, Dokumenten und den Daten der Pipeline. Im Bild steht bei dieser Ebene noch das Wort Fleecing; was es damit auf sich hat, erzähle ich weiter unten.
Eine Sicherung, die nie jemand liest, ist für mich eher eine Vermutung. Deshalb liest der PBS jeden Tag um 15:30 Chunks zurück und vergleicht ihre Prüfsummen. Eine Prüfsumme ist eine Art Fingerabdruck einer Datei, und ändert sich auch nur ein Bit, passt der Abdruck nicht mehr. Dieser Lauf heißt verify und nimmt sich jede Sicherung spätestens nach 30 Tagen wieder vor.
Ebene 2: jeder Stack für sich
Für den Alltag ist eine ganze VM oft zu grob. Wer nur die Datenbank von gestern braucht, will nicht die ganze VM zurückdrehen. Deshalb sichert jede VM um 03:30, mit bis zu 20 Minuten Zufallsversatz, jeden ihrer Stacks einzeln. Das erledigt compose-backup, ein kleines Werkzeug, das ich dafür geschrieben habe.
Es hält den Stack kurz an und packt seine Daten und seine Beschreibung ein. Dazu legt es eine Liste mit den Prüfsummen aller Dateien und notiert für jede Kiste, aus welcher Vorlage sie gebaut wurde. Eine solche Vorlage heißt bei Docker Image, und notiert wird dabei der genaue Fingerabdruck der Version, der Digest, statt einfach „die neueste“. Die letzten drei Sicherungen bleiben auf der VM liegen.
Danach kopiert rclone, ein Kopierprogramm für Online-Speicher, die Sicherungen zu Hetzner. Es verschlüsselt dabei Inhalte und Dateinamen. Das muss so sein, denn in jeder Sicherung steckt auch die .env-Datei des Stacks aus Teil 4, und darin stehen Passwörter im Klartext. Nach jedem Lauf meldet sich das Skript, leise bei Erfolg, laut bei einem Fehler, und mit einer Warnung, wenn eine Platte über 85 % voll ist.
Ebene 3: zurück zum Sonntagmorgen
Die feinste Ebene ist das Update aus der Szene vom Anfang. Sonntags um 05:00 holt jede VM neue Images. Gibt es für einen Stack keine, passiert nichts. Gibt es welche, sichert das Skript den Stack zuerst auf der VM, startet ihn mit den neuen Images, wartet 30 Sekunden und prüft, ob alle Kisten laufen und gesund sind.
Danach schickt es mir eine Nachricht aufs Handy, und darin steht genau der Befehl, der den Stand von vor dem Update zurückholt. Für Immich sieht das so aus, leicht gekürzt:
Aktualisiert: immich
Alle Container laufen, nichts zu tun.
Nur bei Problemen: Rueckweg auf den Stand vor dem Update (wurde NICHT ausgefuehrt):
immich: compose-backup restore /srv/backups/immich/<stand>/ --force --pinned --up
Ausgeführt wird der Befehl nie automatisch. Ein Rückweg, der von selbst losläuft, würde auch Daten zurückdrehen, die seit dem Update dazugekommen sind, also entscheide ich. Ist ein Stack nach dem Update nicht gesund, kommt derselbe Befehl als „Rollback empfohlen“ mit hoher Priorität.
Alles landet bei Hetzner
Zwei der drei Ebenen schicken ihre Kopien zu Hetzner, in den sogenannten Object Storage. Das ist Speicher, den man nicht wie eine Festplatte einbindet, sondern übers Internet Datei für Datei anspricht, ähnlich einem Lager mit Schließfächern. Die Sprache, in der man mit so einem Lager redet, heißt S3. Fast jedes Werkzeug beherrscht sie, bei mir unter anderem der PBS, rclone und OpenTofu.
Ein Schließfach heißt in dieser Welt Bucket, und ich habe eines pro Zweck, etwa für die Chunks des PBS, für die Stack-Sicherungen und für das Inventarbuch von OpenTofu aus Teil 4. Hetzner rechnet pro Konto ab, nicht pro Bucket. Ein Bucket je Zweck kostet also nichts extra, und Zugriffsrechte und Aufräumregeln lassen sich für jeden Zweck einzeln festlegen.
Aus dem Spiegel wird eine Geschichte
rclone gleicht den Bucket mit der VM ab wie einen Spiegel. Was auf der VM verschwindet, verschwindet beim nächsten Lauf auch im Bucket, und eine kaputte Sicherung wird genauso treu hochgeladen wie eine gute. Deshalb ist auf jedem Bucket die Versionierung an. Wer eine Datei überschreibt oder löscht, erzeugt nur eine neue Version, die alte bleibt im Schließfach liegen.
Damit das Fach nicht endlos voll wird, gibt es eine Aufräumregel, die der Speicher selbst ausführt. Sie lässt alte Versionen der Stack-Sicherungen nach 30 Tagen verfallen.
Bleibt der Schlüssel. Verschlüsselung verschiebt das Problem ja nur dorthin. Den Schlüssel für rclone habe ich im Passwortmanager, denn ein Schlüssel, der nur auf dem Server liegt, den er schützen soll, ist im Ernstfall mit ihm weg.
Zurückholen
Jetzt also der Ernstfall. Welcher Weg der richtige ist, hängt wieder am Schaden. Das Bild beginnt oben mit der Frage, was kaputt ist, und verzweigt dann in die drei Fälle.
Nach einem kaputten Update kopiere ich den Befehl aus der Nachricht und führe ihn auf der VM aus. Sind Daten eines Stacks falsch oder weg, wähle ich eine der drei Sicherungen auf der VM. Ist die VM selbst nicht mehr da, holt rclone die Sicherung aus dem Bucket und entschlüsselt sie dabei.
In beiden Fällen macht compose-backup restore den Rest, und zwar vorsichtig. Es prüft zuerst alle Prüfsummen und schreibt erst, wenn jede stimmt. Vorhandene Daten überschreibt es nur, wenn ich das ausdrücklich verlange (--force), und es startet genau die Images, die beim Sichern liefen (--pinned), nicht die neuesten.
Startet die ganze VM nicht mehr, zeigt Proxmox die Sicherungen vom PBS wie eine weitere Festplatte. Ich wähle eine aus, mein Server holt die Chunks und entschlüsselt sie mit seinem Schlüssel.
Hat das je funktioniert?
Ja, und zwar im großen Stil, denn der Umzug ins neue Homelab im September war im Grunde ein Restore. Paperless habe ich auf dem alten Rechner mit compose-backup gesichert, 11 GB in fünf Minuten, und auf der neuen VM mit Prüfsummen-Check zurückgespielt. Danach standen 767 Dokumente in der Datenbank. Jeder Dienst, der so umgezogen ist, war eine Generalprobe. Die Fehler dabei waren meine, nicht die des Werkzeugs: zweimal ein Schrägstrich zu viel am Ende eines Kopierpfads.
Wer mich weckt
Die beste Sicherung hilft nichts, wenn niemand merkt, dass sie gebraucht wird. Den kaputten Immich-Dienst vom Anfang würde ich sonst erst bemerken, wenn ich das nächste Mal Fotos ansehen will.
Alle Warnungen erreichen mich über einen einzigen Kanal, ntfy. Das ist ein schlichter Push-Dienst, wie eine Klingel: Ein Skript schickt eine kurze Nachricht an ntfy, und mein Handy zeigt sie an. ntfy läuft bei Hetzner, nicht auf meinem Server zu Hause. Fällt der aus, ist die Klingel noch da.
Wer klingelt, zeigt das nächste Bild. Oben steht mein Server mit den Quellen der Warnungen, unten ntfy bei Hetzner, und die roten Linien sind die Nachrichten auf dem Weg zum Handy.
Die erste Quelle kennst du schon, die Sicherungs- und Update-Skripte auf jeder VM.
Die zweite ist Uptime Kuma, der Wächter aus Teil 4. Er fragt jede Minute an 22 Stellen nach, ob sie antworten, von den Diensten über beide DNS-Server bis zum Backup-Server und zu ntfy selbst. Oft prüft er dabei ein Stichwort in der Antwort, nicht nur, ob überhaupt etwas kommt. Bevor er Alarm schlägt, versucht er es mehrmals, damit ein einzelner Aussetzer niemanden weckt.
Die dritte Quelle schaut auf Messwerte. InfluxDB ist eine Datenbank für Zeitreihen, ein Fahrtenschreiber, der Werte mit Uhrzeit speichert. Proxmox schreibt alle paar Sekunden hinein, wie ausgelastet jede VM ist, mein Server jede Minute die Selbstauskunft seiner Festplatten (SMART), und das Messprogramm Telegraf liefert Werte vom Server bei Hetzner. Kleine Python-Skripte schauen alle fünf Minuten darauf und melden sich, wenn ein Runner aus Teil 5 knapp an Speicher wird, mein Server nicht erreichbar ist oder eine Platte schwächelt. Sie melden nur Wechsel, einmal beim Kippen und einmal bei der Entwarnung.
Wo die Klingel schweigt
Ganz dicht ist das nicht, und zwei Lücken kenne ich. Die nächtliche VM-Sicherung belastet den Server, und anfangs meldete Kuma nachts kurze Aussetzer, die sich von selbst erledigten. Seitdem gibt es von 01:00 bis 03:00 ein Wartungsfenster, in dem die betroffenen Prüfungen „Wartung“ zeigen statt „Ausfall“. Ein echter Ausfall in diesem Fenster fällt deshalb erst danach auf. Den Preis kenne ich und zahle ihn.
Die zweite Lücke ist größer. Kuma und die Python-Wachen laufen selbst in VMs auf meinem Server. Hängt der ganze Server, hängen sie mit, und ntfy wartet auf eine Nachricht, die niemand schickt. Gegen den Hänger selbst hilft ein Watchdog, eine Art Totmannschalter, der den Server dann von allein neu startet. Eine Prüfung von außen, die Alarm schlägt, wenn mein Server schweigt, wäre der nächste Schritt.
Zwei unruhige Nächte
Ruhig waren die Nächte allerdings nicht von Anfang an.
Aus der Praxis: Mitte Oktober waren an einem Morgen meine Doku, die Oberfläche des Proxys und die Anmeldung weg. Auf drei VMs hatte das Dateisystem aufgegeben, jedes Mal mitten in der Sicherung genau dieser VM, in Nächten, in denen der Upload zum PBS stockte. Die VM läuft während der Sicherung nämlich weiter. Will sie einen Block überschreiben, der noch nicht gesichert ist, muss dieser Block erst zum Backup-Server. Hängt der Upload, hängt auch das Schreiben, die VM meldet eine Zeitüberschreitung, und ihr Dateisystem gibt auf. Die Abhilfe heißt Fleecing. Die alten Blöcke kommen zuerst in einen Zwischenspeicher auf meinem Server, und die VM schreibt mit voller Geschwindigkeit weiter. Die drei Dateisysteme hat eine Prüfung beim Neustart repariert. Fleecing ist seit dem 16. Oktober an, und seitdem sind die Nächte ruhig.
Aus der Praxis: Im September schlug verify immer wieder fehl, über 1.700 einzelne Chunk-Fehler in 30 Tagen. Ein Teil kam von außen. Hetzner meldete eine Störung im Object Storage, und sein Eingang, das Gateway, antwortete mit Fehlern (503 und 504). Den anderen Teil hatte ich selbst gebaut. Der Sicherungsjob war gewachsen und lief bis in den Nachmittag, verify startete trotzdem um 13:00, und beide hämmerten gleichzeitig auf denselben Bucket. Verify läuft jetzt um 15:30 und liest weniger auf einmal, und der nächste Lauf hatte noch genau einen Fehler.
Wer Teil 5 gelesen hat, erkennt das Muster. Dort teilten sich zwei Jobs einen Runner, hier teilten sich zwei Jobs einen Bucket, und keiner von beiden wusste vom anderen.
Zurück im Zug
Damit sind wir am Ende der Serie, und ich setze mich noch einmal in den Zug aus Teil 1. Ich tippe paperless.home.example aufs Handy, und eine Sekunde später ist der Brief da. Inzwischen weißt du, was in dieser Sekunde passiert. NetBird und ein einziger Proxy bringen die Anfrage ohne offenen Port nach Hause (Teil 2). Der Brief ist über Scanner, Paperless und ein lokales Sprachmodell ins Archiv gekommen (Teil 3). Die VM, auf der er liegt, ist eine Datei im Repo (Teil 4), die eine Pipeline auf meinen eigenen Runnern angewendet hat (Teil 5).
Und falls mein Server heute Nacht stirbt? Dann liegt der Brief verschlüsselt bei Hetzner, sogar zweimal, als Teil der ganzen VM und in der Sicherung des Paperless-Stacks. Bescheid sagt mir in den meisten Fällen das Handy. Nur wenn der ganze Server stumm hängen bleibt, merkt es von außen noch niemand. Das ist die nächste Baustelle.
Wenn du jetzt noch einmal auf das große Bild aus Teil 1 schaust, liest du es vermutlich mit anderen Augen. Welche der vier Schichten würdest du in deinem eigenen Homelab zuerst bauen?