CluPilotCloud/docs/runbooks/host-bootstrap.md

12 KiB

Runbook: Wenn die Host-Übernahme stehenbleibt

Der Bootstrap läuft in neun Abschnitten. Bleibt einer davon aus, zeigt die Konsole welcher — nicht „irgendetwas ging schief". Dieses Runbook sagt je Abschnitt: woran man es merkt, wo man nachsieht, und was der übliche Grund ist.


Die eine Regel, die über allen steht

Eine halb installierte Maschine wird neu aufgesetzt, nicht nachgebessert.

Nicht aus Bequemlichkeit. Der Bootstrap ist so gebaut, dass ein zweiter Lauf auf einer frisch aufgesetzten Maschine immer gleich ausgeht — ein Lauf auf einer Maschine, an der jemand von Hand etwas gerade gerückt hat, ist das nicht mehr. Wer nachbessert, tauscht ein wiederholbares Ergebnis gegen ein einmaliges, und merkt den Unterschied erst beim nächsten Host.

Der Weg zurück ist immer derselbe:

  1. Im Adminbereich einen neuen Host anlegen. Der Einmal-Code ist verbraucht; die Seite zeigt ihn nicht wieder her, und das ist Absicht.
  2. Beim Anbieter das Rettungssystem starten.
  3. Die neue Zeile einfügen.

Der alte Host-Eintrag wird im Adminbereich entfernt. Solange er steht, hält er seine Tunneladresse belegt.

Ausnahme: Bleibt der Lauf in rescue_checked stehen, ist noch nichts geschrieben worden. Dort ist Nachbessern richtig — es ist der einzige Abschnitt, der die Platte nicht angefasst hat.


Wo alles steht

Was Wo
Fortschritt, Zeile je Abschnitt /var/lib/clupilot/progress.jsonl
Was schon gesendet wurde (Zeilenzahl) /var/lib/clupilot/progress.sent
Laufprotokoll des Skripts /var/lib/clupilot/bootstrap.log
Aufrufargumente (nur root) /var/lib/clupilot/arguments
Arbeitsverzeichnis: ISO, Protokolle /var/tmp/clupilot-work/
Installer-Protokoll /var/tmp/clupilot-work/qemu.log
Antwortdatei des Installers /var/tmp/clupilot-work/answer.toml
Traefik /var/log/traefik.log, /etc/traefik/traefik.yml

Die Fortschrittsdatei ist der Zustand. Ein Abschnitt, der dort done gemeldet hat, läuft bei einem Wiederanlauf nicht erneut.


Vor dem Neustart oder danach?

Das ist die erste Frage, und sie ist leicht zu beantworten:

findmnt -no FSTYPE /

tmpfs, overlay oder ramfs heißt: noch im Rettungssystem, der Neustart steht bevor. zfs heißt: die Maschine läuft schon auf dem installierten System, und der first-boot-Hook hat den Lauf wieder aufgenommen.


Abschnitt für Abschnitt

rescue_checked — die Eingangsprüfung

Woran man es merkt: Das Skript endet sofort mit einer Liste von Befunden. In der Konsole steht nichts, weil es vor dem Tunnel keinen Weg dorthin gibt.

Übliche Gründe:

  • „Das Wurzelverzeichnis liegt auf /dev/… also auf einer echten Partition." Die Maschine läuft nicht im Rettungssystem. Beim Anbieter das Rettungssystem einschalten und neu starten — das Einschalten allein genügt nicht.
  • „Die CPU meldet weder vmx noch svm." Ein Cloud-Produkt ohne verschachtelte Virtualisierung (Hetzner CPX/CX, teils netcup). Nicht abstellbar; es braucht eine dedizierte Maschine.
  • „/dev/kvm gibt es nicht." Virtualisierung im BIOS aus, oder das Rettungssystem hat das Modul nicht geladen: modprobe kvm_intel bzw. modprobe kvm_amd, dann die Zeile noch einmal.
  • „Es sind Partitionen echter Platten eingehängt." Jemand hat nachgesehen. umount und noch einmal.
  • „Die Uhr geht … Sekunden falsch." Die Meldung enthält den fertigen Befehl zum Stellen. Ohne ihn scheitert später jede TLS-Prüfung mit einer Meldung über Zertifikate statt über die Uhrzeit.

Hier ist Nachbessern richtig. Es wurde noch nichts geschrieben.


debian_installed — das Grundsystem

Heißt „Grundsystem geschrieben". Es entsteht kein Debian, das nachher jemand umbaut: die offizielle Proxmox-ISO wird mit einer Antwortdatei versehen und unter QEMU gegen die echten Platten gestartet.

