Der Xhyve-Hypervisor erlaubt es, Linux-Distributionen auf OS X zu betreiben.
Neben den etablierten Virtualisierungslösungen wie VMware Fusion und VirtualBox gibt es seit einiger Zeit mit Xhyve einen Hypervisor für OS X, der als freie Software unter der BSD-Lizenz verfügbar ist. Es handelt sich um einen Port des von FreeBSD entwickelten Hypervisor Bhyve. Ein wesentlicher Unterschied besteht darin, dass Xhyve auf dem in OS X 10.10 "Yosemite" eingeführten Hypervisor-Framework basiert, das eine API für die Programmierung von Hypervisor-Systemen ist. Damit lässt sich Virtualisierungssoftware über eine definierte API programmieren, ohne eigenen Kernel-Code für OS X schreiben zu müssen.
Am einfachsten lässt sich Xhyve über das Paketmanagementsystem Homebrew installieren. Damit genügt ein Aufruf von
brew install --HEAD xhyve
um den Hypervisor zu installieren.
Nun wird es etwas schwieriger, denn in Xhyve gibt es bisher keine Firmware, die beim Booten eines Systems helfen könnte. Wegen der Beschränkungen des Hypervisor-Framework-Modells entspricht jeder virtuellen Maschine ein OS-X-Prozess, sodass die Xhyve-Entwickler nicht die Firmware-Pakete von Bhyve übernehmen konnten. Stattdessen verwenden sie die Linux-Kexec-Schnittstelle, um einen Linux-Kernel mit einer initialen RAM-Disk zu booten.
Also müssen vor der Installation eines Linux-Systems der Kernel und die Initramdisk vom Installationsmedium extrahiert und als Files abgespeichert werden. Mit einer aktuellen CentOS-Distribution geht das beispielsweise so:
mkdir centos dd if=/dev/zero bs=2k count=1 of=centos.iso dd if=CentOS-7-x86_64-Minimal.iso bs=2k skip=1 >> centos.iso hdiutil attach centos.iso cp /Volumes/CentOS\ 7\ x86_64/isolinux/vmlinuz centos cp /Volumes/CentOS\ 7\ x86_64/isolinux/initrd.img centos diskutil unmount /Volumes/CentOS\ 7\ x86_64/ rm centos.iso
Ein leeres Festplatten-Image zur Installation des Linux-Systems erzeugen Sie so:
dd if=/dev/zero of=centos/hdd.img bs=1g count=6
Die Installation starten Sie nun mit einem Shellskript wie dem folgenden (analog zu http://www.pagetable.com/?p=831):
KERNEL="centos/vmlinuz" INITRD="centos/initrd.img" CMDLINE="earlyprintk=serial console=ttyS0 acpi=off" MEM="-m 1G" NET="-s 2:0,virtio-net" IMG_CD="-s 3,ahci-cd,CentOS-7-x86_64-Minimal.iso" IMG_HDD="-s 4,virtio-blk,centos/hdd.img" PCI_DEV="-s 0:0,hostbridge -s 31,lpc" LPC_DEV="-l com1,stdio" xhyve $MEM $SMP $PCI_DEV $LPC_DEV $NET $IMG_CD $IMG_HDD -f kexec,$KERNEL,$INITRD,"$CMDLINE"
Das Skript müssen Sie mit "sudo" starten, weil es Root-Rechte braucht, um die Netzwerk-Devices anzulegen. Wenn der CentOS-Installer läuft, gehen sie alle nötigen Menüpunkte durch (Installation source, Installation Destination, Root password, Timezone settings) und starten mit "b" die Installation.
Am Ende wird es noch einmal etwas tricky. Nun müssen auch der installierte Kernel und die Initramdisk aus der VM auf die Mac-Festplatte kopiert werden. Am einfachsten ist es wohl, die beiden Dateien von einer anderen Centos-Installation mit der gleichen Version zu nehmen und auf den Mac zu kopieren. Eine Shell im Anaconda-Installer zu öffnen, scheiterte zumindest auf einem Mac-Laptop daran, die nötige Tastenkombination zu verwenden, die bereits mit Funktionen von OS X belegt war. Also bleibt nur der etwas kompliziertere Weg, noch einmal den Installationskernel zu booten, aber dabei auf das Installations-ISO zu verzichten. In der sich anschließend öffnenden Rettungs-Shell lässt sich die Boot-Partition mounten.
Eine weitere Hürde ergibt sich dadurch, dass alle Programme, die sich dazu eignen, Dateien zu übertragen, auf einer anderen Partition befinden. Der Weg zum Erfolg ist also: das Root-Dateisystem mounten, das Device-Dateisystem "bind"-mounten (sonst gibt es später keine Device Files), einen Chroot im Root-Dateisystem starten, das Boot-Dateisystem mounten, das Netzwerk konfigurieren und schließlich Kernel und Initrd auf das Host-Dateisystem des Mac kopieren, etwa mit "scp". Im Einzelnen sieht das etwa so aus (mit einem LVM-Volume als Root-Partition):
mkdir /mnt lvm_scan mount /dev/centos/root /mnt mount -o bind /dev/ /mnt/dev mount -o bind /proc/ /mnt/proc chroot /mnt mount /dev/vda1 /boot ifup eth0 scp /boot/vmlinuz-3.10.0-327.10.1.el7.x86_64 oliver@192.168.64.1:centos scp /boot/initramfs-3.10.0-327.10.1.el7.x86_64.img oliver@192.168.64.1:centos umount /boot exit umount /mnt/dev/ umount /mnt/proc/ umount /mnt halt
Liegen Kernel und Initramdisk nun auf dem Mac-Dateisystem (im Verzeichis "centos"), lässt sich das installierte CentOS mit einem Skript analog zu dem obigen booten:
KERNEL="centos/vmlinuz-3.10.0-327.10.1.el7.x86_64" INITRD="centos/initramfs-3.10.0-327.10.1.el7.x86_64.img" CMDLINE="earlyprintk=serial console=ttyS0 acpi=off root=/dev/centos/root ro" MEM="-m 1G" NET="-s 2:0,virtio-net" IMG_HDD="-s 4,virtio-blk,hdd.img" PCI_DEV="-s 0:0,hostbridge -s 31,lpc" LPC_DEV="-l com1,stdio" xhyve $MEM $PCI_DEV $LPC_DEV $NET $IMG_CD $IMG_HDD -f kexec,$KERNEL,$INITRD,"$CMDLINE
Beachten Sie hier das verwendete Root-Device in der Variablen CMDLINE. Hier zeigt der Device Node "/dev/centos/root" auf das zur Installation verwendete LVM-Volume. Bei einer Installation auf einer gewöhnlichen Partition steht hier beispielsweise "/dev/vda2" oder ähnliches.
Etwas einfacher lässt sich beispielsweise Ubuntu installieren, das es am Ende der Installation erlaubt, ohne Tastenakrobatik eine Shell zu starten. Dann erschöpft sich der Aufwand darin, Kernel und Initrd von dort aus auf den Host zu kopieren. (Interessant wäre es auch, Libguestfs auf dem Mac zu verwenden, um "offline" über das Festplatten-Image an die beiden Dateien zu kommen).
Fertig für Prime Time ist Xhyve noch nicht, aber es ist ein interessantes Projekt, das es immerhin schon ermöglicht, Linux-VMs mit wenig Ressourcen auf OS X zu betreiben. Mit Firmware-Support wäre Xhyve bereits wesentlich einfacher zu verwenden. Wie Docker kürzlich angekündigt hat, läuft die Container-Software nun "nativ" auf OS X und verwendet dazu auch Xhyve. Mit dem Support einer Firma mit entsprechenden Ressourcen ist damit zu rechnen, dass diverse Verbesserungen in Xhyve einfließen.
Mit einem einzigen Befehl lässt sich unter Linux eine virtuelle Maschine installieren.