8. September 2018

Virtualisierung mit KVM auf Debian Stretch 9.5

KVM on Debian

Guten Morgen,

vor einer Weile habe ich auf Ebay ein nettes kleines Micro-ITX-Board mit Pentium G4400 geschossen. In ein geräumiges Gehäuse gepackt, ein paar Festplatten dazu und schon haben wir einen hübschen, effizienten Heimserver. Was könnte man damit bloß anstellen? Virtualisierung!

Einleitung

Vieles in diesem Artikel beschriebene lässt sich auf diverse Linux-Distributionen anwenden. Da es aber einige Unterschiede, bspw. beim Paket-Management gibt, werde ich mich hier auf Debian fokussieren. Entsprechend werden Sie bevor wir beginnen ein Debian 9.5 auf Ihrem System installieren müssen. Sollten Sie dabei Unterstützung brauchen, kann ich das Debian Handbuch empfehlen.

Wenn wir davon reden, eine VM auf KVM zu betreiben, meinen wir meistens eine große Sammlung von Programmen, die größtenteils gar nicht zu KVM gehören:

  • KVM ist die Kernel Virtual Machine, die die Virtualisierungsschicht des Linux Kernels darstellt.
  • qemu ist ein Emulator, der dank seines modularen Aufbaus diverse Hardwareplattformen emulieren kann. In unserem fall, wird die Hardware unserer virtuellen Maschine "emuliert".
  • libvirt ist eine API, die auf qemu und KVM aufsetzt. Sie beinhaltet einen Dienst und verschiedene Werkzeuge, die die Verwaltung von VMs deutlich einfacher machen.
  • virsh ist ein Kommandozeilenprogramm, mit dem libvirt-Instanzen gemanaged werden (z.B. Starten oder Stoppen von VMs).
  • virt-install ist ein Kommandozeilenprogramm, mit dem VMs für libvirt konfiguriert werden können.
  • virt-manager ist ein GUI-Client, der auf libvirt aufbaut. Er erlaubt die Verwaltung von VMs mit einer grafischen Oberfläche. Da ich lieber die Kommandozeilentools verwenden möchte, wird virt-manager nicht Teil dieses Artikels sein.

Ich habe festgestellt, dass viele Tutorials zu KVM und libvirt etwas unklar sind, insbesondere hinsichtlich Benutzern und Zugriffsrechten. Daher möchte ich hier einige Grundlagen abhandeln.

Libvirt kennt zwei verschiedene Betriebsmodi, die anhand Ihrer URL differenziert werden können: mit der URL qemu:///system verbindet man sich zum libvirt-Service (libvirtd), einer systemweiten Session, die üblicherweise mit Root-Berechtigungen läuft. Das ist die Session, mit der sich Tools wie virt-manager normalerweise verbinden. Da libvirtd als Root läuft, hat es alle notwendigen Rechte um auf Netzwerkbrücken, Block-Devies, usw. zuzugreifen. Virtuelle Festplatten, VM-Konfigurationen, etc. werden standardmäßig in /var/lib/libvirt abgelegt. Übrigens können nur VMs in qemu:///system beim Systemstart automatisch hochgefahren werden.

Verwendet man die URL qemu:///session, wird eine neue libvirt-Instanz für den aktuellen Benutzer erstellt. Es ist möglich, mehrere Benutzer-Instanzen parallel auf einem System zu starten. Die Berechtigungen der benutzerspezifischen Instanz richten sich nach dem Benutzer, der die Instanz gestartet hat. VMs, Festplatten, etc. werden im Benutzerverzeichnis gespeichert, sodass hier keine erweiterten Zugriffsrechte notwendig sind. Allerdings ist eine benutzerspezifische Session nicht in der Lage Block-Devices zu verwenden, ohne dass udev-Regeln eingerichtet werden, die dem Benutzer Zugriff auf /dev/[blockdevice] erlauben. Auch die Verwendung von Netzwerkbrücken braucht unter Umständen zusätzliche Zugriffsrechte.

Um herauszufinden, mit welcher Session man gerade verbunden ist, kann man virsh uri ausführen. Die Standard-Session ist normalerweise qemu:///session. Um das zu Ändern, kann man die folgende Umgebungsvariable in der .bashrc einfügen und sich anschließend aus und wieder einloggen (ansonsten muss man --connect qemu:///system an alle virsh und virt-install Befehle anhängen).

export LIBVIRT_DEFAULT_URI="qemu:///system"

Da qemu:///system im Allgemeinen als der Standardmodus angesehen wird, werde ich diese Session verwenden.

Einrichtung

Beginnen wir also mit der Installation der benötigten Pakete:

sudo apt install qemu-kvm libvirt-clients libvirt-daemon-system virtinst

Üblicherweise möchte man in den VMs auf das Netzwerk zugreifen können. Hierzu ist eine Netzwerkbrücke anzulegen, die die Verbindung zum physikalischen Netzwerkadapter herstellt. Passen Sie die Netzwerkkonfiguration folgendermaßen an:

