pvesnap-recovery: Snapshots als Maschine starten

Zwei Betriebsarten:

  live      abgeschottet ohne Netzwerk - zum Hineinschauen ueber die
            noVNC-Konsole, Dump ziehen, Daten ueber ein Austauschlaufwerk
            herausholen
  recovery  mit Netzwerk und gleicher Identitaet (SMBIOS-UUID, vmgenid,
            MAC-Adressen, Hostname) - warnt, wenn das Original noch laeuft

Die Datentraeger werden ueber PVE::Storage::vdisk_clone geklont, also mit
derselben Funktion und Cluster-Sperre, die Proxmox selbst verwendet. Auf
Ceph/ZFS/LVM-thin ist das Copy-on-Write: 32 GiB waren im Test in 0,8s
geklont, das Original bleibt unberuehrt.

Enthaelt der Snapshot den Arbeitsspeicher, wird er mitkopiert - die Maschine
laeuft dann genau dort weiter, wo sie stand, statt zu booten. Dafuer muss die
Geraeteausstattung exakt passen:

  - vmgenid und smbios1 bleiben erhalten (ohne vmgenid bricht das Laden mit
    "Unknown savevm section" ab)
  - runningmachine/runningcpu werden uebernommen
  - die Netzwerkkarte wird abgeklemmt statt entfernt
  - das Austauschlaufwerk kommt erst nach dem Fortsetzen per Hotplug dazu,
    sonst bemerkt der Gast es nie (nachgewiesen ueber "info virtio-status")

Proxmox meldet einen fehlgeschlagenen RAM-Ladevorgang als TASK OK und laesst
die Maschine angehalten stehen - deshalb wird das Task-Protokoll mitgelesen,
fortgesetzt und deutlich gemeldet, wenn stattdessen kalt gebootet wurde.

Austausch mit dem Host: bei VMs eine formatierte Zusatzplatte, bei
Containern ein durchgereichtes Verzeichnis - dort passt auch ein bereits
eingehaengtes Netzlaufwerk.

