Product SiteDocumentation Site

12.2. Virtualisierung

Virtualisierung ist einer der größten Fortschritte der letzten Jahre im Computerwesen. Der Ausdruck umfasst verschiedene Abstraktionen und Techniken der Simulation virtueller Rechner mit unterschiedlichen Graden der Unabhängigkeit von der tatsächlichen Hardware. Dabei kann ein physischer Server mehrere Systeme beherbergen, die gleichzeitig und getrennt voneinander funktionieren. Es gibt zahlreiche Anwendungen, und sie rühren häufig von dieser Trennung her: zum Beispiel Testumgebungen mit unterschiedlichen Konfigurationen, oder die getrennte Unterbringung von Diensten auf unterschiedlichen virtuellen Rechnern aus Sicherheitsgründen.
Es gibt zahlreiche Virtualisierungslösungen, jede mit ihren eigenen Vor- und Nachteilen. Dieses Buch konzentriert sich auf Xen, LXC und KVM, es gibt jedoch weitere bemerkenswerte Umsetzungen einschließlich der folgenden:

12.2.1. Xen

Xen ist eine Lösung zur „Paravirtualisierung“. Es führt zwischen der Hardware und den darüber liegenden Systemen eine dünne Abstraktionsschicht ein, die „Hypervisor“ genannt wird. Diese agiert als Schiedsrichter, der den Zugang der virtuellen Rechner zur Hardware kontrolliert. Er wickelt jedoch nur einige der Instruktionen ab, der Rest wird direkt von der Hardware im Auftrag des Systems ausgeführt. Der Hauptvorteil liegt darin, dass die Leistung nicht abnimmt und die Systeme so fast dieselbe Geschwindigkeit wie bei direkter Ausführung erreichen. Die Kehrseite besteht darin, dass die Kernel der Betriebssysteme, die man mit einem Xen-Hypervisor verwenden möchte, angepasst werden müssen, um mit Xen zu funktionieren.
Lassen Sie uns einige Zeit bei den Ausdrücken bleiben. Der Hypervisor ist die unterste Schicht, die direkt auf der Hardware läuft, sogar unterhalb des Kernels. Dieser Hypervisor kann die übrige Software auf verschiedene Domains aufteilen, die man als ebenso viele virtuelle Rechner ansehen kann. Eine dieser Domains (die erste, die gestartet wird) wird als dom0 bezeichnet und spielt eine besondere Rolle, da nur diese Domain den Hypervisor und die Ausführung der übrigen Domains kontrollieren kann. Diese übrigen Domains werden domU genannt. Mit anderen Worten und aus der Sicht des Benutzers entspricht dom0 dem „Host“ bei anderen Virtualisierungssystemen, während eine domU als „Gast“ angesehen werden kann.
Zur Verwendung von Xen unter Debian sind drei Komponenten erforderlich:
  • Der Hypervisor an sich. Je nach verfügbarer Hardware ist das entsprechende Paket entweder xen-hypervisor-4.4-amd64, xen-hypervisor-4.4-armhf oder xen-hypervisor-4.4-arm64.
  • Ein Kernel, der auf diesem Hypervisor läuft. Jeder jüngere Kernel als 3.0 läuft, einschließlich der Version 3.16 in Jessie.
  • Die i386-Architektur erfordert zudem eine Standardbibliothek mit passenden Patches, um Xen nutzen zu können; diese befindet sich im Paket libc6-xen.
Um den Aufwand der manuellen Auswahl dieser Komponenten zu vermeiden, stehen komfortablerweise einige fertige Pakete bereit (wie zum Beispiel xen-linux-system-amd64); sie alle installieren eine als gut bekannte Kombination aus passendem Hypervisor und Kernelpaketen. Der Hypervisor bringt zudem das Paket xen-utils-4.4 mit sich, das Hilfsprogramme zur Steuerung des Hypervisors von dom0 aus enthält. Dieses wiederum bringt die passende Standardbibliothek mit sich. Während der Installation all dieser Komponenten erstellen Konfigurationsskripten außerdem einen neuen Eintrag im Menü des Grub Boot-Loaders, mit dem der ausgewählte Kernel in einer Xen dom0 gestartet wird. Man beachte jedoch, dass dieser Eintrag gewöhnlich nicht zuoberst in der Liste steht und deshalb nicht standardmäßig ausgewählt wird. Falls dies nicht das erwünschte Verhalten ist, kann es mit folgenden Befehlen verändert werden:
# mv /etc/grub.d/20_linux_xen /etc/grub.d/09_linux_xen
# update-grub
Nachdem diese Voraussetzungen installiert sind, besteht der nächste Schritt darin, das Verhalten von dom0 selbst zu testen; hierzu gehört ein Neustart des Hypervisors und des Xen-Kernels. Das System sollte auf normale Art hochfahren mit einigen zusätzlichen Meldungen auf dem Terminal während der frühen Initialisierungsschritte.
Jetzt ist es an der Zeit, unter Verwendung der Hilfsprogramme aus xen-tools tatsächlich brauchbare Systeme auf dem domU-System zu installieren. Dieses Paket stellt den Befehl xen-create-image bereit, der die Aufgabe weitgehend automatisiert. Der einzig zwingend notwendige Parameter ist --hostname, der domU einen Namen gibt. Andere Optionen sind zwar ebenfalls wichtig, können aber in der Konfigurationsdatei /etc/xen-tools/xen-tools.conf gespeichert werden, und ihr Fehlen in der Befehlszeile führt nicht zu einer Fehlermeldung. Es ist daher wichtig, entweder vor der Erstellung von Abbildern den Inhalt dieser Datei zu überprüfen oder beim Aufruf des Befehls xen-create-image zusätzliche Parameter zu verwenden. Zu den wichtigen und beachtenswerten Parametern gehören folgende:
  • --memory, um den Umfang an RAM festzulegen, den das neu erstellte System nutzen kann;
  • --size und --swap, um die Größe der „virtuellen Platten“ zu definieren, die der domU zur Verfügung stehen;
  • --debootstrap, um zu veranlassen, dass das neue System mit debootstrap installiert wird; in diesem Fall wird meistens auch die Option --dist verwendet (mit dem Namen einer Distribution wie zum Beispiel jessie).
  • --dhcp legt fest, dass die Netzwerkkonfiguration der domU durch DHCP besorgt wird, während --ip die Benennung einer statischen IP-Adresse ermöglicht.
  • Schließlich muss noch eine Speichermethode für die zu erstellenden Abbilder (diejenigen, die von der domU aus als Festplatten gesehen werden) gewählt werden. Die einfachste Methode besteht darin, mit der Option --dir auf der dom0 eine Datei für jedes Gerät zu erstellen, das der domU zur Verfügung stehen soll. Für Systeme, die LVM verwenden, besteht die Alternative darin, die Option --lvm zu nutzen, gefolgt von dem Namen einer Volume-Gruppe; xen-create-image erstellt dann ein neues logisches Volume innerhalb dieser Gruppe, und dieses logische Volume wird der domU als Festplatte zur Verfügung gestellt.
