aboutsummaryrefslogtreecommitdiff
path: root/articles/2012-11-20_virtualisierung_mit_kvm_und_virtuelle_netzwerke_mit_vde.md
blob: 8d3e8db6afd475ed43063da5d1785a762528e56a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Virtualisierung mit KVM und virtuelle Netzwerke mit VDE

Ich spiele in meiner Freizeit gerne mit verschiedenen neuen Datenbank-Systemen, Sprachen und Frameworks - passe ich dabei nicht penibel auf, entsteht schnell ein Gewirr aus Konfigurations-Dateien und einmal installierten Paketen, die gar nicht mehr verwendet werden. Das System fühlt sich mit der Zeit also etwas ungut und zugemüllt an.

Bis jetzt versuche ich zumindest größere Entwicklungen in eigenen VMs abzugrenzen, ganz einheitlich bin ich dabei wegen einigen störenden Punkten aber nicht. Zum einen ist die Verwaltung der
Netzanbindung verschiedener VMs über die im Arch-Wiki [beschriebene Behelfsmethode](https://wiki.archlinux.org/index.php/KVM#Poor_Man.27s_Networking) mit SSH-Tunneln alles andere als schön, zum anderen will ich nicht für jede VM ein eigenes Fenster mit Konsole
rumfliegen haben. Was ich will, ist also eine "richtige" Netzwerk-Konfiguration über virtuelle Interfaces und einen Betrieb der VMs ohne grafische Oberfläche als Daemon im Hintergrund.

Als Virtualisierungs-System setze ich auf KVM, die Distribution der Wahl ist weiterhin ArchLinux.

## Kernel Based Virtual Machine

[KVM](http://www.linux-kvm.org/page/Main_Page) ist das direkt im Linux-Kernel integrierte Virtualisierung-System. Einzige Voraussetzung dafür ist ein Prozessor mit Virtualisierungs-Funktionen, diese sollten die meisten der in den
letzten Jahren auf den Markt gekommenen Prozessoren besitzen - selbst mein Core Duo aus 2007 führt KVM einwandfrei aus. Ansonsten verhält sich KVM identisch zu [QEMU](http://wiki.qemu.org/Main_Page), der einzige Unterschied ist,
dass der Prozessor nicht wie bei QEMU komplett emuliert wird, sondern die Befehle über den Kernel an den physikalischen Prozessor durchgereicht werden. Dies hat den Nachteil, dass KVM z.B.
keine ARM-Plattformen unter x86 ausführen kann, der große Vorteil ist jedoch die gute Performance. Es übertrifft bei mir - gefühlsmäßig, ich habe keine Benchmarks durchgeführt - ohne Probleme
sowohl [VirtualBox](https://wiki.archlinux.org/index.php/VirtualBox) als auch [VMware](https://wiki.archlinux.org/index.php/VMware).

Ein Vorteil aus der vollständigen Integration der KVM in den Kernel ist es, dass sich auch ganz normale Block-Geräte wie Festplatten-Partitionen etc. ohne Anpassung verwenden lassen.
Dadurch kann ich ohne Probleme z.B. ein auf einer zweiten Host-Partition installiertes Betriebssystem im laufenden Linux-Betrieb "dazubooten" und nutzen.

Angesteuert wird die KVM wahlweise über `qemu-kvm` oder `qemu --enable-kvm`. Damit das funktioniert müssen jedoch die Kernel-Module `kvm` und `kvm_intel` bzw. `kvm_amd` geladen werden.
Die grundlegende Verwendung abseits des anderen Befehls ist gleich wie bei QEMU. So werden Image-Dateien für die Gast-Systeme mit `qemu-img` erstellt und auch Einstellungen zur Hardware
des Gast-Systems werden auf die gleiche Weise gesetzt. Aus diesem Grund gehe ich hier auch nicht näher auf die grundlegende Verwendung ein, Details lassen sich bei Bedarf im Arch-Wiki [nachlesen](https://wiki.archlinux.org/index.php/QEMU).

Hier als Beispiel mein derzeitiger Standardaufruf von KVM, der für alle VMs gleich ist. Dynamisch ist allein das zu verwendende Speicher-Gerät - in meinem Fall verschiedene Image-Dateien.

```sh
qemu-kvm -cpu host -hda $1 -m 1024 -daemonize -vnc none -usb -net nic -net vde
```

Dieser verwendet das als erster Parameter übergebene Gerät als Festplatte und setzt neben den nötigen Netzwerk-Einstellungen die VM mittels `-daemonize` in den Hintergrund. Falls benötigt, kann
als Wert des Parameters `-vnc` auch eine von einem Doppelpunkt angeführte Zahl übergeben werden um die Grafik-Ausgabe der VM an einen VNC-Server anzubinden (z.B. `-vnc :1` für `127.0.0.1:1`). Diese
Funktion verwende ich nicht, da ich ausschließlich über das interne Netzwerk die im Gast installierten Dienste nutze und administrative Tätigkeiten immer über SSH durchführe.

## Netzwerken mit VDE

[VDE](http://wiki.virtualsquare.org/wiki/index.php/VDE_Basic_Networking) steht für Virtual Distributed Ethernet und ermöglicht genau das was der Name erahnen lässt: Virtuelle Switches die beispielsweise VMs in einem Host internen LAN verbinden können.

Meine Konfiguration hält sich dabei im wesentlichen an den [Vorschlag](https://wiki.archlinux.org/index.php/QEMU#Networking_with_VDE2) im englischen Arch-Wiki, welchen ich in ein einfaches Script verpackt habe:

```sh
#!/bin/sh
case "$1" in
	start)
		ip tuntap add tap0 mode tap
		vde_switch -tap tap0 -daemon -pidfile .switch.pid -mod 660 -group kvm
		ip addr add dev tap0 192.168.100.254/24
		ip link set dev tap0 up
	;;
	stop)
		kill -9 `cat .switch.pid`
		rm .switch.pid
		ip tuntap del tap0 mode tap
	;;
esac
```

Dieses Script erzeugt ein virtuelles Interface `tap0` und verbindet ein neues, als Daemon im Hintergrund laufendes, virtuelles Switch mit diesem. Als nächstes wird dann noch eine statische IP Konfiguration für das virtuelle Interface definiert. Durch diese können alle mit `-net nic -net vde` Parametern gestarteten KVM Gäste über die IP `192.168.100.254` auf den Host zugreifen.

In den Gast-Systemen selbst muss zusätzlich eine statische IP Konfiguration vorgenommen werden:

	interface=eth0
	address=192.168.100.1
	netmask=255.255.255.0
	broadcast=192.168.100.255
	gateway=192.168.100.254

Um das interne virtuelle LAN bei Bedarf mit der Außenwelt zu verbinden gibt es ebenfalls ein kleines Script welches die nötige Route erzeugt bzw. löscht:

```sh
#!/bin/sh
case "$1" in
	start)
		echo "1" > /proc/sys/net/ipv4/ip_forward
		iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o $2 -j MASQUERADE
	;;
	stop)
		iptables -t nat -X
		echo "0" > /proc/sys/net/ipv4/ip_forward
	;;
esac
```

Anpassbar ist hierbei das Interface, um z.B. daheim `eth0` und unterwegs wahlweise `wlan0` oder `usb0` verwenden zu können.

## KVM Hardware Error

Nach einer Kernel Aktualisierung im ArchLinux Gast-System, kam es beim Neustart plötzlich zu dieser etwas erschreckenden Meldung:

```
KVM: entry failed, hardware error 0x80000021

If you're running a guest on an Intel machine without unrestricted mode
support, the failure can be most likely due to the guest entering an invalid
state for Intel VT. For example, the guest maybe running in big real mode
which is not supported on less recent Intel processors.

EAX=00000000 EBX=0020fa5c ECX=00000000 EDX=fffff000
ESI=f6d29014 EDI=00000001 EBP=f6461fa0 ESP=f6461f60
EIP=c0128443 EFL=00010246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =007b 00000000 ffffffff 00c0f300 DPL=3 DS   [-WA]
CS =0060 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0068 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =007b 00000000 ffffffff 00c0f300 DPL=3 DS   [-WA]
FS =00d8 36648000 ffffffff 00809300 DPL=0 DS16 [-WA]
GS =00e0 f6d2f540 00000018 00409100 DPL=0 DS   [--A]
LDT=0000 ffff0000 f0000fff 00f0ff00 DPL=3 CS64 [CRA]
TR =0080 f6d2d3c0 0000206b 00008b00 DPL=0 TSS32-busy
GDT=     f6d28000 000000ff
IDT=     c060b000 000007ff
CR0=8005003b CR2=ffffffff CR3=006ef000 CR4=000006d0
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000700000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
EFER=0000000000000000
Code=00 8b 15 c4 b5 61 c0 55 89 e5 5d 8d 84 10 00 c0 ff ff 8b 00 <c3> 8d b6 00 00 00 00 8d bf 00 00 00 00 8b 15 a0 ae 61 c0 55 89 e5 53 89 c3 b8 30 00 00 00
```

Dies sah für mich im ersten Moment wie ein klarer Hardware-Fehler aus, alle Informationen die sich über meine bevorzugte Suchmaschine finden ließen, waren jedoch für andere Situationen und ältere Kernel Versionen als `3.6.6-1`. Nach Tests mit verschiedenen Parametern für die zuständigen Kernel-Module, funktionierte es schließlich nach Laden des Moduls mit folgendem Befehl wieder einwandfrei:

```sh
modprobe kvm_intel emulate_invalid_guest_state=0
```

Um den `emulate_invalid_guest_state` Parameter dauerhaft zu setzen reicht ein Eintrag in `/etc/modprobe.d`.

## Fazit

Mithilfe der beschriebenen Konfiguration und den Scripts lassen sich KVM VMs unsichtbar im Hintergrund starten und in einem Host-internen virtuellen LAN ansteuern. Bei Bedarf kann dieses virtuelle Netz mithilfe von Routen erweitert werden. Für den Netzzugriff in den Gast-Systemen reicht eine einfache statische Konfiguration.  
Ich werde das Ganze in nächster Zeit vermutlich noch etwas  erweitern und verbessern, aber diese Grundlage ist auf jeden Fall besser als die von mir am Anfang genutzten SSH-Tunnel zwischen Gast und Host. 

Das Erstellen einer neuen VM benötigt jetzt nicht viel mehr als eine Kopie eines Muster-Images und eine Anpassung der statischen IP Konfiguration - mit zusätzlichen Scripts könnte ich mir auch eine einfache, selbstgebaute Variante von [Vagrant](http://vagrantup.com/) auf KVM Basis vorstellen. Wobei auch dort, durch die [Einführung](https://github.com/mitchellh/vagrant/commit/391dc392675c73518ebf04252d824fe916e8860b) einer neuen Abstraktionsschicht, die Unterstützung von KVM als Alternative zu VirtualBox ein Stück näher gerückt sein dürfte.