Verworfen wird restlos, samt Aufheben des rbd-Snapshot-Schutzes, den das
Klonen setzt - sonst koennte die Vorhaltezeit den Snapshot nie mehr loeschen.
Angefasst wird nur, was den Tag pvesnap-recovery traegt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
duffyduck
2026-07-31 11:38:38 +02:00
co-authored by Claude Opus 5
parent 8577b23b0c
commit 725fbf8732
6 changed files with 2486 additions and 6 deletions
+193 -1
View File
@@ -12,10 +12,12 @@ löscht. Alles wird über **eine INI-Datei** gesteuert, die sich auch bequem in
* Läuft cluster-weit (alle Nodes) über `pvesh`
* Nur Python-Standardbibliothek — keine zusätzlichen Pakete nötig
Dazu zwei Werkzeuge, um wieder **an die Daten im Snapshot** zu kommen:
Dazu drei Werkzeuge, um wieder **an die Daten im Snapshot** zu kommen:
* `pvesnap-explorer` — zwei Fenster im Terminal wie im Midnight Commander
* `pvesnap-web` — im Browser durchsehen und herunterladen, auch vom anderen Rechner
* `pvesnap-recovery` — den Snapshot als **laufende Maschine** starten, abgeschottet
ohne Netzwerk oder als vollwertige Wiederherstellung mit gleicher Identität
---
@@ -46,6 +48,7 @@ Das Skript legt an:
| `/usr/local/bin/pvesnap` | Dienst und Konfiguration |
| `/usr/local/bin/pvesnap-explorer` | Zwei-Fenster-Explorer |
| `/usr/local/bin/pvesnap-web` | Web-Oberfläche |
| `/usr/local/bin/pvesnap-recovery` | Snapshot als Maschine starten |
| `/etc/pvesnap/pvesnap.conf` | Konfiguration (wird bei Updates **nicht** überschrieben) |
| `/var/lib/pvesnap/state.json` | merkt sich die letzten Läufe |
| `/etc/systemd/system/pvesnap.service` | systemd-Unit des Snapshot-Dienstes |
@@ -546,6 +549,193 @@ Snapshot wieder ausgehängt.
---
## Einen Snapshot als Maschine starten — `pvesnap-recovery`
Manchmal reicht es nicht, einzelne Dateien herauszukopieren. Eine Datenbank zum
Beispiel liegt im Snapshot als Haufen halbfertiger Dateien — brauchbar wird sie
erst, wenn der Datenbankserver läuft und selbst einen Dump schreibt. Genau dafür
ist `pvesnap-recovery` da: Es startet den Snapshot als **eigenständige Maschine**,
ohne das Original anzufassen.
Zwei Betriebsarten:
| | **live** | **recovery** |
|---|---|---|
| Netzwerk | keins | volles Netz |
| Identität | bleibt (UUID, MACs, Hostname) | bleibt (UUID, MACs, Hostname) |
| Wofür | hineinschauen, Dump ziehen, Daten holen | die Maschine wirklich wieder in Betrieb nehmen |
| Risiko | keins — sie kann nichts erreichen | hoch, solange das Original läuft |
Bedient wird das Ganze mit `pvesnap-recovery` (ncurses-Oberfläche mit Übersicht
und Assistent) oder direkt über Parameter.
### Warum das schnell geht
Die Datenträger werden nicht kopiert, sondern **geklont**. Auf Ceph/RBD, ZFS und
LVM-thin ist das ein Copy-on-Write-Klon: Er ist in Sekunden fertig, egal wie groß
die Platte ist, und belegt anfangs keinen zusätzlichen Platz. Eine 32-GB-Platte
war im Test nach **0,8 Sekunden** geklont.
Dafür wird `PVE::Storage::vdisk_clone` benutzt — dieselbe Funktion, die auch
Proxmox selbst für Klone verwendet, samt Cluster-Sperre auf dem Storage. Es wird
also nichts nachgebaut, was Proxmox schon kann.
> Auf Datei-Storages (`dir`, `nfs`, `cifs`) geht das nicht — dort lässt sich aus
> einem qcow2-internen Snapshot kein Klon ziehen. Für diese Storages bleibt der
> Weg über `pvesnap-explorer`.
### Der Arbeitsspeicher kommt mit
Enthält der Snapshot den Arbeitsspeicher (`vmstate`, in der Konfiguration
`snapshot_vmstate = yes`), wird der mitgenommen. Die Maschine **bootet dann
nicht**, sondern läuft genau dort weiter, wo sie beim Snapshot stand:
* kein Crash-Recovery, kein `fsck`, kein Journal-Rollback
* Datenbanken sind bereits offen und konsistent
* die Uhr im Gast steht auf dem Snapshot-Zeitpunkt
Im Test war das nachweisbar: Die Konsole zeigte 10:38 — die Uhrzeit des
Snapshots — während auf dem Host längst 11:24 war.
Damit das klappt, muss die Geräteausstattung exakt zum gespeicherten Zustand
passen. `pvesnap-recovery` sorgt selbst dafür:
* `vmgenid` und `smbios1` bleiben erhalten (fehlen sie, bricht das Laden mit
`Unknown savevm section or instance 'vmgenid'` ab)
* `runningmachine` und `runningcpu` aus dem Snapshot werden übernommen
* die Netzwerkkarte bleibt **vorhanden**, wird aber abgeklemmt (`link_down=1`)
statt entfernt — herausnehmen würde den Zustand unbrauchbar machen
* das Austauschlaufwerk wird erst **nach** dem Fortsetzen angesteckt (Hotplug),
weil der Gast in einem Zustand aufwacht, in dem es die Platte noch nicht gab
Ein Detail, das Proxmox nicht selbst meldet: Schlägt das Laden des
Arbeitsspeichers fehl, quittiert Proxmox den Start trotzdem mit `TASK OK` und
lässt die Maschine angehalten stehen. `pvesnap-recovery` liest das Task-Protokoll
mit, setzt die Maschine fort und sagt deutlich, wenn statt des RAM-Standes kalt
gebootet wurde.
Mit `--no-resume` lässt sich der Arbeitsspeicher bewusst weglassen.
### Daten aus einer Maschine ohne Netzwerk holen
Ohne Netz kommt nichts heraus — dafür gibt es das **Austauschlaufwerk**.
**Bei virtuellen Maschinen** wird eine leere, formatierte Zusatzplatte angelegt
(Bezeichnung `PVESNAP`, mit einer kurzen `LIESMICH.txt` darauf):
```bash
# Snapshot abgeschottet starten, mit 20 GB Austauschplatte
pvesnap-recovery live 802 --exchange 20G
# im Gast (über die noVNC-Konsole):
mount /dev/disk/by-label/PVESNAP /mnt
mysqldump --all-databases > /mnt/dump.sql
umount /mnt && poweroff
# auf dem Host:
pvesnap-recovery pull 9802 # gibt den Pfad aus, z. B. /run/pvesnap/exchange/9802
pvesnap-recovery release 9802 # wieder lösen
pvesnap-recovery destroy 9802 # alles verwerfen
```
**Bei Containern** ist es einfacher: Ein Host-Verzeichnis wird direkt
durchgereicht und erscheint im Container unter `/mnt/pvesnap`. Was der Container
hineinschreibt, liegt sofort auf dem Host — kein Ein- und Aushängen nötig.
```bash
pvesnap-recovery live 100 --exchange ja
pct exec 9100 -- sh -c 'pg_dumpall > /mnt/pvesnap/dump.sql'
ls /var/lib/pvesnap/exchange/9100/
```
Und hier passt auch die Idee mit dem **Netzlaufwerk**: Ist auf dem Host ohnehin
schon eine NFS- oder CIFS-Freigabe eingehängt, lässt sie sich direkt
durchreichen — der Container schreibt dann quasi aufs Netzlaufwerk, obwohl er
selbst kein Netzwerk hat:
```bash
pvesnap-recovery live 100 --exchange-dir /mnt/nfs/dumps
```
Bei virtuellen Maschinen geht das nicht: Ein Host-Verzeichnis lässt sich nicht in
eine VM hineinreichen. Dort bleibt es bei der Austauschplatte.
### An die Konsole kommen
```
https://<node>:8006/?console=kvm&novnc=1&vmid=9802&node=<node>&resize=off&cmd=
```
Diese Adresse gibt `pvesnap-recovery` nach dem Anlegen aus, ebenso
`pvesnap-recovery console <VMID>`. Es ist die ganz normale noVNC-Konsole von
Proxmox — die Maschine taucht auch in der Weboberfläche auf, markiert mit dem Tag
`pvesnap-recovery`. Bei Containern geht zusätzlich `pct enter <VMID>`.
### Wiederherstellung mit Netzwerk
```bash
pvesnap-recovery recover 802 autosnap-g5min-20260731-103800 --newid 9802
```
Hier bleibt alles erhalten, was die Maschine ausmacht: SMBIOS-UUID, `vmgenid`,
MAC-Adressen, bei Containern der Hostname. Für alles im Netz ist sie dieselbe
Maschine — inklusive Lizenzbindungen, AD-Mitgliedschaft und DHCP-Reservierungen.
**Genau deshalb ist sie gefährlich.** `pvesnap-recovery` prüft vorher, ob das
Original läuft, und warnt unmissverständlich. Zwei Maschinen mit derselben MAC
und derselben IP im selben Netz geben Chaos. Das Original also **vorher
stoppen** — oder mit `--net down` starten und die Karte erst zuschalten, wenn
klar ist, dass die Luft rein ist.
### Parameter
| Parameter | Bedeutung |
|---|---|
| `live <VMID> [snapshot]` | abgeschottet starten (ohne Snapshot: der neueste) |
| `recover <VMID> [snapshot]` | mit Netzwerk und gleicher Identität starten |
| `--newid <ID>` | VMID der neuen Maschine (Vorgabe: nächste freie) |
| `--node <name>` | auf welchem Node sie laufen soll |
| `--net none\|down\|on` | keine Karte / Karte ohne Leitung / voll am Netz |
| `--resume` / `--no-resume` | Arbeitsspeicher laden bzw. bewusst kalt starten |
| `--exchange <größe>` | Austauschplatte, z. B. `20G` (Container: `ja` genügt) |
| `--exchange-storage <name>` | Storage dafür (Vorgabe: wie die erste Platte) |
| `--exchange-fs <fs>` | `ext4` (Vorgabe), `ext3`, `xfs`, `vfat`, `ntfs` |
| `--exchange-dir <pfad>` | nur Container: dieses Host-Verzeichnis durchreichen |
| `--memory <MB>`, `--cores <n>` | abweichende Ausstattung (nicht mit `--resume`) |
| `--name <name>` | Name der neuen Maschine |
| `--keep-binds` | durchgereichte Host-Verzeichnisse des Originals übernehmen |
| `--no-start` | nur einrichten, nicht starten |
| `-y`, `--yes` | nicht nachfragen |
| Befehl | Bedeutung |
|---|---|
| `pvesnap-recovery` | ncurses-Oberfläche mit Übersicht und Assistent |
| `list` | vorhandene Wiederherstellungen anzeigen |
| `start` / `stop` | hoch- bzw. herunterfahren |
| `console <VMID>` | noVNC-Adresse ausgeben |
| `pull <VMID>` | Austauschlaufwerk auf den Host holen |
| `release <VMID>` | es wieder lösen |
| `destroy <VMID>` | restlos verwerfen |
### Was beim Verwerfen passiert
`destroy` räumt vollständig auf: Maschine stoppen, Gast samt aller Klone
entfernen, Austauschverzeichnis löschen — und den **Schutz der Quell-Snapshots
wieder aufheben**.
Dieser letzte Punkt ist wichtig: Ceph verlangt für einen Klon, dass der
Quell-Snapshot geschützt ist (`rbd snap protect`), und Proxmox setzt das beim
Klonen selbst. Bliebe der Schutz stehen, könnte die Vorhaltezeit diesen Snapshot
später nicht mehr löschen — im Protokoll stünde dann immer wieder
`snapshot is protected`. Solange eine Wiederherstellung existiert, ist ihr
Quell-Snapshot also bewusst unlöschbar; danach nicht mehr.
Zur Sicherheit fasst `destroy` nur Maschinen an, die den Tag `pvesnap-recovery`
tragen. Eine von Hand angelegte VM lässt sich damit nicht versehentlich löschen.
`uninstall.sh` warnt ebenfalls, wenn noch Wiederherstellungen offen sind.
---
## Aufbau
```
@@ -563,6 +753,8 @@ pvesnap/
tui.py ncurses-Konfigurationseditor
snapfs.py Snapshots einbinden und mounten (rbd/zfs/lvm/qcow2)
explorer.py Zwei-Fenster-Explorer im Terminal
recovery.py Snapshot als Maschine starten (Klone, Konfiguration, Aufräumen)
recovery_ui.py ncurses-Oberfläche und Kommandozeile dazu
web/ Web-Oberfläche zum Herunterladen
server.py HTTP-Server, ZIP im Strom, Zugangsschlüssel
assets.py Stylesheet und HTML-Gerüst