Nachdem diese Entscheidungen getroffen sind, können wir das Abbild der zukünftigen Xen-domU erstellen:
# xen-create-image --hostname testxen --dhcp --dir /srv/testxen --size=2G --dist=jessie --role=udev

[...]
General Information
--------------------
Hostname       :  testxen
Distribution   :  jessie
Mirror         :  http://ftp.debian.org/debian/
Partitions     :  swap            128Mb (swap)
                  /               2G    (ext3)
Image type     :  sparse
Memory size    :  128Mb
Kernel path    :  /boot/vmlinuz-3.16.0-4-amd64
Initrd path    :  /boot/initrd.img-3.16.0-4-amd64
[...]
Logfile produced at:
         /var/log/xen-tools/testxen.log

Installation Summary
---------------------
Hostname        :  testxen
Distribution    :  jessie
MAC Address     :  00:16:3E:8E:67:5C
IP-Address(es)  :  dynamic
RSA Fingerprint :  0a:6e:71:98:95:46:64:ec:80:37:63:18:73:04:dd:2b
Root Password   :  adaX2jyRHNuWm8BDJS7PcEJ
Wir haben jetzt einen virtuellen Rechner, er läuft zur Zeit jedoch nicht (und belegt daher lediglich Platz auf der Festplatte der dom0). Wir können selbstverständlich weitere Abbilder erstellen, möglicherweise mit anderen Parametern.
Bevor wir diese virtuellen Rechner starten, müssen wir festlegen, wie wir auf sie zugreifen werden. Sie können natürlich als eigenständige Rechner angesehen werden, auf die nur über ihre jeweilige Systemkonsole zugegriffen wird, dies entspricht jedoch nur selten dem Nutzungsmuster. Meistens wird eine domU als entfernter Server angesehen, auf den nur über ein Netzwerk zugegriffen wird. Es wäre jedoch ziemlich umständlich, für jede domU eine Netzwerkkarte hinzuzufügen. Deshalb ist es möglich, mit Xen virtuelle Schnittstellen zu erstellen, die von jeder Domain gesehen und auf übliche Weise benutzt werden können. Man beachte, dass diese Karten, obwohl sie virtuell sind, nur von Nutzen sind, wenn sie mit einem Netzwerk verbunden sind, selbst wenn dieses virtuell ist. Xen bietet zu diesem Zweck mehrere Netzwerkmodelle:
  • Das einfachste Modell ist das bridge-Modell; alle eth0-Netzwerkkarten (sowohl in der dom0 als auch in den domU-Systemen) verhalten sich so, als wären sie direkt an einen Ethernet-Switch angeschlossen.
  • Dann kommt das routing-Modell, bei dem dom0 als Router agiert, der zwischen den domU-Systemen und dem (physischen) externen Netzwerk steht.
  • Schließlich befindet sich im NAT-Modell die dom0 ebenfalls zwischen den domU-Systemen und dem übrigen Netzwerk, jedoch sind die domU-Systeme von außen nicht direkt zugänglich, sondern der Datenverkehr wird auf der dom0 einer „Network Address Translation“ unterworfen.
