KVM dans un screen (encore) avec le monitor kvm

Comme dit dans les précédents billets kvm ne dispose pas de de manager comme Xen (xm toussa). Après avoir réussi à obtenir le système guest dans un screen il restait à garder une main sur le monitor (contrôle de kvm, screenshot, dump, gdb, load/save, etc) sans l’interface graphique (ctrl+alt+2). Comme en plus je suis exigeant, avoir le monitor dans une fenêtre screen à côté du système dans la kvm était un minimum.

Bon, pour le kvm dans un screen pas de problème. C’est du déjà vu (option -nographic et console série sur le guest). Voyons ce que nous dit kvm -h pour le reste :
Debug/Expert options:
-monitor dev redirect the monitor to char device ‘dev’
[…]
Après des heures à chercher comment récupérer cela dans un screen, un cu ou un minicom à grand coup de bidouilles autour de pts, ptmx, et autre… j’ai bêtement tenté un :
% tty
/dev/pts/7
% kvm [truc option bla bla] -monitor /dev/pts/7
(qemu)
Oh ! Le prompt du monitor kvm ! Restait à l’intégrer dans une fenêtre dans la même session de screen que la sortie série du système guest. Voici la recette :

Le but du jeu est de lancer un screen et de récupérer dans la première fenêtre le TTY, on ouvre alors une seconde fenêtre pour y lancer kvm. La méthode la plus simple est de faire un script shell lancé dans screen invoquant lui-même un screen :
#!/bin/sh
echo Running kvm with monitor send to `tty` : $STY
screen -t KVM kvm -hda debian.cow -m 512 -net nic
-net tap,ifname=tap10,script=no -nographic -localtime -monitor `tty`
for ((;;))
do
sleep 10000
done
La boucle for est nécessaire sinon la fenêtre ne reste pas ouverte. Reste plus qu’à lancer ça avec :
% screen -S rototo -t monitor ./script.sh
Le -S pour nommer la session et le -t pour nommer la première fenêtre. L’invocation de screen depuis le script créé un nouvelle fenêtre appelée KVM avec le guest dedans.

Comme je ne voulais pas m’arrêté en si bon chemin, j’ai écris un petit quelque chose pour simplifier encore plus le tout en utilisant un script façon init. Le truc s’appel kvmmanage.

Ce script supporte le lancement, le listage et l’accès aux guests kvm. Accessoirement il permet aussi de stopper le guest (en attachant le screen et en vous laissant faire) ou salement avec un gros SIGKILL.

Le script utilise un autre script (launcher.sh) permettant de lancer les guests dans les screen avec le monitor comme présenté plus haut :
#!/bin/sh
echo Running kvm with monitor send to `tty` : $STY
touch /var/run/kvmmanage/$STY
. $1
screen -t KVM ${KVMCMD}
for ((;;))
do
sleep 10000
done
Il suffit ensuite de créé des profiles sous la forme de fichiers .prf :
KVMCMD= »kvm -hda debian.cow -m 512 -net nic -net tap,ifname=tap10,script=no -nographic -localtime -monitor `tty` »
Un kvmmanage start nom lance launcher.sh avec en argument nom.prf, le screen apparaît à l’écran et un fichier dans /var/run/kvmmanage est créé avec l’identifiant de session screen. Lister les guests est simple, il suffit de lister ce répertoire. C’est ce que fait kvmmanage list. Pour réattacher la console on check le fichier, s’il existe on utilise l’identifiant de session pour attacher le screen.

Ce script est du vite-fait et vous devrez modifier certains chemins comme KVMDIR et LAUNCHSCRIPT. Il est également possible de lancer plusieurs fois le même guest (comme en vrai avec kvm) ce qui est passablement dangeureux. Enfin, je n’ai pas trouvé de moyen propre de stopper un guest sauf en s’y attachant et en le stoppant par halt, init 0, etc…

KVM, console, screen et hop, BSD aussi !

