Virtuelle Maschinen eignen sich hervorragend dazu, beispielsweise System-Upgrades zu testen, die immer mit einem gewissen Risiko verbunden sind. So wollten wir testen, ob ein Komplett-Update von CentOS 5 auf 6 möglich ist, eine Prozedur, von der die Release Notes abraten. Der erste Schritt besteht darin, vom laufenden System eine möglichst aktuelle Kopie zu machen. Für diese sogenannte P2V-Migration (Physical-to-Virtual) gibt es einige Möglichkeiten, etwa spezielle Tools aus dem »virt-v2v
«
-Paket [1] oder ein übers Netz angefertigtes Image mit »dd
«
, das aber bei einem laufenden System kaum zu einem konsistenten Ergebnis führen wird. Sauberer lässt sich das mit einem der für Linux verfügbaren Image-Backup-Programme wie Clonezilla [2] oder Partimage [3] erreichen, doch das erfordert, das System herunterzufahren und ein Live-System zu booten.
Zum Zweck des Update-Tests, der keine einhundertprozentige Synchronisierung erforderte, entschieden wir uns dafür, per »rsync
«
die CentOS-Installation auf den Server zu kopieren, der das gastgebende System werden sollte. Auf diese Art lassen sich die Daten nach der ersten vollständigen Kopie problemlos und schnell aktualisieren. Ein Disk-Image für das virtuelle System kann man etwa mit »qemu-img
«
anlegen oder gleich mit »guestfish
«
[4], das auf Wunsch ein Ext3-Dateisystem erzeugt [5]:
guestfish -N fs:ext3
Mit dem Aufruf von Guestfish mit dem neuen Image (»guestfish -a Image
«
) landet man in einer Shell, in der man mit »run
«
erst einmal das System in den Bereitschaftszustand überführt. Danach zeigt »list-filesystems
«
die verfügbaren Partitionen an, die das eingebaute Kommando »mount
«
in Guestfish einbindet. Mit »-i
«
gestartet, macht Guestfish das automatisch.
Die Guestfish-Shell bietet einige eingebaute Tools, mit denen sich Daten vom Host- ins Gastsystem kopieren lassen und umgekehrt, etwa »copy-in
«
, »copy-out
«
, »tar-in
«
und »tar-out
«
[6]. Leider kann die Performance dieser Tools nicht überzeugen, so dauert es schon mal einen ganzen Nachmittag, einige GByte ins Gastsystem zu kopieren.
Die bessere Alternative besteht darin, das Gastsystem per Loopback im Host zu mounten und die Daten direkt im Hostsystem zu kopieren. Dazu muss das Disk-Image des Gastsystems im Raw-Format vorliegen. Es gibt zwar auch Ansätze, etwa Qcow2-Images direkt zu mounten, die aber das Netzwerksubsystem nutzen und deshalb langsamer sind. Doch selbst mit dem potenziellen Umweg, das Image mit »qemu-img convert
«
von Qcow2 nach Raw zu wandeln, spart man insgesamt noch eine Menge Zeit.
Um die im Image enthaltenen Partitionen zu mounten, muss man erst einmal die entsprechenden Offsets vom Dateibeginn ermitteln. Dazu bietet sich das Tool »kpartx
«
an, das mit »-l
«
aufgerufen die Partitionen ausgibt. Mit »-a
«
ausgeführt, legt es die passenden Device-Mapper-Dateien an:
kpartx -l ff-clone7.img loop0p1 : 0 20969472 /dev/loop0 2048 kpartx -a ff-clone7.img kpartx -l ff-clone7.img loop0p1 : 0 20969472 /dev/loop0 2048
Man sieht die Device-Mapper-Dateien, hier nur »loop0p1
«
, mit denen sich die repräsentierten Partitionen mounten lassen:
mount /dev/mapper/loop0p1 /mnt/
Nun lassen sich die Dateien mit den gewohnten Tools wie »tar
«
,»cp
«
oder »rsync
«
auf die gemountete virtuelle Disk kopieren. Hierbei sollte man darauf achten, die passenden Optionen zu verwenden, um die Dateirechte und -inhaber zu konservieren, beispielsweise mit »rsync -az
«
. Gegebenenfalls, etwa beim Einsatz von SELinux, sollte man auch die Extended Attributes des Dateisystems nicht vergessen. Rsync kennt dazu den Schalter »-X
«
, Tar bietet für diese Zwecke »--selinux
«
und »--xattrs
«
.
Später bindet »umount
«
das Dateisystem wieder aus, »kpartx -d
«
löscht die Device-Mapper-Dateien. Weil das alles auf Dateiebene geschieht (statt etwa mit »dd
«
die Platte komplett zu klonen), fehlt dem virtuellen System noch der Bootloader im Master Boot Record. Um ihn auf die Platte zu bekommen, gibt es wiederum mehrere Wege. So kann eine existierende virtuelle Maschine dazu verwendet werden, die neue virtuelle Festplatte zu mounten und sich mit »chroot
«
in das neue System zu versetzen. Ein Aufruf von »grub-install
«
mit dem richtigen Device-Namen installiert Grub dann im MBR der neuen virtuellen Platte. Auch Guestfish bietet mittlerweile den Befehl »guestfs_grub_install
«
, mit dem sich die Operation bewerkstelligen lassen sollte.
Beim Test führte der Versuch, Grub zu installieren, jedenfalls zur Fehlermeldung »Error 2: unknown file or directory type
«
, deren Ursache schwer ausfindig zu machen war. Schließlich stellte sich heraus, dass Guestfish (beziehungsweise die von ihm verwendeten »e2fsprogs
«
der Version 1.40.5 und neuer) beim Anlegen des Ext3-Dateisystems als Inode-Größe 256 Bytes wählt, was nicht mit älteren Versionen von Grub kompatibel ist. Leider gibt es keine Möglichkeit, die Inode-Größe des existierenden Dateisystems umzuwandeln, sodass der einzig gangbare Weg darin besteht, ein neues Dateisystem mit der älteren Inode-Größe von 128 Bytes anzulegen und alle Systemdaten dorthin zu kopieren. Der dazu nötige Schalter von »mkfs.ext*
«
lautet »-I Inode-Größe
«
.
Sind diese Probleme gelöst, wird man mit einem bootenden virtuellen Klon der realen Maschine belohnt. Kleine Abweichungen kann man normalerweise zur Laufzeit in der VM noch per »rsync
«
korrigieren.