Zu diesen drei Netzknoten gehören eine Reihe von Schnittstellen mit ungewöhnlichen Bezeichnungen, wie zum Beispiel vif*, veth*, peth* und xenbr0. Der Xen-Hypervisor ordnet sie gemäß dem an, was auch immer als Layout festgelegt worden ist, unter der Kontrolle der Hilfsprogramme auf der Anwenderebene. Da die NAT- und Routing-Modelle besonderen Fällen vorbehalten sind, beschäftigen wir uns hier nur mit dem Bridging-Modell.
Die Standardkonfiguration der Xen-Pakete verändert die systemweite Netzwerk-Konfiguration nicht. Jedoch ist der xend-Daemon so konfiguriert, dass er virtuelle Netzwerkschnittstellen in eine bereits bestehende Netzwerkbrücke integriert (wobei xenbr0 Vorrang erhält, falls es mehrere solcher Brücken gibt). Wir müssen daher eine Brücke in /etc/network/interfaces einrichten (wozu das Paket bridge-utils installiert werden muss, weshalb es vom Paket xen-utils-4.4 empfohlen wird), um den bestehenden eth0-Eintrag zu ersetzen:
auto xenbr0
iface xenbr0 inet dhcp
    bridge_ports eth0
    bridge_maxwait 0
Nach einem Neustart, um sicherzustellen, dass die Brücke automatisch erstellt wird, können wir jetzt die domU mit den Xen-Steuerprogrammen starten, insbesondere mit dem Befehl xl. Mit diesem Befehl ist es möglich, Verschiedenes mit den Domains zu machen, unter anderem sie aufzulisten und sie zu starten oder zu beenden.
# xl list
Name                                        ID   Mem VCPUs      State   Time(s)
Domain-0                                     0   463     1     r-----      9.8
# xl create /etc/xen/testxen.cfg
Parsing config from /etc/xen/testxen.cfg
# xl list
Name                                        ID   Mem VCPUs      State   Time(s)
Domain-0                                     0   366     1     r-----     11.4
testxen                                      1   128     1     -b----      1.1
Man beachte, dass die domU testxen wirklichen Speicher des RAM verwendet, der ansonsten für die dom0 verfügbar wäre, und keinen simulierten Speicher. Man sollte daher darauf achten, das physische RAM entsprechend zuzuteilen, wenn man einen Server einrichtet, auf dem Xen-Instanzen laufen sollen.
Voilà! Unser virtueller Rechner startet. Wir können auf ihn auf zweifache Art zugreifen. Der normale Weg besteht darin, sich mit ihm „aus der Ferne“ über das Netzwerk zu verbinden, wie wir es auch bei einem wirklichen Rechner tun würden; hierzu ist es normalerweise erforderlich, entweder einen DHCP-Server oder eine DNS-Konfiguration einzurichten. Der andere Weg, der der einzige sein könnte, falsch die Netzwerk-Konfiguration nicht korrekt war, besteht darin, über den Befehl xl console die Konsole hvc0 zu benutzen:
# xl console testxen
[...]

Debian GNU/Linux 8 testxen hvc0

testxen login: 
Man kann dann eine Sitzung öffnen, als säße man an der Tastatur des virtuellen Rechners. Zur Trennung von dieser Konsole dient die Tastenkombination Strg+].
Sobald eine domU läuft, kann sie so wie jeder andere Server verwendet werden (da sie schließlich ein GNU/Linux-System ist). Ihr Status als virtueller Rechner ermöglicht jedoch einige zusätzliche Funktionen. So kann eine domU zum Beispiel mit den Befehlen xl pause und xl unpause vorübergehend angehalten und dann wieder fortgesetzt werden. Man beachte, dass bei einer angehaltenen domU, obwohl sie keine Prozessorleistung in Anspruch nimmt, der ihr zugeordnete Speicherplatz weiterhin belegt ist. Es könnte interessant sein, hier die Befehle xl save und xl restore in Erwägung zu ziehen: das Speichern einer domU gibt die Ressourcen frei, die vorher von dieser domU verwendet wurden, einschließlich des RAM. Wenn sie fortgesetzt wird (oder eigentlich ihr Pausieren beendet wird), bemerkt eine domU außer dem Fortschreiten der Zeit nichts. Falls eine domU läuft, wenn die dom0 heruntergefahren wird, speichern die gebündelten Skripten automatisch die domU, und stellen sie beim nächsten Hochfahren wieder her. Dies schließt natürlich die gleichen Unannehmlichkeiten ein, die entstehen, wenn man zum Beispiel einen Laptop in den Ruhezustand versetzt; insbesondere, dass Netzwerkverbindungen verfallen, falls die domU zu lange ausgesetzt ist. Man beachte auch, dass Xen insofern mit einem Großteil der ACPI-Energieverwaltung inkompatibel ist, als es nicht möglich ist, das Host-System (die dom0) in den Bereitschaftsbetrieb zu versetzen.
Das Anhalten oder Neustarten einer domU kann entweder aus dieser domU heraus geschehen (mit dem Befehl shutdown) oder von der dom0 aus mit xl shutdown oder xl reboot.

12.2.2. LXC

