Product SiteDocumentation Site

12.2. Virtualisation

La virtualisation est une des évolutions majeures de ces dernières années en informatique. Ce terme regroupe différentes abstractions simulant des machines virtuelles de manière plus ou moins indépendante du matériel. On peut ainsi obtenir, sur un seul ordinateur physique, plusieurs systèmes fonctionnant en même temps et de manière isolée. Les applications sont multiples et découlent souvent de cette isolation des différentes machines virtuelles : on peut par exemple se créer plusieurs environnements de test selon différentes configurations, ou héberger des services distincts sur des machines (virtuelles) distinctes pour des raisons de sécurité.
Il existe différentes mises en œuvre pour la virtualisation, chacune ayant ses avantages et ses inconvénients. Nous allons nous concentrer sur Xen, LXC et KVM, mais on peut aussi citer, à titre d'exemple :

12.2.1. Xen

Xen est une solution de « paravirtualisation », c'est-à-dire qu'elle insère entre le matériel et les systèmes supérieurs une fine couche d'abstraction, nommée « hyperviseur », dont le rôle est de répartir l'utilisation du matériel entre les différentes machines virtuelles qui fonctionnent dessus. Cependant, cet hyperviseur n'entre en jeu que pour une petite partie des instructions, le reste étant exécuté directement par le matériel pour le compte des différents systèmes. L'avantage est que les performances ne subissent pas de dégradation ; la contrepartie est que les noyaux des systèmes d'exploitation que l'on souhaite utiliser sur un hyperviseur Xen doivent être modifiés pour en tirer parti.
Explicitons un peu de terminologie. Nous avons vu que l'hyperviseur était la couche logicielle la plus basse, qui vient s'intercaler directement entre le noyau et le matériel. Cet hyperviseur est capable de séparer le reste du logiciel en plusieurs domaines, correspondant à autant de machines virtuelles. Parmi ces domaines, le premier à être lancé, désigné sous l'appellation dom0, joue un rôle particulier, puisque c'est depuis ce domaine (et seulement celui-là) qu'on pourra contrôler l'exécution des autres. Ces autres domaines sont, quant à eux, appelés domU. Le terme « dom0 » correspond donc au système « hôte » d'autres mécanismes de virtualisation, « domU » correspondant aux « invités ».
Pour utiliser Xen sous Debian, trois composants sont nécessaires :
  • L'hyperviseur proprement dit. Selon le type de matériel dont on dispose, on installera xen-hypervisor-4.4-amd64, xen-hypervisor-4.4-armhf ou xen-hypervisor-4.4-arm64.
  • Un noyau qui fonctionne sur cet hyperviseur. Tout noyau plus récent que 3.0 conviendra, y compris la version 3.16 présente dans Jessie.
  • Une bibliothèque standard modifiée pour tirer parti de Xen. Pour cela, on installera le paquet libc6-xen (valable uniquement sur architecture i386).
Pour se simplifier la vie, on installera un des métapaquets auxiliaires, tel que xen-linux-system-amd64, qui dépend d'une combinaison réputée stable de versions de l'hyperviseur et du noyau. L'hyperviseur recommande également le paquet xen-utils-4.4, lequel contient les utilitaires permettant de contrôler l'hyperviseur depuis le dom0. Et ce dernier (tout comme le noyau Xen) recommande la bibliothèque standard modifiée. Lors de l'installation de ces paquets, les scripts de configuration créent une nouvelle entrée dans le menu du chargeur de démarrage Grub, permettant de démarrer le noyau choisi dans un dom0 Xen. Attention toutefois, cette nouvelle entrée n'est pas celle démarrée en standard. Pour lister les entrées correspondant à l'hyperviseur Xen en premier, vous pouvez exécuter ces commandes :
# mv /etc/grub.d/20_linux_xen /etc/grub.d/09_linux_xen
# update-grub
Une fois cette installation effectuée, il convient de tester le fonctionnement du dom0 seul, donc de redémarrer le système avec l'hyperviseur et le noyau Xen. À part quelques messages supplémentaires sur la console lors de l'initialisation, le système démarre comme d'habitude.
Il est donc temps de commencer à installer des systèmes sur les domU. Nous allons pour cela utiliser le paquet xen-tools. Ce paquet fournit la commande xen-create-image, qui automatise en grande partie la tâche. Son seul paramètre obligatoire est --hostname, qui donne un nom au domU ; d'autres options sont importantes, mais leur présence sur la ligne de commande n'est pas nécessaire parce qu'elles peuvent être placées dans le fichier de configuration /etc/xen-tools/xen-tools.conf. On prendra donc soin de vérifier la teneur de ce fichier avant de créer des images, ou de passer des paramètres supplémentaires à xen-create-image lors de son invocation. Notons en particulier :
  • --memory, qui spécifie la quantité de mémoire vive à allouer au système créé ;
  • --size et --swap, qui définissent la taille des « disques virtuels » disponibles depuis le domU ;
  • --debootstrap, qui spécifie que le système doit être installé avec debootstrap ; si l'on utilise cette option, il sera important de spécifier également --dist avec un nom de distribution (par exemple jessie).
  • --dhcp spécifie que la configuration réseau du domU doit être obtenue par DHCP ; au contraire, --ip permet de spécifier une adresse IP statique.
  • Enfin, il faut choisir une méthode de stockage pour les images à créer (celles qui seront vues comme des disques durs dans le domU). La plus simple, déclenchée par l'option --dir, est de créer un fichier sur le dom0 pour chaque périphérique que l'on souhaite fournir au domU. L'autre possibilité, sur les systèmes utilisant LVM, est de passer par le biais de l'option --lvm le nom d'un groupe de volumes, dans lequel xen-create-image créera un nouveau volume logique ; ce volume logique sera rendu disponible au domU comme un disque dur.