Pourquoi m’arrêter en si bon chemin ? Puisque j’ai une Debian 4.0 (Etch) qui tourne dans une KVM avec un support pour la console dans un Screen pourquoi ne pas faire de même avec un FreeBSD ? Je m’attendais à plus de difficulté qu’avec GNU/Linux… et bien non. au contraire.

Après création de l’image disque et installation sans problème d’un FreeBSD 6.2 dans ma configuration bridgée via TUN/TAP (voir billet en rapport) il suffit de modifier quelques éléments de la configuration.

Première étape, demander gentillement du bootloader d’utiliser la console série. Il suffit d’ajouter une ligne dans votre /boot/loader.conf :
console= »comconsole »
Ceci fait, tout comme avec GNU/Linux, il faut signaler que cette console est sécure et utilisable on change donc une ligne dans /etc/ttys en :
# The ‘dialup’ keyword identifies dialin lines to login, fingerd etc
ttyd0 « /usr/libexec/getty std.9600 » vt100 on secure
Enfin, histoire de voir plus clairement ce qui se passe on créé un boot.config à la racine contenant :
-D
Comme le précise la documentation FreeBSD cette option permet de préciser au système qu’il doit utiliser la console interne ET série pour le boot.

Petite précision au passage concernant l’utilisation, ensuite, avec l’option -nographic de kvm : Il est important de ne pas utiliser l’option -no-acpi car l’ACPI/APM est nécessaire pour que BSD éteigne la machine au terme de la procédure d’arrêt. Procédure qu’il faut lancer avec un halt -p. Dans le cas contraire, vous vous retrouvez avec un système arrêté mais kvm ne quitte pas automatiquement. Et comme vous n’avez pas accès au monitor de kvm vous êtes obligé d’utiliser kill. Pas très propre.

Notez au passage que dans sa configuration classique kvm propose un monitor (ctrl+alt+2), une console série très pratique avant l’utilisation de -nographic (ctrl+alt+3) et une console parallèle (ctrl+alt+4).

Prochaine étape : utiliser d’autres systèmes et régler le problème du monitor en mode console série.

KVM, console série et GNU screen

Le gros avantage cosmétique de Xen est son manager. Il permet de créer des machines virtuelles et d’attacher et détacher une console. KVM/QEMU utilise SDL pour créer une fenêtre présentant la console graphique. Il est également possible d’utiliser une connexion VNC. Mais tout cela n’est pas suffisant pour obtenir quelque chose de souple comme la commande xm de Xen.

Voici comment palier à cela avec un peu de configuration de base et GNU Screen…

La commande kvm dispose d’une option -nographic permettant de désactiver l’affichage graphique et de rediriger la console série du système guest (pas vraiment guest puisque c’est KVM) sur la console d’où à été lancé la commande. Côté kvm c’est donc tout simple. Reste à dire au système guest d’utiliser la console série exactement comme pour une configuration classique utilisant un TTY série.

Dans le système guest on commence par configurer Grub en ajoutant en début du fichier menu.lst :
serial –unit=0 –speed=9600 –word=8 –parity =no –stop=1
terminal –timeout=10 –dumb serial console
Bref, on utilise la console série en 9600 8N1. Toujours dans ce fichier, on ajoute les arguments pour le noyau sur la ligne kernel qui va bien :
console=tty0 console=ttyS0,9600n8
Grub, au prochain boot affichera ses informations sur la console série (attention, c’est moche, pas de beau menu coloré). Idem pour le noyau. Maintenant configurons le système lui-même pour permettre l’utilisation d’une console. Ceci est l’affaire de getty et se configure naturellement dans /etc/inittab :
T0:123:respawn:/sbin/getty -L ttyS0 9600 vt100
Cette ligne est normalement commentée et utilisée pour les runlevel 2 et 3 (second champ). On décommente et on précise un runlevel en plus (123 donc).