Obwohl es dazu benutzt wird, „virtuelle Rechner“ zu erstellen, ist LXC genaugenommen kein Virtualisierungssystem, sondern ein System, um Gruppen von Prozessen voneinander zu isolieren, obwohl sie alle auf demselben Host laufen. Es macht sich eine Reihe neuerer Entwicklungen im Linux-Kernel zunutze, die gemeinhin als Kontrollgruppen (control groups) bekannt sind, mit denen verschiedene Sätze von Prozessen, die „Gruppen“ genannt werden, bestimmte Aspekte des Gesamtsystems auf unterschiedliche Weise sehen. Dies gilt vor allem für Aspekte wie die Prozesskennungen, die Netzwerkonfiguration und die Einhängepunkte. Eine derartige Gruppe isolierter Prozesse hat keinerlei Zugriff auf die anderen Prozesse des Systems, und ihre Zugriffe auf das Dateisystem können auf einen bestimmten Teilbereich eingegrenzt werden. Sie kann auch ihre eigene Netzwerkschnittstelle und Routing-Tabelle haben, und möglicherweise ist sie so konfiguriert, dass sie nur einen Teil der auf dem System verfügbaren Geräte sieht.
Diese Funktionen können kombiniert werden, um eine ganze Prozessfamilie, vom init-Prozess angefangen, zu isolieren, und die sich daraus ergebende Gruppe sieht einem virtuellen Rechner sehr ähnlich. Die offizielle Bezeichnung für eine derartige Anordnung ist ein „Container“ (daher der Name LXC: LinuX Containers), jedoch besteht ein wichtiger Unterschied zu einem „wirklichen“ virtuellen Rechner, wie einem der durch Xen oder KVM bereitgestellt wird, darin, dass es keinen zweiten Kernel gibt; der Container verwendet denselben Kernel wie das Host-System. Dies hat Vor- und Nachteile: zu den Vorteilen gehören die exzellente Performance aufgrund fehlender Last durch Overhead, und die Tatsache, dass der Kernel einen vollständigen Überblick über alle Prozesse hat, die auf dem System laufen, wodurch die Steuerung effizienter sein kann, als wenn zwei unabhängige Kernel verschiedene Aufgabensätze steuern würden. Zu den Nachteilen gehört vor allem, dass man in einem Container keinen anderen Kernel laufen lassen kann (sei dies eine andere Linux-Version oder ein völlig anderes Betriebssystem).
Da wir es hier mit einer Isolierung und nicht mit einer einfachen Virtualisierung zu tun haben, ist es schwieriger, einen LXC-Container einzurichten, als nur ein Debian-Installationsprogramm auf einem virtuellen Rechner auszuführen. Wir werden einige Voraussetzungen beschreiben und dann zur Netzwerkkonfigurierung übergehen; damit werden wir in der Lage sein, das System, das in dem Container laufen soll, zu erstellen.

12.2.2.1. Vorbereitende Schritte

Das Paket lxc enthält die für die Ausführung von LXC erforderlichen Hilfsprogramme und muss daher installiert werden.
LXC benötigt außerdem das Konfigurationssystem für die Kontrollgruppen, das ein unter /sys/fs/cgroup einzuhängendes virtuelles Dateisystem ist. Weil Debian 8 auf systemd geschwenkt hat, das auch auf control groups setzt, wird es automatisch beim Starten ohne weitere Konfiguration ausgeführt.

12.2.2.2. Netzwerkkonfigurierung

LXC wird mit dem Ziel installiert, virtuelle Rechner einzurichten; während wir diese natürlich vom Netzwerk getrennt halten und mit ihnen nur über das Dateisystem kommunizieren könnten, ist es in den meisten Anwendungsfällen erforderlich, den Containern wenigstens einen minimalen Netzwerkzugang zu gewähren. Typischerweise erhält jeder Container eine virtuelle Netzwerkschnittstelle, die mit dem wirklichen Netzwerk über eine Bridge verbunden ist. Diese virtuelle Schnittstelle kann entweder direkt an die physische Schnittstelle des Hosts angeschlossen sein (wobei sich der Container dann direkt im Netzwerk befindet) oder an eine weitere virtuelle Schnittstelle, die auf dem Host festgelegt ist (und bei der der Host dann den Datenverkehr filtern oder umleiten kann). In beiden Fällen ist das Paket bridge-utils erforderlich.
Der einfachste Fall besteht darin, die Datei /etc/network/interfaces zu editieren, indem die Konfiguration für die physische Schnittstelle (zum Beispiel eth0) zu einer Bridge-Schnittstelle verschoben (normalerweise br0) und die Verbindung zwischen ihnen konfiguriert wird. Wenn zum Beispiel die Konfigurationsdatei der Netzwerkschnittstellen Einträge wie die folgenden enthält:
auto eth0
iface eth0 inet dhcp
sollten sie deaktiviert und durch folgende ersetzt werden:
#auto eth0
#iface eth0 inet dhcp

auto br0
iface br0 inet dhcp
  bridge-ports eth0
Die Auswirkung dieser Konfiguration ähnelt derjenigen, die einträte, falls die Container Rechner wären, die an dasselbe physische Netzwerk angeschlossen sind wie der Host. Die „Bridge“-Konfiguration verwaltet den Übergang der Ethernet-Frames zwischen allen verbundenen Schnittstellen, zu denen sowohl die physische Schnittstelle eth0 als auch die für die Container festgelegten Schnittstellen gehören.
In Fällen, in denen diese Konfiguration nicht verwendet werden kann (falls zum Beispiel den Containern keine öffentlichen IP-Adressen zugeordnet werden können), wird eine virtuelle tap-Schnittstelle eingerichtet und mit der Bridge verbunden. Die dementsprechende Netzstruktur wird dann zu einer, bei der der Host mit einer zweiten Netzwerkkarte an einen eigenen Switch angeschlossen ist, wobei die Container ebenfalls an diesen Switch angeschlossen sind. Der Host muss in diesem Fall als Gateway für die Container agieren, falls diese mit der Außenwelt kommunizieren sollen.
Zusätzlich zu bridge-utils ist für diese „üppige“ Konfiguration das Paket vde2 erforderlich; die Datei /etc/network/interfaces wird dann zu:
# Schnittstelle eth0 bleibt unverändert
auto eth0
iface eth0 inet dhcp