Woran man es merkt: Der Lauf steht lange ohne Meldung; im Rettungssystem läuft ein qemu-system-x86_64.

Wo man nachsieht: /var/tmp/clupilot-work/qemu.log, und die Antwortdatei daneben. Läuft QEMU noch, kann man dem Installer zusehen — er hört auf 127.0.0.1:5900:

ssh -L 5900:127.0.0.1:5900 root@<öffentliche-ip>

Dann mit einem VNC-Betrachter auf localhost:5900. Sieht man dort eine Eingabemaske, ist die Antwortdatei nicht angenommen worden — der Installer ist in den interaktiven Modus gefallen und wartet, bis die Stunde abläuft.

Übliche Gründe:

  • answer.toml abgelehnt. Steht in /var/tmp/clupilot-work/assistant.log. Das Skript prüft sie mit validate-answer, bevor es die ISO backt, also ist das selten — und wenn, dann liegt es an einem Wert aus der Umgebung (Adresse, Gateway, MAC), den das Rettungssystem anders meldet als erwartet.
  • Prüfsumme der ISO stimmt nicht. Abgebrochene Übertragung. Zeile noch einmal.
  • Keine passende PVE-9-ISO gefunden. Die Liste unter https://enterprise.proxmox.com/iso/ war nicht erreichbar.

rebooted — die einzige unumkehrbare Stelle

Woran man es merkt: Die Maschine antwortet nach dem Neustart nicht mehr, oder sie antwortet, meldet aber nichts weiter.

Übliche Gründe:

  • Die Maschine bootet noch vom Rettungssystem statt von der Platte. Beim Anbieter das Rettungssystem abschalten und neu starten.
  • Der first-boot-Hook lief nicht. Nachsehen mit journalctl -u proxmox-first-boot und ls /var/lib/clupilot/. Fehlt das Verzeichnis ganz, ist der Hook nicht in die ISO gekommen — dann neu aufsetzen.

Kommt die Maschine gar nicht zurück: Anbieterkonsole. Neu aufsetzen ist schneller als jede Suche.


proxmox_installed — abnehmen und Quellen richten

Woran man es merkt: Meldung mit failed und einem der folgenden Sätze.

Übliche Gründe:

  • „pveversion gibt es nicht" — die ISO hat kein Proxmox installiert. Neu aufsetzen.
  • „läuft auf …, das ist kein PVE-Kernel" — die Maschine ist in den Debian-Kernel gebootet. uname -r muss -pve enthalten.
  • „erwartet wäre PVE 9" — Abbild und Unterbau passen nicht zusammen. Mit dem richtigen Abbild neu aufsetzen; Paketquellen heilen das nicht.
  • „apt-get update schlägt fehl" — siehe /var/tmp/clupilot-work/apt.log. Fast immer eine Abonnement-Quelle, die wieder aufgetaucht ist: ls /etc/apt/sources.list.d/.

network_bridged — der gefährlichste Abschnitt

Woran man es merkt: Entweder eine failed-Meldung, oder die Maschine ist für ein paar Minuten weg und kommt dann von selbst zurück.

Kommt sie zurück, war das die Selbstrücknahme. Das ist kein Fehler des Zeitgebers, sondern sein Zweck: die Brücke hätte den Host vom Netz genommen. Nachsehen mit journalctl -t clupilot.

Übliche Gründe:

  • Falsche Anbieterform erkannt. Bei einer gerouteten Einzeladresse muss pointopoint in /etc/network/interfaces stehen; fehlt sie, findet der Kernel das Gateway nicht.
  • „die Datacenter-Firewall ließ sich nicht einschalten" — ohne sie sind die „nur 80/443"-Regeln jeder Kunden-VM wirkungslos. Prüfen mit pvesh get /cluster/firewall/options.

Kommt die Maschine nicht zurück: Anbieterkonsole, dort tar xzf /var/lib/clupilot/interfaces.vor-der-bruecke.tar.gz -C / und ifreload -a. Danach neu aufsetzen.


wireguard_joined — ab hier ist CluPilot erreichbar

Woran man es merkt: Bis hierher stand in der Konsole „wartet auf den Tunnel". Bleibt es dabei, ist dieser Abschnitt der offene.

Wo man nachsieht: wg show auf dem Host. Steht dort ein Peer ohne latest handshake, steht die Datei und der Tunnel nicht.

