diff --git a/docs/runbooks/host-bootstrap.md b/docs/runbooks/host-bootstrap.md new file mode 100644 index 0000000..b035bea --- /dev/null +++ b/docs/runbooks/host-bootstrap.md @@ -0,0 +1,305 @@ +# 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: + +```sh +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`: + +```bash +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: + ```bash + curl -H "Authorization: Bearer $(cat /etc/traefik/host-token)" http:///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: + +```bash +/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: + +```bash +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. diff --git a/docs/superpowers/plans/2026-07-30-host-uebernahme-bootstrap-skript.md b/docs/superpowers/plans/2026-07-30-host-uebernahme-bootstrap-skript.md index cd88c1e..e0c0343 100644 --- a/docs/superpowers/plans/2026-07-30-host-uebernahme-bootstrap-skript.md +++ b/docs/superpowers/plans/2026-07-30-host-uebernahme-bootstrap-skript.md @@ -502,7 +502,7 @@ merkt, wo man nachsieht, was der übliche Grund ist. Und ausdrücklich: **eine h installierte Maschine wird neu aufgesetzt, nicht nachgebessert.** Ein neuer Code aus dem Adminbereich, Rettungssystem, noch einmal. -- [ ] Schreiben, committen. Nachricht: `Write down what to do when the bootstrap stops` +- [x] Schreiben, committen. Nachricht: `Write down what to do when the bootstrap stops` ---