# Virtuelle Schnittstelle
auto tap0
iface tap0 inet manual
  vde2-switch -t tap0

# Bridge für Container
auto br0
iface br0 inet static
  bridge-ports tap0
  address 10.0.0.1
  netmask 255.255.255.0
Das Netzwerk kann dann entweder statisch in den Containern eingerichtet werden oder dynamisch mit einem DHCP-Server, der auf dem Host läuft. Solch ein DHCP-Server muss so konfiguriert sein, dass er Anfragen auf der Schnittstelle br0 beantwortet.

12.2.2.3. Das System einrichten

Lassen Sie uns jetzt das von dem Container zu verwendende Dateisystem einrichten. Da dieser „virtuelle Rechner“ nicht direkt auf der Hardware laufen wird, sind im Vergleich zu einem Standard-Dateisystem einige Feineinstellungen vorzunehmen, insbesondere was den Kernel, die Geräte und Konsolen betrifft. Glücklicherweise enthält das Paket lxc Skripten, die diese Konfigurierung weitestgehend automatisieren. So installieren zum Beispiel die folgenden Befehle (die das Paket debootstrap und rsync erfordern) einen Debian-Container:
root@mirwiz:~# lxc-create -n testlxc -t debian
debootstrap is /usr/sbin/debootstrap
Checking cache download in /var/cache/lxc/debian/rootfs-jessie-amd64 ... 
Downloading debian minimal ...
I: Retrieving Release 
I: Retrieving Release.gpg 
[...]
Download complete.
Copying rootfs to /var/lib/lxc/testlxc/rootfs...
[...]
Root password is 'sSiKhMzI', please change !
root@mirwiz:~# 
Man beachte, dass das Dateisystem zunächst in /var/cache/lxc erstellt und dann in sein Zielverzeichnis verschoben wird. So lassen sich mehrere identische Container wesentlich schneller erstellen, da sie nur kopiert werden müssen.
Man beachte, dass das Skript zum Erstellen des Debian Beispiels eine Option --arch akzeptiert, um die Architaktur anzugeben, die Installiert werden soll, sowie eine Option --release, wenn Sie etwas anderes als das aktuelle "stable" Release von Debian installieren wollen. Sie können auch die Umgebungsvariable MIRROR auf einen lokalen Debain Spiegel zeigen lassen.
Das neu erstellte Dateisystem enthält jetzt ein minimales Debian-System, und per Voreinstellung hat der Container keine Netzwerkschnittstelle (außer Loopback). Da wir das nicht wollen, editieren wir die Konfigurationsdatei des Containers (/var/lib/lxc/testlxc/config) und fügen einige lxc.network.*-Einträge hinzu:
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.hwaddr = 4a:49:43:49:79:20
Diese Einträge bedeuten jeweils, dass eine virtuelle Schnittstelle in dem Container erzeugt wird; dass sie automatisch in Gang gesetzt wird, wenn der besagte Container startet; dass sie automatisch mit der br0-Bridge auf dem Host verbunden wird; und dass ihre MAC-Adresse wie angegeben lautet. Falls diese letzte Angabe fehlt oder deaktiviert ist, wird eine zufällige MAC-Adresse erzeugt.
Ein anderer nützlicher Eintrag in dieser Datei ist die Angabe des Hostnamens:
lxc.utsname = testlxc

12.2.2.4. Den Container starten

Nun, da das Abbild unseres virtuellen Rechners fertig ist, wollen wir den Container starten:
root@mirwiz:~# lxc-start --daemon --name=testlxc
root@mirwiz:~# lxc-console -n testlxc
Debian GNU/Linux 8 testlxc tty1

testlxc login: root
Password: 
Linux testlxc 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1 (2015-05-24) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@testlxc:~# ps auxwf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.2  28164  4432 ?        Ss   17:33   0:00 /sbin/init
root        20  0.0  0.1  32960  3160 ?        Ss   17:33   0:00 /lib/systemd/systemd-journald
root        82  0.0  0.3  55164  5456 ?        Ss   17:34   0:00 /usr/sbin/sshd -D
root        87  0.0  0.1  12656  1924 tty2     Ss+  17:34   0:00 /sbin/agetty --noclear tty2 linux
root        88  0.0  0.1  12656  1764 tty3     Ss+  17:34   0:00 /sbin/agetty --noclear tty3 linux
root        89  0.0  0.1  12656  1908 tty4     Ss+  17:34   0:00 /sbin/agetty --noclear tty4 linux
root        90  0.0  0.1  63300  2944 tty1     Ss   17:34   0:00 /bin/login --     
root       117  0.0  0.2  21828  3668 tty1     S    17:35   0:00  \_ -bash
root       268  0.0  0.1  19088  2572 tty1     R+   17:39   0:00      \_ ps auxfw
root        91  0.0  0.1  14228  2356 console  Ss+  17:34   0:00 /sbin/agetty --noclear --keep-baud console 115200 38400 9600 vt102
root       197  0.0  0.4  25384  7640 ?        Ss   17:38   0:00 dhclient -v -pf /run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.e
root       266  0.0  0.1  12656  1840 ?        Ss   17:39   0:00 /sbin/agetty --noclear tty5 linux
root       267  0.0  0.1  12656  1928 ?        Ss   17:39   0:00 /sbin/agetty --noclear tty6 linux
root@testlxc:~# 
Wir befinden uns nun in dem Container; unser Zugriff auf diejenigen Prozesse beschränkt, die vom Container selbst gestartet wurden, und unser Zugriff auf das Dateisystem ist in ähnlicher Weise auf die zugehörige Teilmenge des gesamten Dateisystems (/var/lib/lxc/testlxc/rootfs) eingeschränkt. Wir können die Konsole mit Control+a q wieder verlassen.
Beachten Sie, dass wir den Container beim Aufruf von lxc-start durch die Option --daemon als Hintergrundprozess laufen lassen. Wir können den Container dann mit einem Befehl wie lxc-stop --name=testlxc schließen.
Das Paket lxc enthält ein Initialisierungsskript, das automatisch einen oder mehrere Container starten kann, wenn der Host bootet (es basiert auf lxc-autostart welches Container startet, deren Option lxc.start.auto auf 1 gesetzt ist). Eine feinere Steuerung der Startreihenfolge ist mit lxc.start.order und lxc.group möglich: standardmäßig startet das Initialisierungsskript zuerst Container, die Teil der Gruppe onboot sind und dann die Container, die nicht Teil einer Gruppe sind. In beiden Fällen wird die Reihenfolge innerhalb einer Gruppe durch die Option lxc.start.order definiert.