Übliche Gründe:

  • Der Hub kennt den Peer nicht. Sollte nicht vorkommen — CluPilot legt ihn beim Anlegen des Hosts an —, aber ein gelöschter Host-Eintrag nimmt ihn mit.
  • Der Hub-Endpunkt ist von dieser Maschine aus nicht erreichbar. UDP auf dem Port des Hubs prüfen.
  • „konnte wg-quick@wg0 nicht freigeben" — der Tunnel überlebte den nächsten Neustart nicht. Das ist ein harter Fehler, kein Schönheitsfehler.

traefik_running

Woran man es merkt: failed mit einem der Sätze unten. Der Host ist erreichbar, also lässt sich alles direkt nachsehen.

Übliche Gründe:

  • „antwortet nicht am Ping-Endpunkt"/var/log/traefik.log und systemctl status traefik.
  • „80 und 443 sind nicht belegt" — Traefik läuft, ein Entrypoint fehlt. ss -ltnp | grep -E ':80|:443'. Belegt sie etwas anderes, gehört das nicht auf diese Maschine.
  • Prüfsumme des Binaries stimmt nicht. Zeile noch einmal.

Dass Traefik hier noch keine Routentabelle holt, ist richtig so: den Token dafür gibt es erst mit der Registrierung.


template_built — die goldene Vorlage

Woran man es merkt: failed, meist mit einem Hinweis auf eine der drei Fallen.

Wo man nachsieht: /var/tmp/clupilot-work/virt-customize.log und qm.log.

Übliche Gründe:

  • „erfüllt Falle 2 nicht" — das Cloud-Abbild hat LVM oder die Wurzel ist nicht die letzte Partition. Dann stimmt etwas am Abbild nicht, das dort liegt.
  • „qemu-guest-agent ist NICHT im Abbild"virt-customize hat Erfolg gemeldet und apt hat das Paket still nicht installiert. Fast immer ein Netzproblem im Abbild-Umbau.
  • „kein user: www-data" — die Compose-Datei im Abbild ist nicht die aus assets/. Ohne diese Zeile schlagen alle occ-Aufrufe fehl.
  • „meldet nicht template: 1" — die VM existiert, ist aber keine Vorlage. qm template 9000 von Hand und dann trotzdem neu aufsetzen: wenn dieser Schritt schiefging, ist unklar, was sonst noch.

registered — die Übergabe

Woran man es merkt: Der Host bleibt in der Konsole auf onboarding.

Übliche Gründe:

  • „die Proxmox-Rolle ließ sich nicht angleichen" — ohne Sys.Modify stirbt später jede Kundenbereitstellung am Backup-Schritt. Prüfen mit pveum role list.
  • „hat nicht geantwortet" — CluPilot ist über den Tunnel nicht erreichbar, obwohl der Handshake stand. Auf der CluPilot-Seite nachsehen, ob die Tunneladresse in TRUSTED_RANGES steht.
  • „kam ohne host_token zurück" — die Registrierung ist durchgelaufen, die Antwort war unvollständig. Auf der CluPilot-Seite nachsehen.
  • „der Schlüsseltausch hat keinen Handshake ergeben" — das Skript hat auf den alten Schlüssel zurückgestellt, der Host ist also noch erreichbar. Der Hub hat den neuen Peer möglicherweise schon aufgenommen und den alten entfernt; dann ist der Host beim nächsten Versuch weg. Neu aufsetzen.
  • „die Routentabelle ist nicht abrufbar" — der Token stimmt nicht oder /host/routes antwortet nicht. Direkt prüfen:
    curl -H "Authorization: Bearer $(cat /etc/traefik/host-token)" http://<tunnel-ip>/host/routes
    

Der Host ist nicht mehr erreichbar

Erst die Frage: war die Firewall schon dran? Sie wird als allerletztes angewendet. Steht in der Konsole registered noch nicht auf done, war sie es nicht — dann liegt es am Netz, nicht an den Regeln.

War sie dran, gibt es von der Anbieterkonsole aus genau einen Griff:

/usr/local/sbin/clupilot-emergency-open-firewall.sh

Der Host nimmt danach auf jedem Port wieder an. Es gibt bewusst keine automatische Wiederöffnung — kein Zeitgeber, kein „nach N Minuten ohne Handshake wieder auf". Eine Firewall, die sich unter Störung selbst öffnet, ist keine Firewall.

Zurück kommen die Regeln mit:

nft -f /etc/nftables.conf && systemctl enable --now nftables

Was dieses Runbook nicht sagt

Alles, was noch nicht auf echter Hardware gelaufen ist. Die Abschnitte oben sind aus dem Skript und aus den Fundstellen geschrieben, die ihm zugrunde liegen — nicht aus Vorfällen. Was beim ersten Durchlauf tatsächlich stehenbleibt, gehört hier ergänzt, mit dem Satz, der in der Konsole stand.