Lorsque ces choix sont faits, nous pouvons créer l'image de notre futur domU Xen :
# 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
Nous disposons à présent d'une machine virtuelle, mais actuellement éteinte, qui n'occupe de la place que sur le disque dur du dom0. Nous pouvons bien entendu créer plusieurs images, avec des paramètres différents au besoin.
Avant d'allumer ces machines virtuelles, il reste à définir la manière d'accéder aux domU. Il est possible de les considérer comme des machines isolées et de n'accéder qu'à leur console système, mais ce n'est guère pratique. La plupart du temps, on pourra se contenter de considérer les domU comme des serveurs distants et de les contacter comme à travers un réseau. Cependant, il serait peu commode de devoir ajouter une carte réseau pour chaque domU ! Xen permet donc de créer des interfaces virtuelles, que chaque domaine peut voir et présenter à l'utilisateur de la manière habituelle. Cependant, ces cartes, même virtuelles, doivent pour être utiles être raccordées à un réseau, même virtuel. Xen propose pour cela plusieurs modèles de réseau :
  • En mode pont (bridge), toutes les cartes réseau eth0 (pour le dom0 comme pour les domU) se comportent comme si elles étaient directement branchées sur un commutateur Ethernet (switch). C'est le mode le plus simple.
  • En mode routage, le dom0 est placé entre les domU et le réseau extérieur (physique) ; il joue un rôle de routeur.
  • En mode traduction d'adresse (NAT), le dom0 est également placé entre les domU et le reste du réseau ; cependant, les domU ne sont pas accessibles directement depuis l'extérieur, le trafic subissant de la traduction d'adresses sur le dom0.