12.2.3. Virtualisierung mit KVM

KVM, das Kernel-based Virtual Machine bedeutet, ist in erster Linie ein Kernel-Modul, das den größten Teil der Infrastruktur bereitstellt, die von einem Virtualisierungsprogramm benutzt werden kann, ist jedoch selbst kein Virtualisierungsprogramm. Die eigentliche Steuerung der Virtualisierung wird von einer Anwendung auf der Grundlage von QEMU vorgenommen. Wundern Sie sich nicht, dass dieser Abschnitt über qemu-*-Befehle spricht: er handelt dennoch von KVM.
Im Gegensatz zu anderen Virtualisierungssystemen war KVM von Anfang an Teil des Linux-Kernels. Seine Entwickler entschieden sich, die für eine Virtualisierung vorgesehenen Prozessor-Befehlssätze (Intel-VT und AMD-V) zu nutzen, wodurch KVM leichtgewichtig, elegant und ressourcenschonend bleibt. Die Kehrseite ist natürlich, dass KVM nicht auf allen Rechnerarchitekturen läuft, sondern nur auf denen mit entsprechenden Prozessoren. Sie können überprüfen, ob Sie einen derartigen Prozessor haben wenn unter den CPU-Flags in der Datei /proc/cpuinfo „vmx“ oder „svm“ aufgeführt ist.
Mit aktiver Unterstützung seiner Entwicklung durch Red Hat scheint KVM auf dem Wege zu sein, zur Referenz für Linux-Virtualisierung zu werden.

12.2.3.1. Vorbereitende Schritte

Im Gegensatz zu Programmen wie VirtualBox enthält KVM selbst keine Benutzerschnittstelle zur Erstellung und Verwaltung virtueller Rechner. Das Paket qemu-kvm stellt nur eine ausführbare Datei zum Start eines virtuellen Rechners bereit sowie ein Initialisierungsskript, das die passenden Kernel-Module lädt.
Glücklicherweise stellt Red Hat mit der Entwicklung der Bibliothek libvirt und der dazugehörigen Werkzeuge des virtual machine manager einen weiteren Satz von Hilfsprogrammen zur Lösung dieses Problems bereit. Mit libvirt ist es möglich, virtuelle Rechner einheitlich zu verwalten unabhängig von dem Virtualisierungssystem, das hinter den Kulissen beteiligt ist (gegenwärtig unterstützt es QEMU, KVM, Xen, LXC, OpenVZ, VirtualBox, VMWare und UML). virtual-manager ist eine grafische Schnittstelle, die libvirt zur Erstellung und Verwaltung virtueller Rechner benutzt.
Zunächst installieren wir mit apt-get install qemu-kvm libvirt-bin virtinst virt-manager virt-viewer die erforderlichen Pakete. libvirt-bin stellt den Daemon libvirtd zur Verfügung, mit dem (unter Umständen aus der Ferne) die Verwaltung der virtuellen Rechner, die auf dem Host laufen, möglich ist, und der die erforderlichen virtuellen Rechner startet, wenn der Host hochfährt. Zusätzlich enthält dieses Paket das Befehlszeilenwerkzeug virsh, das die Steuerung der Rechner ermöglicht, die von libvirtd verwaltet werden.
Das Paket virtinst stellt den Befehl virt-install bereit, mit dem es möglich ist, virtuelle Rechner von der Befehlszeile aus zu erstellen. Und schließlich ermöglicht virt-viewer den Zugriff auf die grafische Konsole eines virtuellen Rechners.

12.2.3.2. Netzwerkkonfigurierung

Genauso wie in Xen und LXC gehört zu der häufigsten Netzwerkkonfiguration eine Bridge, mit der die Netzwerkschnittstellen der virtuellen Rechner zusammengefasst werden (siehe Abschnitt 12.2.2.2, „Netzwerkkonfigurierung“).
Stattdessen kann (und das ist die Voreinstellung bei KVM) dem virtuellen Rechner eine private Adresse (im Bereich von 192.168.122.0/24) zugeordnet und NAT eingerichtet werden, so dass der virtuelle Rechner auf das externe Netzwerk zugreifen kann.
Für den Rest dieses Abschnitts wird angenommen, dass der Host über eine eth0 als physische Schnittstelle und eine br0-Bridge verfügt, und das Erstere mit Letzterer verbunden ist.

