Backup der VMs im laufenden Betrieb mit libvirt

Backup der VMs im laufenden Betrieb mit libvirt

Mit libvirt bzw. deren Kommandozeilen-Interface virsh kann ein Backup der VMs im laufenden Betrieb durchgeführt werden. Das nachfolgende Script stellt ein Grundgerüst, angeregt durch einen Artikel von Christian Rößner, für ein Backup nach der folgenden Methode zur Verfügung:

Es wird zuerst ein Snapshot aller Volumes einer VM angelegt. Dadurch besteht jedes Volume aus (mindestens) zwei Dateien: eine Datei mit den originalen Daten und eine zweite Datei, welche alle Änderungen gegenüber dem Originalvolume ab dem Erstellen des Snapshots enthält. Das Originalvolume wird bei aktivem Snapshot nicht mehr beschrieben, es kann nun problemlos gesichert werden. Zum Kopieren kann “cp -f –sparse=always …” oder, sofern verfügbar, “rsync –sparse …” zum Einsatz kommen. Beide Kommandos behandeln freien Platz in den Volumes optimal, rsync ist jedoch um einiges schneller, wenn im Backup-Verzeichnis bereits vom vorherigen Backup schon die gleiche Datei vorhanden ist, da dann nur die Änderungen kopiert werden. Anschließend werden mit einem sogenannten Blockcommit die im Snapshot als Änderungen geschriebene Blöcke in das Originalvolume wieder eingearbeitet. Das alles kann im laufenden Betrieb vom Host der VMs aus durchgeführt werden.

Update vom 06.09.2021: Der Server mit dem Git-Repository existiert nicht mehr. Interessierte können sich ein Archiv des letzten Stand des Projekts herunterladen.

Update: mittlerweile handelt es sich hier um die 3. Version des Scriptes, welches nun auch korrekt mit mehreren Volumes einer VM umgehen kann. Fälschlicherweise hatte ich angenommen, dass “snapshot-create-as” mit entsprechender “–diskspec” nur einen Snapshot des angegebenen Volumes erzeugt, was aber nicht der Fall ist. “snapshot-create-as” erzeugt in einem Schritt ein Snapshot aller Volumes der VM. Obiges Script berücksichtigt das nun.

Update 2: Skript Version 4. Das Skript wurde erweitert, um auch VM-Festplatten im qcow2-Format verarbeiten zu können. Ebenfalls werden die Images jeder VM in einem eigenen Verzeichnis gesichert. VM-Images mit gleichem Namen aus unterschiedlichen Speicherpools überschreiben sich somit nicht mehr. Vielen Dank an Sylvia für die Hinweise und Jan für die Lösung!

Am Anfang des Skripts wird festgelegt, wo die Volumes und die XML-Definition der VMs zu finden sind. Das in Zeile 5 angegebene Verzeichnis ist das Ziel der Backups.

Ebenfalls am Anfang des Skripts ist eine Sicherung eingebaut, die das mehrfache gleichzeitige Ausführen des Skripts verhindert.

Für alle laufenden VMs wird ausgeführt:

  • virsh snapshot-create-as …: erstellen eines Snapshots aller Volumes der VM
  • rsync –sparse …: kopieren der originalen Volumes ins Backupverzeichnis
  • virsh blockcommit …: einarbeiten der Änderungen ins originale Volume
  • löschen der Overlay-Images

Nach dem Abarbeiten aller Volumes wird das XML-Definitionsfile der jeweiligen VM ebenfalls ins Backup-Verzeichnis kopiert.

Fallstricke

virsh blockcommit … –delete

“virsh blockcommit –help” zeigt eine Option “–delete” an, welche das eingearbeitete Änderungsfile praktischerweise gleich löschen würde. Leider ist diese Option bisher nicht im Sourcecode eingearbeitet und erzeugt nur die Fehlermeldung: “error: unsupported flags (0x2) in function qemuDomainBlockCommit”. Ein manuelles Löschen ist notwendig.

virsh snapshot-create-as … –quiesce

Für die Option “–quiesce” ist es notwenig, dass auf dem Gast der sogenannte “qemu-guest-agent” installiert ist. Dieser kann Befehle vom Host-System entgegen nehmen und wie in diesem Fall, das Dateisystem in einen konsistenten Zustand versetzen.

qemu-guest-agent erforderlich

Der für die Option “–quiesce” erforderliche Dienst “qemu-guest-agent” benötigt einen Channel in der VM-Definition, welcher mit dem von mir eingesetzten virt-manager in der Version 0.9.5 leider nicht angelegt werden kann. Man muss vielmehr auf dem VM-Host mit dem Kommando “virsh edit ” die XML-Definition der VM direkt bearbeiten und innerhalb von “” folgenden Schnipsel einfügen:

<channel type='unix'>
  <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/<vmname>.qemu.guest_agent.0'/>
  <target type='virtio' name='org.qemu.guest_agent.0'/>
  <address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>

ist entsprechend zu ersetzen. Anschließend muss die VM heruntergefahren und wieder gestartet werden. Ein einfacher Reboot reicht nicht aus! Danach sollte der Dienst “qemu-guest-agent” erfolgreich innerhalb der VM gestartet werden können.

Cron

Sollte obiges Script per Cron eingesetzt werden, so muss es nach bisherigen Tests unter dem Benutzer root laufen. Der Benutzer libvirt-quemu, wie er unter Debian-Betriebssystemben beim Installieren von libvirt eingerichtet wird, hat keine Berechtigung, mit den KVM/QEMU-Systemdiensten zu kommunizieren.

Fazit

Ich selbst setzte seit kurzem mehrere kleine VMs für eigene Dienste ein und benutze ein Script nach obigem Muster für das Backup der VMs. Es kann einfach an die eigenen Bedürfnisse angepasst werden. Wesentlich sind die Befehle zum Auflisten der VMs und die Befehle zum Auflisten der Volumes der jeweiligen VM. Für jede VM werden die Volumes aufgelistet, ein Snapshot aller Volumes angelegt und anschließend jedes Volume gesichert. Danach werden die Snapshots wieder in die Original-Volumes eingearbeitet und der Admin kann dann sicher eins: ruhiger schlafen.

Backup  KVM  libvirt  Linux  OSS 

Siehe auch