Dernier point, on s’assure que ttyS0 est bien un terminal considéré comme sûr :
% cat /etc/securetty | grep ttyS0
ttyS0
Parfait. Il ne reste plus qu’à stop le système guest et le relancer dans un screen :
% screen kvm -hda disk.cow -m 512 -net nic -net tap,ifname=tap10 -nographic
Et voilà. Total bonheur.

PS : Attention ! Configurer screen ou votre PS1 de manière à clairement différencier le guest de l’hôte. Lacher un reboot ou un init 0 dans la mauvaise console arrive très très facilement.

Debian et machine virtuelle KVM

Ayant dernièrement acheté une nouvelle configuration (Intel Core2Quad Q6600 sur ASRock 4CoreDual-SATA2) j’ai, bien entendu, décidé d’enfin jouer un peu avec la virtualisation et Xen 3.1. Malheureusement le kernel Xen basé sur un 2.6.18 n’intègre pas de support pour le contrôleur IDE de la carte mère (VIA vt8237s). On remarquera que le support existe dans des nouveau kernel mais ainsi qu’un hack pour le 2.6.18. Ubuntu dispose également d’un 2.6.22 « xenifié » sous forme de paquet .deb.

Ceci étant, plutôt que de le lancer dans d’immondes bidouilles j’ai tourné mon regard vers KVM, le support de virtualisation intégré au kernel. El là, suprise ! C’est convi, rapide et simple.

Installation des outils userspace :
% apt-get install kvm qemu
Chargement du module pour le support VT Intel :
% modprobe kvm-intel
Création d’une image disque de 5 giga en CoW (Copy on Write) pour économiser de la place (les 5Go ne sont pas réellement utilisés mais uniquement l’espace effectivement occupé par les données de l’image disque):
% qemu-img create disk.cow 5G
Lancement de kvm avec utilisation de l’image ISO d’installation de Debian 4.0 (avec 512Mo de mémoire pour le système) :
% kvm -hda disk.cow -cdrom /path/debian-40r1-i386-businesscard.iso -boot d -m 512
Installation classique minimale Debian… et enfin utilisation du système via :
% kvm -hda disk.cow -m 512
La configuration par défaut est entièrement automatique. Le système hébergé reçoit une adresse IP via DHCP et le routage est automatique. Ainsi la distribution Debian peut directement être mise à jour. C’est le système de routage userspace de KVM/QEMU. Ceci n’est pas très satisfaisant à mon goût.

Ne disposant que d’une seule interface ethernet matérielle dans le système hôte (nommée eth1 en raison d’un problème udev dont je parlerai pas ailleurs) l’idée de base est de créer un bridge ethernet reliant eth1 et une interface TUN/TAP.

Phase 1, on installe le paquet uml-utilities contenant l’utilitaire tunctl :
% apt-get install uml-utilities
On descend ensuite le réseau façon Debian :
% /etc/init.d/network stop
Puis on change /etc/network/interfaces comme ceci :
auto lo eth1 tap10 br0

iface lo inet loopback

iface tap10 inet manual
pre-up tunctl -b -u denis -t tap10
pre-up ifconfig tap10 up
post-down tunctl -d tap10

iface br0 inet static
bridge_ports eth1 tap10
bridge_maxwait 0
address 192.168.0.1
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.0.10

iface eth1 inet manual
Dans l’ordre, on configure le loopback puis eth1. On créé ensuite tap10 (tap0 est utilisé par ailleurs avec OpenVPN) et on bridge eth1 et tap10 en donnant une adresse au bridge. eth1 et tap10 sont donc maintenant physiquement connecté au même hub virtuel. tap10 est « le bout de câble » connecté à notre eth0 dans le système Debian tournant dans la KVM. On démarre celui-ci avec :
% kvm -hda disk.cow -m 512 -net nic -net tap,ifname=tap10
Dans le /etc/network/interfaces du système on trouve :
iface eth0 inet static
address 192.168.0.200
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.0.10
Et voilà, le tour est joué. Le système KVM est accessible depuis le système hôte via 192.168.0.200 comme s’il était sur le réseau (en fait, il l’est via le bridge).