12.2.3.3. Installation mit virt-install

Die Erstellung eines virtuellen Rechners ist der Installation eines normalen Systems sehr ähnlich, außer dass die Eigenschaften des virtuellen Rechners in einer scheinbar endlosen Befehlszeile beschrieben werden.
In der Praxis bedeutet dies, dass wir das Debian-Installationsprogramm verwenden, indem wir den virtuellen Rechner auf einem virtuellen DVD-ROM-Laufwerk hochfahren, dem ein auf dem Host-System gespeichertes DVD-Abbild von Debian zugeordnet ist. Der virtuelle Rechner exportiert seine grafische Konsole über das VNC-Protokoll (für Einzelheiten siehe Abschnitt 9.2.2, „Entfernte grafische Arbeitsflächen benutzen“), so dass wir den Installationsprozess steuern können.
Zunächst müssen wir libvirtd mitteilen, wo die Plattenabbilder gespeichert werden sollen, es sei denn, dass der voreingestellte Ort (/var/lib/libvirt/images/) in Ordnung ist.
root@mirwiz:~# mkdir /srv/kvm
root@mirwiz:~# virsh pool-create-as srv-kvm dir --target /srv/kvm
Pool srv-kvm created

root@mirwiz:~# 
Wir wollen jetzt mit dem Installationsprozess für den virtuellen Rechner beginnen und uns die wichtigsten Optionen des Befehls virt-install ansehen. Der Befehl registriert den virtuellen Rechner und seine Parameter in libvirtd und startet ihn dann, so dass seine Installierung fortgesetzt werden kann.
# virt-install --connect qemu:///system  1
               --virt-type kvm           2
               --name testkvm            3
               --ram 1024                4
               --disk /srv/kvm/testkvm.qcow,format=qcow2,size=10 5
               --cdrom /srv/isos/debian-8.1.0-amd64-netinst.iso  6
               --network bridge=br0      7
               --vnc                     8
               --os-type linux           9
               --os-variant debianwheezy

Starting install...
Allocating 'testkvm.qcow'             |  10 GB     00:00
Creating domain...                    |    0 B     00:00
Guest installation complete... restarting guest.

1