Ces trois modes mettent en jeu un certain nombre d'interfaces aux noms inhabituels, comme vif*, veth*, peth* et xenbr0, qui sont mises en correspondance selon différents agencements par l'hyperviseur Xen, contrôlé par les utilitaires en espace utilisateur. Nous ne nous attarderons pas ici sur les modes NAT et routage, qui ne présentent d'intérêt que dans des cas particuliers.
La configuration standard des paquets Debian de Xen n'effectue aucune modification à la configuration réseau du système. En revanche, le démon xend est configuré pour intégrer les cartes réseau virtuelles dans n'importe quel pont pré-existant (si plusieurs existent, c'est xenbr0 qui est retenu). Il convient donc de mettre en place un pont dans /etc/network/interfaces (cela nécessite le paquet bridge-utils qui est recommandé par xen-utils-4.4) en remplaçant l'entrée existante pour eth0 :
auto xenbr0
iface xenbr0 inet dhcp
    bridge_ports eth0
    bridge_maxwait 0
Après un redémarrage pour vérifier que le pont est bien créé de manière automatique, nous pouvons maintenant démarrer le domU grâce aux outils de contrôle de Xen, en particulier la commande xl. Cette commande permet d'effectuer différentes manipulations sur les domaines, notamment de les lister, de les démarrer et de les éteindre.
# 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
On notera que le domU testxen occupe de la mémoire vive réelle, qui est prise sur celle disponible pour le dom0 (il ne s'agit pas de mémoire vive simulée). Il sera donc important de bien dimensionner la mémoire vive d'une machine que l'on destine à héberger des instances Xen.
Voilà ! Notre machine virtuelle démarre. Pour y accéder, nous avons deux possibilités. La première est de s'y connecter « à distance », à travers le réseau (comme pour une machine réelle, cependant, il faudra probablement mettre en place une entrée dans le DNS, ou configurer un serveur DHCP). La seconde, qui peut être plus utile si la configuration réseau du domU était erronée, est d'utiliser la console hvc0. On utilisera pour cela la commande xl console :
# xl console testxen
[...]

Debian GNU/Linux 8 testxen hvc0

testxen login: 
On peut ainsi ouvrir une session, comme si l'on était au clavier de la machine virtuelle. Pour détacher la console, on utilisera la combinaison de touches Ctrl+].
Une fois que le domU est fonctionnel, on peut s'en servir comme d'un serveur classique (c'est un système GNU/Linux, après tout). Mais comme il s'agit d'une machine virtuelle, on dispose de quelques fonctions supplémentaires. On peut par exemple le mettre en pause temporairement, puis le débloquer, avec les commandes xl pause et xl unpause. Un domU en pause cesse de consommer de la puissance de processeur, mais sa mémoire lui reste allouée. La fonction de sauvegarde (xl save) et celle de restauration associée (xl restore) seront donc peut-être plus intéressantes. En effet, une sauvegarde d'un domU libère les ressources utilisées par ce domU, y compris la mémoire vive. Lors de la restauration (comme d'ailleurs après une pause), le domU ne s'aperçoit de rien de particulier, sinon que le temps a passé. Si un domU est toujours en fonctionnement lorsqu'on éteint le dom0, il sera automatiquement sauvegardé ; au prochain démarrage, il sera automatiquement restauré et remis en marche. Bien entendu, on aura les inconvénients que l'on peut constater par exemple lors de la suspension d'un ordinateur portable ; en particulier, si la suspension est trop longue, les connexions réseau risquent d'expirer. Notons en passant que Xen est pour l'instant incompatible avec une grande partie de la gestion de l'énergie ACPI, ce qui inclut la suspension (software suspend) du système hôte (dom0).
Pour éteindre ou redémarrer un domU, on pourra soit exécuter la commande shutdown à l'intérieur de ce domU, soit utiliser, depuis le dom0, xl shutdown ou xl reboot.

12.2.2. LXC

Bien qu'il soit utilisé pour construire des « machines virtuelles », LXC n'est pas à proprement parler une solution de virtualisation. C'est en réalité un système permettant d'isoler des groupes de processus sur un même système. Il tire parti pour cela d'un ensemble d'évolutions récentes du noyau Linux, regroupées sous le nom de control groups, et qui permettent de donner des visions différentes de certains aspects du système à des ensembles de processus appelés groupes. Parmi ces aspects du système figurent notamment les identifiants de processus, la configuration réseau et les points de montage. Un groupe de processus ainsi isolés n'aura pas accès aux autres processus du système et son accès au système de fichiers pourra être restreint à un sous-ensemble prédéfini. Il aura également accès à sa propre interface réseau, sa table de routage, éventuellement à un sous-ensemble des périphériques présents, etc.
Si l'on tire parti de ces fonctions, on peut isoler de la sorte tout une famille de processus depuis le processus init et on obtient un ensemble qui se rapproche énormément d'une machine virtuelle. L'appellation officielle est « un conteneur » (ce qui donne son nom à LXC, pour LinuX Containers), mais la principale différence avec une machine virtuelle Xen ou KVM tient au fait qu'il n'y a pas de deuxième noyau ; le conteneur utilise le même noyau que la machine hôte. Cela présente des avantages comme des inconvénients : parmi les avantages, citons les excellentes performances grâce à l'absence d'hyperviseur et de noyau intermédiaire, le fait que le noyau peut avoir une vision globale des processus du système et peut donc ordonnancer leur exécution de manière plus efficace que si deux noyaux indépendants essayaient d'ordonnancer des ensembles de processus sans cette vision d'ensemble. Parmi les inconvénients, citons qu'il n'est pas possible d'avoir une machine virtuelle avec un noyau différent (qu'il s'agisse d'un autre système d'exploitation ou simplement d'une autre version de Linux).
Comme il s'agit d'isolation et non de virtualisation complète, la mise en place de conteneurs LXC est un peu plus complexe que la simple utilisation de debian-installer sur une machine virtuelle. Après quelques préliminaires, il s'agira de mettre en place une configuration réseau, puis de créer le système qui sera amené à fonctionner dans le conteneur.

12.2.2.1. Préliminaires

Les utilitaires requis pour faire fonctionner LXC sont inclus dans le paquet lxc, qui doit donc être installé avant toute chose.
LXC a également besoin du système de paramétrage des control groups. Ce dernier se présente comme un système de fichiers virtuels à monter dans /sys/fs/cgroup. Comme Debian 8 utilise par défaut systemd, qui a aussi besoin des control groups, cette opération est effectuée automatiquement au démarrage, et il n'est plus besoin de configuration supplémentaire.

12.2.2.2. Configuration réseau

Nous cherchons à utiliser LXC pour mettre en place des machines virtuelles ; il est possible de les laisser isolées du réseau et de ne communiquer avec elles que par le biais du système de fichiers, mais il sera dans la plupart des cas pertinent de donner aux conteneurs un accès, au moins minimal, au réseau. Dans le cas typique, chaque conteneur aura une interface réseau virtuelle et la connexion au vrai réseau passera par un pont. Cette interface virtuelle peut être soit branchée sur l'interface physique de la machine hôte, auquel cas le conteneur est directement sur le réseau, soit branchée sur une autre interface virtuelle de l'hôte, qui pourra ainsi filtrer ou router le trafic de manière fine. Dans les deux cas, il faudra installer le paquet bridge-utils.
Dans le cas simple, il s'agit de modifier /etc/network/interfaces pour créer une interface br0, y déplacer la configuration de l'interface physique (eth0 par exemple) et y ajouter le lien entre les deux. Ainsi, si le fichier de définitions des interfaces standard contient initialement des lignes comme celles-ci :
auto eth0
iface eth0 inet dhcp
Il faudra les désactiver et les remplacer par :
#auto eth0
#iface eth0 inet dhcp

auto br0
iface br0 inet dhcp
  bridge-ports eth0
Cette configuration aura un résultat similaire à celui qui serait obtenu si les conteneurs étaient des machines branchées sur le même réseau physique que la machine hôte. La configuration en « pont » s'occupe de faire transiter les trames Ethernet sur toutes les interfaces connectées au pont, c'est-à-dire l'interface physique eth0 mais aussi les interfaces qui seront définies pour les conteneurs.
Si l'on ne souhaite pas utiliser cette configuration, par exemple parce qu'on ne dispose pas d'adresse IP publique à affecter aux conteneurs, on créera une interface virtuelle tap que l'on intègrera au pont. On aura alors une topologie de réseau similaire à ce que l'on aurait avec une deuxième carte réseau sur l'hôte, branchée sur un switch séparé, avec les conteneurs branchés sur ce même switch. L'hôte devra donc faire office de passerelle pour les conteneurs si l'on souhaite que ceux-ci puissent communiquer avec l'extérieur.
Pour cette configuration riche, on installera, en plus de bridge-utils, le paquet vde2 ; le fichier /etc/network/interfaces peut alors devenir :
# Interface eth0 inchangée
auto eth0
iface eth0 inet dhcp

# Interface virtuelle
auto tap0
iface tap0 inet manual
  vde2-switch -t tap0

# Pont pour les conteneurs
auto br0
iface br0 inet static
  bridge-ports tap0
  address 10.0.0.1
  netmask 255.255.255.0
On pourra ensuite soit configurer le réseau de manière statique dans les conteneurs, soit installer sur l'hôte un serveur DHCP configuré pour répondre aux requêtes sur l'interface br0.

12.2.2.3. Mise en place du système

Nous allons maintenant mettre en place le système de fichiers qui sera utilisé par le conteneur. Comme cette « machine virtuelle » ne fonctionnera pas directement sur le matériel, certains ajustements sont nécessaires par rapport à un système de fichiers classique, notamment en ce qui concerne le noyau, les périphériques et les consoles. Fort heureusement, le paquet lxc contient des scripts qui automatisent en grande partie cette mise en place. Ainsi, pour créer un conteneur Debian, on pourra utiliser les commandes suivantes (qui auront besoin des paquets debootstrap et rsync) :
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:~# 
On notera que le système de fichiers est initialement généré dans /var/cache/lxc, puis copié vers le répertoire de destination ; cela permet de créer d'autres systèmes de fichiers identiques beaucoup plus rapidement, puisque seule la copie sera nécessaire.
Signalons que le script de création de template Debian accepte une option --arch pour spécifier l'architecture du système à installer ainsi qu'une option --release si l'on souhaite une version de Debian autre que la version stable actuelle. Vous pouvez également définir la variable d'environnement MIRROR pour indiquer un miroir Debian local à utiliser.
Le système de fichiers nouvellement créé contient désormais un système Debian minimal. Le conteneur associé n'a aucun périphérique réseau (mis à part la boucle locale). Puisque cela n'est pas vraiment souhaitable, nous éditerons le fichier de configuration du conteneur (/var/lib/lxc/testlxc/config) et ajouterons ces quelques directives lxc.network.* :
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.hwaddr = 4a:49:43:49:79:20
Ces lignes signifient respectivement qu'une interface virtuelle sera créée dans le conteneur, qu'elle sera automatiquement activée au démarrage dudit conteneur, qu'elle sera automatiquement connectée au pont br0 de l'hôte et qu'elle aura l'adresse MAC spécifiée. Si cette dernière instruction est absente, ou désactivée, une adresse aléatoire sera utilisée.
Une autre instruction utile est celle qui définit le nom d'hôte :
lxc.utsname = testlxc

12.2.2.4. Lancement du conteneur

Maintenant que notre image de machine virtuelle est prête, nous pouvons démarrer le conteneur :
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:~# 
Nous voilà ainsi dans le conteneur, d'où nous n'avons accès qu'aux processus lancés depuis le conteneur lui-même et qu'au sous-ensemble dédié du système de fichiers (/var/lib/lxc/testlxc/rootfs). Nous pouvons quitter la console avec la combinaison de touches Ctrl+a suivie de q.
Notons que l'on a démarré le conteneur en tâche de fond, grâce à l'option --daemon de lxc-start. On pourra ensuite l'interrompre par lxc-stop --name=testlxc.
Le paquet lxc contient un script d'initialisation qui peut démarrer automatiquement un ou plusieurs conteneurs lors du démarrage de l'ordinateur (il utilise lxc-autostart, qui démarre les conteneurs dont l'option lxc.start.auto est réglée à 1). Un contrôle plus fin de l'ordre de démarrage est possible, grâce aux options lxc.start.order et lxc.group : par défaut, le script d'initialisation démarre d'abord les conteneurs qui sont dans le groupe onboot, puis ceux qui ne font partie d'aucun groupe. Dans les deux cas, l'ordre de lancement au sein d'un groupe est contrôlé par l'option lxc.start.order.

12.2.3. Virtualisation avec KVM

KVM (Kernel-based Virtual Machine, « machine virtuelle basée sur le noyau ») est avant tout un module noyau facilitant la mise en place de machines virtuelles. L'application que l'on utilise pour démarrer et contrôler ces machines virtuelles est dérivée de QEMU. Ne vous étonnez donc pas si l'on fait appel à des commandes qemu-* dans cette section traitant de KVM .
Contrairement aux autres solutions de virtualisation, KVM a été intégré au noyau Linux dès ses débuts. Le choix de s'appuyer sur les jeux d'instructions dédiés à la virtualisation (Intel-VT ou AMD-V) permet à KVM d'être léger, élégant et peu gourmand en ressources. La contrepartie est qu'il ne fonctionne pas sur tous les ordinateurs, mais seulement ceux disposant de processeurs adaptés. Pour les ordinateurs à base de x86, vous pouvez vérifier que votre processeur dispose des jeux d'instructions requis en cherchant « vmx » ou « svm » dans les drapeaux du processeur listés dans /proc/cpuinfo.
Grâce à Red Hat soutenant activement son développement, KVM est plus ou moins devenu la référence pour la virtualisation sous Linux.

12.2.3.1. Préliminaires

Contrairement à des outils comme Virtualbox, KVM ne dispose pas en standard d'interface pour créer et gérer les machines virtuelles. Le paquet qemu-kvm se contente de fournir un exécutable du même nom (qui sert à démarrer une machine virtuelle) et un script de démarrage qui charge les modules nécessaires.
Fort heureusement, Red Hat fournit aussi la solution à ce problème puisqu'ils développent libvirt et les outils associés virtual-manager. libvirt est une bibliothèque qui permet de gérer des machines virtuelles de manière uniforme, quelle que soit la technologie de virtualisation employée. À l'heure actuelle, libvirt gère QEMU, KVM, Xen, LXC, OpenVZ, VirtualBox, VMWare et UML. virtual-manager est une interface graphique exploitant libvirt pour créer et gérer des machines virtuelles.
Installons donc tous les paquets requis avec apt-get install qemu-kvm libvirt-bin virtinst virtual-manager virt-viewer. libvirt-bin fournit le démon libvirtd qui sert à gérer des machines virtuelles (éventuellement à distance) et qui va mettre en route les machines virtuelles requises au démarrage du serveur. En outre, le paquet fournit virsh, un outil en ligne de commande qui permet de contrôler les machines virtuelles gérées par libvirtd.
virtinst fournit quant à lui virt-install qui sert à créer des machines virtuelles depuis la ligne de commande. Enfin, virt-viewer permet d'accéder à la console graphique d'une machine virtuelle.

12.2.3.2. Configuration réseau

Tout comme avec Xen ou LXC, la configuration la plus courante pour des serveurs publics consiste à configurer un pont dans lequel seront intégrées les interfaces réseau des machines virtuelles (voir Section 12.2.2.2, « Configuration réseau »).
Alternativement, la configuration par défaut employée par KVM est d'attribuer une adresse privée à la machine virtuelle (dans la plage 192.168.122.0/24) et de faire du NAT pour que la machine ait un accès au réseau extérieur.
Dans la suite de cette section, nous supposerons qu'un pont br0 a été configuré et que l'interface réseau physique eth0 y a été intégrée.

12.2.3.3. Installation avec virt-install

La création d'une machine virtuelle est très similaire à l'installation d'une machine normale, sauf que toutes les caractéristiques de la machine sont décrites par une ligne de commande à rallonge.
En pratique, cela veut dire que nous allons utiliser l'installateur Debian en démarrant sur un lecteur de DVD-Rom virtuel associé à une image ISO d'un DVD Debian. La machine virtuelle exportera la console graphique via le protocole VNC (voir explications en Section 9.2.2, « Accéder à distance à des bureaux graphiques ») et nous pourrons donc contrôler le déroulement de l'installation par ce biais.
En préalable, nous allons indiquer à libvirtd l'emplacement où nous allons stocker les images disques. Ce n'est nécessaire que si l'on souhaite utiliser un autre emplacement que celui par défaut (/var/lib/libvirt/images/).
root@mirwiz:~# mkdir /srv/kvm
root@mirwiz:~# virsh pool-create-as srv-kvm dir --target /srv/kvm
Pool srv-kvm created

root@mirwiz:~# 
Lançons maintenant l'installation de la machine virtuelle et regardons de plus près la signification des options les plus importantes de virt-install. Cette commande va enregistrer la machine virtuelle et ses paramètres auprès de libvirtd, puis la démarrer une première fois afin que l'on puisse effectuer l'installation.
# 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

L'option --connect permet d'indiquer l'hyperviseur à gérer. L'option prend la forme d'une URL indiquant à la fois la technologie de virtualisation (xen://, qemu://, lxc://, openvz://, vbox://, etc.) et la machine hôte (qui est laissée vide lorsque l'hôte est la machine locale). En outre, dans le cas de QEMU/KVM, chaque utilisateur peut gérer des machines virtuelles qui fonctionneront donc avec des droits limités et le chemin de l'URL permet de distinguer les machines « systèmes » (/system) des autres (/session).

2

KVM se gérant de manière similaire à QEMU, l'option --virt-type kvm précise que l'on souhaite employer KVM même si l'URL de connexion précise indique QEMU.

3

L'option --name définit l'identifiant (unique) que l'on attribue à la machine virtuelle.

4

L'option --ram définit la quantité de mémoire vive à allouer à la machine virtuelle (en Mo).

5

L'option --disk indique l'emplacement du fichier image qui va représenter le disque dur de notre machine virtuelle. Si le fichier n'existe pas, il est créé en respectant la taille en Go indiquée dans le paramètre size. Le paramètre format permet de stocker le disque virtuel de différentes manières. Le format par défaut (raw) est un fichier de la taille exacte du disque, copie exacte de son contenu. Le format retenu ici est un peu plus avancé (et spécifique à QEMU) et permet de démarrer avec un petit fichier dont la taille augmente au fur et à mesure que l'espace disque est réellement utilisé par la machine virtuelle.

6

L'option --cdrom indique où trouver l'image ISO du CD-Rom qui va servir à démarrer l'installateur. On peut aussi bien indiquer un chemin local d'un fichier ISO, une URL où l'image peut être récupérée, ou encore un périphérique bloc correspondant à un vrai lecteur de CD-Rom (i.e. /dev/cdrom).

7

L'option --network indique comment la carte réseau virtuelle doit s'intégrer dans la configuration réseau de l'hôte. Le comportement par défaut (que nous forçons ici) est de l'intégrer dans tout pont (bridge) pré-existant. En l'absence de pont, la machine virtuelle n'aura accès au LAN que par du NAT et obtient donc une adresse dans un sous-réseau privé (192.168.122.0/24).

8

--vnc demande que la console graphique soit mise à disposition par VNC. Par défaut, le serveur VNC associé n'écoute que sur l'interface locale (localhost). Si le client VNC est exécuté depuis une autre machine, il faudra mettre en place un tunnel SSH pour établir la connexion (voir Section 9.2.1.3, « Créer des tunnels chiffrés avec le port forwarding »). Alternativement, on peut passer l'option --vnclisten=0.0.0.0 pour demander que le serveur VNC soit accessible depuis toutes les interfaces, mais dans ce cas vous avez intérêt à prévoir des règles adéquates dans le pare-feu.

9

Les options --os-type et --os-variant permettent d'optimiser quelques paramètres de la machine virtuelle en fonction des caractéristiques connues du système d'exploitation indiqué.
À ce stade, la machine virtuelle est démarrée et il faut se connecter à la console graphique pour effectuer l'installation. Si l'opération a été effectuée depuis un bureau graphique, la console graphique a été automatiquement lancée. Autrement, on peut en démarrer une sur un autre poste à l'aide de virt-viewer :
$ virt-viewer --connect qemu+ssh://root@serveur/system
root@serveur's password: 
root@serveur's password: 
À la fin de l'installation, la machine virtuelle est redémarrée. Elle est désormais prête à l'emploi.

12.2.3.4. Gestion des machines avec virsh

L'installation étant terminée, il est temps de voir comment manipuler les machines virtuelles disponibles. La première commande permet de lister les machines gérées par libvirtd :
# virsh -c qemu:///system list --all
 Id Name                 State
----------------------------------
  - testkvm              shut off
Démarrons notre machine virtuelle de test :
# virsh -c qemu:///system start testkvm
Domain testkvm started
Cherchons à obtenir les informations de connexion à la console graphique (le port d'affichage VNC renvoyé peut être passé en paramètre à vncviewer) :
# virsh -c qemu:///system vncdisplay testkvm
:0
Parmi les autres commandes disponibles dans virsh, on trouve :
  • reboot pour initier un redémarrage ;
  • shutdown pour arrêter proprement une machine virtuelle ;
  • destroy pour la stopper brutalement ;
  • suspend pour la mettre en pause ;
  • resume pour la sortir de pause ;
  • autostart pour activer (ou désactiver lorsque l'option --disable est employée) le démarrage automatique d'une machine virtuelle au démarrage de l'hôte ;
  • undefine pour effacer toute trace de la machine virtuelle au sein de libvirtd.
Toutes ces commandes prennent en paramètre un identifiant de machine virtuelle.

12.2.3.5. Installer un système basé sur RPM avec yum sur Debian

Si la machine virtuelle doit faire fonctionner Debian (ou une de ses dérivées), le système peut être initialisé avec debootstrap, comme décrit précédemment. En revanche si la machine virtuelle doit être installée avec un système basé sur RPM (comme Fedora, CentOS ou Scientific Linux), la mise en place sera faite avec l'outil yum (disponible dans le paquet de même nom).
La procédure implique d'utiliser rpm pour extraire un ensemble de fichiers initiaux, notamment les fichiers de configuration de yum, puis d'appeler yum pour extraire le reste des paquets. Mais comme yum est appelé depuis l'extérieur du chroot, il est nécessaire d'effectuer quelques changements temporaires. Dans l'exemple ci-dessous, le chroot cible est situé dans /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