nano /etc/network/interfaces
# The primary network interface
# DHCP muss am physikalischen Adapter deaktiviert werden
allow-hotplug eth0
iface eth0 inet dhcp
iface eth0 inet  manual
iface eth0 inet6 manual

# Virtual network bridge
auto vmbr0
iface vmbr0 inet dhcp
    bridge_ports eth0    # Ersetzen Sie eth0 durch Ihren Adapter
    bridge_stp off
    bridge_maxwait 0
    bridge_fd 0

Starten Sie das System anschließen neu.

Die erste VM erstellen

Mit der Vorbereitung aus dem Weg, können wir nun ein Boot-Image für unsere erste VM herunterladen. Ich werde ein Debian 9.5 netinstall-Image verwenden:

sudo wget "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-9.5.0-amd64-netinst.iso" -O "/var/lib/libvirt/boot/debian-9.5.iso"

Erstellen wir also unsere erste VM:

virt-install --virt-type kvm --name debian9 --memory 512 --cdrom /var/lib/libvirt/boot/debian-9.5.iso --disk size=10 --network bridge=vmbr0 --os-variant debian9

Sie sollten in etwa folgende Ausgabe sehen:

WARNING  Graphics requested but DISPLAY is not set. Not running virt-viewer.
WARNING No console to launch for the guest, defaulting to --wait -1
Starting install...
Allocating 'debian9.qcow2' | 10 GB 00:00:00
Creating domain... | 0 B 00:00:01
Domain installation still in progress. Waiting for installation to complete.

Hier eine Erklärung des obigen Kommandos:

--virt-type kvm: Die VM verwendet KVM

--name debian9: Die VM wird "debian9" genannt. Dieser Name wird angezeigt, wenn man virsh list aufruft. Er wird auch genutzt, wenn man die VM editieren möchte: virsh edit debian9. Beachten Sie, dass es sich NICHT um den Hostnamen der VM handelt.

--memory 512: Wir wollen unserer VM 512 MB RAM geben.

--cdrom /var/...: Das ISO-Image, von dem die VM gebootet werden soll.

--disk size=10: Erstellt neben der VM eine virtuelle Festplatte mit 10 GB Größe. Die resultierende Datei wird in /var/lib/libvirt/images abgelegt und heißt wie die VM.

--network bridge=vmbr0: The VM benutzt unsere zuvor eingerichtete Netzwerkbrücke.

--os-variant debian9: Wir werden in der VM Debian 9 laufen lassen. Dieser Schalter erlaubt verschiedene betriebssystemspezifische Optimierungen. Um eine Liste der möglichen Werte zu erhalten, führen Sie osinfo-query os aus (Sie müssen möglicherweise libosinfo-bin installieren). Der häufig genannte Befehl virt-install --os-variant list funktioniert nicht mehr.

Mit der VM Verbinden

Sie können sich jetzt mit Ihrer VM verbinden um... moment, Sie wissen nicht, wir man sich zu der VM verbinden soll. Hmm... stoppen wir zunächst einmal die Domäneninstallation mittels Ctrl+C. Wir sollten auch die halbfertige VM aufräumen:

virsh destroy debian9
virsh undefine debian9
sudo rm /var/lib/libvirt/images/debian9.qcow2

Es gibt zwei Möglichkeiten, eine VM so auf einem Headless-Server zu initialisieren, dass man ein System installieren kann.

1. Man kann die Konsole der VM im eigenen Terminal zur Verfügung stellen. Allerdings ist diese Funktion Betriebssystemabhängig und steht bspw. in Windows-VVMs nicht zur Verfügung. Zudem gibt es einige nervige Einschränkungen: Das Argument -x kann nicht mit --cdrom kombiniert werden. Früher konnte man ein ISO-Image mit dem Argument -l einbinden, allerdings funktioniert das heute nicht mehr. Stattdessen muss ein gültiger Installationsbaum bereitgestellt werden, was ich nur mit einem Ubuntu-Netinstall-Image geschafft habe:

virt-install --virt-type kvm --name ubuntu --memory 512 -l http://archive.ubuntu.com/ubuntu/dists/bionic/main/installer-amd64/ --disk size=10 --network bridge=vmbr0 --os-variant ubuntu17.10 -x='console=tty0 console=ttyS0,115200n8' --nographics

2. Man macht den Gast über VNC erreichbar. Dies ist die besser Lösung, da sie unabhängig vom Gast-Betriebssystem funktioniert. Außerdem kann eine Desktopumgebung in der VM verwendet werden.

virt-install --virt-type kvm --name debian9 --memory 512 --cdrom /var/lib/libvirt/boot/debian-9.5.iso --disk size=10 --network bridge=vmbr0 --os-variant debian9 --graphics vnc,listen=0.0.0.0 --noautoconsole

Den VNC-Port einer VM kann man ganz einfach herausfinden:

virsh vncdisplay debian9

Starten Sie also ihren VNC-Viewer, geben Sie IP und Port ein und voilà - eine VM mit KVM auf Debian Stretch!