Die Option --connect legt den zu verwendenden „Hypervisor“ fest. Sie hat die Form einer URL, die ein Virtualisierungssystem enthält (xen://, qemu://, lxc://, openvz://, vbox:// und so weiter) und den Rechner, der den virtuellen Rechner aufnehmen soll (dies kann leer bleiben, falls es sich dabei um den lokalen Host handelt). Zusätzlich hierzu, und im Fall vom QEMU/KVM, kann jeder Benutzer virtuelle Rechner, die mit eingeschränkten Berechtigungen laufen, verwalten, wobei der URL-Pfad es ermöglicht, „System“-Rechner (/system) von anderen (/session) zu unterscheiden.

2

Da KVM auf die gleiche Weise wie QEMU verwaltet wird, kann mit --virt-type kvm die Verwendung von KVM festgelegt werden, obwohl die URL aussieht, als würde QEMU verwendet.

3

Die Option --name legt einen (eindeutigen) Namen für den virtuellen Rechner fest.

4

Die Option --ram ermöglicht es, die Größe des RAM (in MB) festzulegen, das dem virtuellen Rechner zugeordnet wird.

5

Mit --disk wird der Ort der Abbild-Datei benannt, die die Festplatte unseres virtuellen Rechners darstellen soll; diese Datei wird, falls sie nicht bereits vorhanden ist, in einer Größe (in GB) erstellt, die mit dem Parameter size festgelegt wird. Der Parameter format ermöglicht die Auswahl zwischen mehreren Arten der Speicherung der Abbild-Datei. Das voreingestellte Format (raw) besteht aus einer einzelnen Datei, die in Größe und Inhalt der Platte entspricht. Wir haben hier ein weiter entwickeltes Format gewählt, das für QEMU spezifisch ist, und bei dem man mit einer kleinen Datei beginnen kann, die nur größer wird, wenn der virtuelle Rechner tatsächlich damit beginnt, Platz zu belegen.

6

Die Option --cdrom wird zur Anzeige des Ortes verwendet, an dem sich die optische Platte befindet, die für die Installierung benutzt wird. Der Pfad kann entweder ein lokaler Pfad zu einer ISO-Datei sein, eine URL, von der die Datei bezogen werden kann, oder die Gerätedatei eines physischen CD-ROM-Laufwerks (das heißt /dev/cdrom).

7

Mit --network wird festgelegt, wie sich die virtuelle Netzwerkkarte in die Netzwerkkonfiguration des Hosts integriert. Das voreingestellte Verhalten (das in unserem Beispiel ausdrücklich erzwungen wird) besteht darin, sie in eine bereits bestehende Netzwerk-Bridge einzubinden. Falls es eine derartige Bridge nicht gibt, kann der virtuelle Rechner das physische Netzwerk nur über NAT erreichen, das heißt, dass er eine Adresse in einem privaten Teilnetzbereich erhält (192.168.122.0/24).

8

--vnc gibt an, dass die grafische Konsole unter Verwendung von VNC zur Verfügung gestellt werden soll. Das voreingestellte Verhalten des zugeordneten VNC-Servers besteht darin, nur an der lokalen Schnittstelle auf Eingaben zu warten. Fall der VNC-Client auf einem anderen Host laufen soll, muss zur Herstellung der Verbindung ein SSH-Tunnel eingerichtet werden (siehe Abschnitt 9.2.1.3, „Verschlüsselte Tunnel mit Port-Weiterleitung einrichten“). Alternativ kann --vnclisten=0.0.0.0 verwendet werden, so dass von allen Schnittstellen aus auf den VNC-Server zugegriffen werden kann. Man beachte jedoch, dass in diesem Fall die Firewall wirklich entsprechend eingestellt werden sollte.

9

Mit den Optionen --os-type und --os-variant lassen sich einige Parameter des virtuellen Rechners optimieren in Abhängigkeit von den bekannten Funktionen des Betriebssystems, das hier genannt wird.
Jetzt läuft der virtuelle Rechner, und wir müssen uns mit der grafischen Konsole verbinden, um den Installationsprozess fortzusetzen. Falls die bisherigen Schritte in einer grafischen Arbeitsumgebung ausgeführt wurden, sollte diese Verbindung von sich aus starten. Anderenfalls, oder falls wir aus der Ferne arbeiten, kann virt-viewer von jeder beliebigen grafischen Umgebung aus aufgerufen werden, um die grafische Konsole zu öffnen (man beachte, dass zweimal nach dem Root-Passwort des entfernten Hosts gefragt wird, da dieser Arbeitsgang zwei SSH-Verbindungen erfordert):
$ virt-viewer --connect qemu+ssh://root@server/system testkvm
root@server's password: 
root@server's password: 
Wenn der Installationsprozess endet, startet der virtuelle Rechner neu und ist dann einsatzbereit.

12.2.3.4. Rechner mit virsh verwalten

Nachdem die Installation nunmehr erledigt ist, wollen wir sehen, wie man mit den vorhandenen virtuellen Rechnern umgeht. Zunächst soll libvirtd nach einer Liste der virtuellen Rechner, die er verwaltet, gefragt werden:
# virsh -c qemu:///system list --all
 Id Name                 State
----------------------------------
  - testkvm              shut off
Lassen Sie uns unseren virtuellen Testrechner starten:
# virsh -c qemu:///system start testkvm
Domain testkvm started
Wir können jetzt die Verbindungshinweise für die grafische Konsole bekommen (die angegebene VNC-Anzeige kann als Parameter an vncviewer übergeben werden):
# virsh -c qemu:///system vncdisplay testkvm
:0
Zu den weiteren bei virsh verfügbaren Unterbefehlen gehören:
  • reboot, um einen virtuellen Rechner neu zu starten;
  • shutdown, um ein sauberes Herunterfahren einzuleiten;
  • destroy, um ihn brutal zu stoppen;
  • suspend, um ihn in den Bereitschaftsbetrieb zu versetzen;
  • resume, um ihn wieder in Betrieb zu nehmen;
  • autostart, um den automatischen Start des virtuellen Rechners beim Hochfahren des Hosts zu aktivieren (oder ihn mit der Option --disable zu deaktivieren);
  • undefine, um alle Spuren des virtuellen Rechners von libvirtd zu entfernen.
Alle diese Unterbefehle erfordern als einen ihrer Parameter die Kennung eines virtuellen Rechners.

12.2.3.5. Ein RPM-basiertes System in Debian mit yum installieren

Wenn auf der virtuellen Maschine ein Debian-System (oder eines seiner Derivate) laufen soll, kann das System mit debootstrap aufgesetzt werden, wie oben beschrieben. Soll aber auf der virtuellen Maschine ein RPM-basiertes System laufen, dann muss es mit dem Utility yum (aus dem gleichnamigen Paket) installiert werden.
Die Prozedur erfordert die Verwendung von rpm, um einen ersten Satz von Dateien zu extrahieren, insbesondere yum Konfigurationsdateien gefolgt vom Aufruf von yum, um den restlichen Satz von Paketen zu extrahieren. Aber da wir yum von außerhalb des chroot aufrufen, müssen wir einige temporäre Änderungen vornehmen. Im Beispiel unten ist das Ziel chroot /srv/centos.
# rootdir="/srv/centos"
# mkdir -p "$rootdir" /etc/rpm
# echo "%_dbpath /var/lib/rpm" > /etc/rpm/macros.dbpath
# wget http://mirror.centos.org/centos/7/os/x86_64/Packages/centos-release-7-1.1503.el7.centos.2.8.x86_64.rpm
# rpm --nodeps --root "$rootdir" -i centos-release-7-1.1503.el7.centos.2.8.x86_64.rpm
rpm: RPM should not be used directly install RPM packages, use Alien instead!
rpm: However assuming you know what you are doing...
warning: centos-release-7-1.1503.el7.centos.2.8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
# sed -i -e "s,gpgkey=file:///etc/,gpgkey=file://${rootdir}/etc/,g" $rootdir/etc/yum.repos.d/*.repo
# yum --assumeyes --installroot $rootdir groupinstall core
[...]
# sed -i -e "s,gpgkey=file://${rootdir}/etc/,gpgkey=file:///etc/,g" $rootdir/etc/yum.repos.d/*.repo