Howto KVM
- Installation
- Utilisation basique de libvirt
- Configuration
- Création d’une VM
- Stockage
- Réseau
- Snapshots
- Mode monitor
- virsh
- Cloner une VM
- Migrer une VM
- Renommer une VM
- Systemd
- Modifier les ressources d’une VM
- Monitoring
- Déduplication de pages mémoire avec KSM
- FAQ
- Erreur avec certaines commandes virsh
- En Debian 8, je ne trouve pas kvm-img
- Soucis réseau avec machine clonée
- Installation d’une VM sans libvirt
- Accéder à virt-manager sur un hyperviseur
- Désactiver l’interface réseau d’une VM à chaud
- Tips performance
- Étendre une image RAW
- Étendre un volume disque à chaud
- Erreur “Unable to create cgroup”
- Souci d’allocation CPU
- Problème lors de l’installation
- Le bloc nécessaire pour une iso
- Disposition qwerty
- Virtualisation imbriquée
- Machine reboot lors du boot sur fichier .iso pour installation d’un systeme (Debian ou autre).
- Erreur de redémarrage d’une machine virtuelle
- Erreur de connection en tant qu’utilisateur
- Erreur de migration de VM relative à AppArmor
- Nested
- Documentation KVM : http://www.linux-kvm.org/page/Documents
- Documentation libvirt : https://libvirt.org/docs.html
- virsh(1) : https://manpages.debian.org/bullseye/libvirt-clients/virsh.1.en.html
- Statut de cette page : prod / bullseye
KVM est une technologie de virtualisation intégrée au noyau Linux. On l’utilise avec libvirt, une surcouche qui facilite l’utilisation de la virtualisation.
Installation
Pour installer un hyperviseur (machine capable de faire tourner des machines virtuelles) :
# apt install qemu-kvm bridge-utils qemu-utils libvirt-daemon-system libvirt-clients virtinst netcat-openbsd
$ kvm --version
QEMU emulator version 5.2.0 (Debian 1:5.2+dfsg-11+deb11u2)
Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers
$ virsh -V
Virsh command line tool of libvirt 7.0.0
See web site at https://libvirt.org/
Compiled with support for:
Hypervisors: QEMU/KVM LXC LibXL OpenVZ VMware VirtualBox ESX Test
Networking: Remote Network Bridging Interface netcf Nwfilter
Storage: Dir Disk Filesystem SCSI Multipath iSCSI LVM RBD Gluster ZFS
Miscellaneous: Daemon Nodedev AppArmor SELinux Secrets Debug DTrace Readline
Installation de virt-manager :
# apt install virt-manager spice-client-gtk gir1.2-spice-client-gtk-3.0
Utilisation basique de libvirt
Un démon libvirtd tourne sur l’hyperviseur, il peut être redémarré sans impact sur les VMs :
# systemctl restart libvirtd
La commande virsh permet de réaliser des opérations en ligne de commande :
# virsh list --all
# virsh start <vm-name>
# virsh shutdown <vm-name>
# virsh destroy <vm-name>
# virsh edit <vm-name>
Pour un accès « graphique », installer sur le poste client :
# apt install virt-manager netcat-openbsd
- Ajoutez chaque administrateur dans le groupe libvirt ;
- Démarrez
virt-manager
sur votre poste et ajoutez une connexion à un hôte distant via SSH.
Note : Il est déconseillé de se connecter directement en root.
Les VMs définies pour tourner sur l’hyperviseur ont un fichier de définition
XML dans le répertoire /etc/libvirt/qemu/
.
Configuration
Un hyperviseur KVM doit avoir des CPUs supportant la virtualisation, une bonne quantité de RAM, une configuration réseau spécifique et l’accès à du stockage adapté à votre utilisation (si besoin, un SAN ou un setup DRBD/LVM).
Configuration CPU
Un hyperviseur KVM doit avoir des CPUs supportant la virtualisation.
Cela s’active en général via le BIOS de la machine. Si ce
n’est pas activé, vous aurez une erreur
KVM: disabled by BIOS
CPU pinning
Le CPU pinning permet d’attacher un processus à un CPU particulier. La machine virtuelle ne pourra alors utiliser que les CPU que l’hyperviseur lui a associés. Ça permet par exemple de limiter le problème d’invalidation du cache CPU.
Pour choisir les CPU, on peut s’appuyer sur les informations sur la
topologie du processeur avec la commande lspcu
.
$ lscpu -e=cpu,core,cache
CPU CORE L1d:L1i:L2:L3
0 0 0:0:0:0
1 1 1:1:1:0
2 2 2:2:2:0
3 3 3:3:3:0
4 4 4:4:4:1
5 5 5:5:5:1
6 6 6:6:6:1
7 7 7:7:7:1
8 0 0:0:0:0
9 1 1:1:1:0
10 2 2:2:2:0
11 3 3:3:3:0
12 4 4:4:4:1
13 5 5:5:5:1
14 6 6:6:6:1
15 7 7:7:7:1
On voit ici que les CPU 4 et 12 (1ère colonne) sont dans le même core (2ème colonne). Les CPU 4 à 7 et 12 à 15 partagent le même cache L3 (3ème colonne, dernier caractère). La configuration XML ci-dessous associe à la machine virtuelle les CPU 4 à 7 et 12 à 15.
<domain>
[…]
<vcpu placement='static'>8</vcpu>
<cputune>
<vcpupin vcpu='0' cpuset='4'/>
<vcpupin vcpu='1' cpuset='12'/>
<vcpupin vcpu='2' cpuset='5'/>
<vcpupin vcpu='3' cpuset='13'/>
<vcpupin vcpu='4' cpuset='6'/>
<vcpupin vcpu='5' cpuset='14'/>
<vcpupin vcpu='6' cpuset='7'/>
<vcpupin vcpu='7' cpuset='15'/>
</cputune>
[…]
La machine virtuelle ne pourra utiliser que ces processur, mais ça n’empêchera pas des processus de l’hôte de les utiliser aussi. Pour empêcher ça, il faudra isoler les CPU.
Configuration mémoire
On conseille d’avoir une certaine marge de RAM par rapport à la somme de la mémoire allouée à chaque VM, surtout si vous activez du cache au niveau des disques des VMs (ce qui est conseillé pour de bonnes performances).
On conseille également de configurer au moins 10 Go de swap sur l’hyperviseur afin d’éviter que le mécanisme Out-Of-Memory Killer ne se déclenche au moindre pic de mémoire.
Enfin, on conseille d’ajuster le paramètre oom_score_adj
entre les machines critiques et non critiques :
@hourly test -s /var/run/libvirt/qemu/VM-non-critique.pid && echo '800' > /proc/$(cat /var/run/libvirt/qemu/VM-non-critique.pid)/oom_score_adj
@hourly test -s /var/run/libvirt/qemu/VM-critique.pid && echo '-800' > /proc/$(cat /var/run/libvirt/qemu/VM-critique.pid)/oom_score_adj
Configuration réseau
On conseille l’utilisation du mode bridge pour le
réseau.
On crée un bridge br0
liée à l’interface eth0
:
# brctl addbr br0
Puis on ajuste le fichier /etc/network/interfaces
ainsi
:
#source-directory /etc/network/interfaces.d
auto eth0
iface eth0 inet manual
auto br0
iface br0 inet static
address <address>/<netmask>
gateway <gateway>
bridge_ports eth0
up echo 0 > /sys/class/net/br0/bridge/multicast_snooping
Note 1 : il est nécessaire de désactiver le multicast_snooping pour assurer un bon fonctionnement d’IPv6
Note 2 : il est nécessaire de commenter
source-directory /etc/network/interfaces.d
car cela fait boguer libvirt
/!\ : s’assurer d’avoir bien installé bridge-utils et configuré le firewall avant de redémarrer
On conseille aussi de ne pas faire transiter les paquets par
iptables
, cela a notamment l’avantage de ne pas créer
d’états quand les paquets transitent vers les machines virtuelles :
sysctl -w net.bridge.bridge-nf-call-iptables=0
echo "net.bridge.bridge-nf-call-iptables=0" >> /etc/sysctl.d/zzz-evolinux_custom.conf
On conseille aussi d’optimiser la partie réseau du noyau : https://wiki.evolix.org/HowtoDebian/Reseau#haute-performance
Configuration stockage
https://libvirt.org/storage.html
Nous utilisons principalement :
- Volumes DRBD over LVM (supporte les migrations à chaud)
- Format QCOW2 (supporte les snapshots à chaud)
- Format RAW (un peu plus performant que QCOW2)
Gestion hyperviseur
En cas de souci, il est important de connaître l’état de l’hyperviseur. On met donc en place des crons du type :
@hourly rsync -a --delete /etc/libvirt/qemu/*xml kvm2.example.com:/root/libvirt-kvm/
@daily virsh list |ssh kvm2.example.com "cat >/root/libvirt-kvm/virsh-list.txt"
Création d’une VM
virt-install
Avoir un ISO disponible sur l’hyperviseur (pour Debian, télécharger l’ISO netinst sur http://cdimage.debian.org/debian-cd/current/amd64/iso-cd/) puis l’on crée une VM ainsi :
# virt-install --connect=qemu:///system \
--name=template \
--cpu mode=host-passthrough --vcpus=1 \
--ram=512 \
--disk path=/path/template.qcow2,bus=virtio,cache=none,size=42,format=qcow2 \
--network=bridge:br0,model=virtio \
--noautoconsole --graphics vnc,listen=127.0.0.1,keymap=fr \
--cdrom=/home/images/debian-8.6.0-amd64-netinst.iso
Notes :
--cpu mode=host-passthrough
signifie que le CPU virtualisé sera identique au CPU de l’hyperviseur, en cas de migration vers un autre hyperviseur il devra avoir un CPU strictement identiquel’exemple utilise (ou crée si il n’existe pas) un fichier QCOW2 de 42 Go, on pourra évidemment choisir d’autres types de stockage ; LVM :
--disk path=/dev/VG_name/LV_name,bus=virtio,cache=none,format=raw,io=threads
; DRBD :--disk path=/dev/drbd/by-disk/VG_name/LV_name,bus=virtio,cache=none,format=raw,io=threads
si l’on a besoin de performances élevées en I/O, on pourra mettre l’option
cache=writeback
pour –disksi besoin de plusieurs disques ou plusieurs interfaces réseau, on pourra répéter les options –disk ou –network
En cas d’installation avec qcow2 préféré le modèle de CPU de la machine à la place de
host-passthrough
car sinon il peut y avoir des souci pour faire un rollback d’un snapshot ;
--cpu mode=SandyBridge --vcpus=1 \
Ce qui donne pour l’installation complète sur kvmdev par exemple :
# virt-install --connect=qemu:///system \
--name=template \
--cpu mode=SandyBridge --vcpus=1 \
--ram=512 \
--disk path=/path/template.qcow2,bus=virtio,cache=none,size=42,format=qcow2 \
--network=bridge:br0,model=virtio \
--noautoconsole --graphics vnc,listen=127.0.0.1,keymap=fr \
--cdrom=/home/images/debian-8.6.0-amd64-netinst.iso
On peut ensuite se connecter en VNC via l’hyperviseur et réaliser l’installation (paquet xtightvncviewer à installer) :
$ vncviewer -via kvm.example.com 127.0.0.1::<port VNC>
Note : on peut connaître le port VNC d’une VM avec la
commande
virsh qemu-monitor-command <vm-name> --hmp "info vnc"
virt-manager
Nous déconseillons l’installation via virt-manager
!!
Certes, l’installation est plus conviviale (car graphique) mais :
- les options disponibles à la création sont très limitées (aucun choix pour CPU,
- les options disponibles sont limitées (impossible de sélectionner un volume DRBD par exemple)
- les choix réalisés par défaut sont incorrects (ajout de périphériques Tablette, Video QXL, USB etc.)
Si vous utilisez tout de même virt-manager
, il faudra
donc revenir sur les options une fois la VM créée :
- Choix processor : Configuration > ne PAS cocher Copier la configuration CPU de l’hôte et mettre manuellement Modèle : host-passthrough
- NIC : choisir Device model : virtio
- VirtIO Disk : sélectionner Mode cache : none (ou writeback)
- IDE CDROM 1 : bien vérifier que le CDROM est déconnecté une fois l’installation terminée
- Supprimer les périphériques inutiles (Tablette, Video QXL etc.)
virsh define
http://libvirt.org/formatdomain.html
Vous pouvez écrire votre propre fichier de définition XML puis l’injecter :
# virsh define template.xml
# virsh start template
Stockage
Les stockages disponibles doivent être visibles par libvirt :
# virsh pool-list --all
# virsh vol-list <pool-name>
# virsh vol-delete --pool <pool-name> <vol-name>
# virsh help pool
Storage Pool (help keyword 'pool'):
find-storage-pool-sources-as find potential storage pool sources
find-storage-pool-sources discover potential storage pool sources
pool-autostart autostart a pool
pool-build build a pool
pool-create-as create a pool from a set of args
pool-create create a pool from an XML file
pool-define-as define a pool from a set of args
pool-define define (but don't start) a pool from an XML file
pool-delete delete a pool
pool-destroy destroy (stop) a pool
pool-dumpxml pool information in XML
pool-edit edit XML configuration for a storage pool
pool-info storage pool information
pool-list list pools
pool-name convert a pool UUID to pool name
pool-refresh refresh a pool
pool-start start a (previously defined) inactive pool
pool-undefine undefine an inactive pool
pool-uuid convert a pool name to pool UUID
# virsh help volume
Storage Volume (help keyword 'volume'):
vol-clone clone a volume.
vol-create-as create a volume from a set of args
vol-create create a vol from an XML file
vol-create-from create a vol, using another volume as input
vol-delete delete a vol
vol-download download volume contents to a file
vol-dumpxml vol information in XML
vol-info storage vol information
vol-key returns the volume key for a given volume name or path
vol-list list vols
vol-name returns the volume name for a given volume key or path
vol-path returns the volume path for a given volume name or key
vol-pool returns the storage pool for a given volume key or path
vol-resize resize a vol
vol-upload upload file contents to a volume
vol-wipe wipe a vol
Volumes DRBD/LVM
Format QCOW2
Ce format est spécifique à QEMU. C’est un format à taille variable (indépendamment du système de fichiers), et il dispose de fonctionnalités avancées permettant notamment de gérer des snapshots à chaud.
Création d’une image QCOW2 :
# qemu-img create -f qcow2 test0.qcow2 5G
Informations sur une image QCOW2 :
# qemu-img info debian1.qcow2
image: debian1.qcow2
file format: qcow2
virtual size: 12G (12884901888 bytes)
disk size: 908M
cluster_size: 65536
Agrandir une image (aucune partition ne sera agrandie) :
# qemu-img resize test.qcow2 +10G
Agrandir une image et une partition. De 10G, on passe à 20G la
partition /dev/sda1
:
# apt install libguestfs-tools
# virt-filesystems --long -h --all -a old.qcow2
Name Type VFS Label MBR Size Parent
/dev/sda1 filesystem ext4 - - 9.5G -
/dev/sda2 filesystem swap - - 511M -
/dev/sda1 partition - - 83 9.5G /dev/sda
/dev/sda2 partition - - 82 511M /dev/sda
/dev/sda device - - - 10G -
# qemu-img create -f qcow2 -o preallocation=metadata new.qcow2 20G
# virt-resize --expand /dev/sda1 old.qcow2 new.qcow2
# virt-filesystems --long -h --all -a new.qcow2
Name Type VFS Label MBR Size Parent
/dev/sda1 filesystem ext4 - - 19G -
/dev/sda2 filesystem swap - - 511M -
/dev/sda1 partition - - 83 19G /dev/sda
/dev/sda2 partition - - 82 511M /dev/sda
/dev/sda device - - - 20G -
L’ancienne image est gardée (et pourra être supprimée une fois la nouvelle validée), et une nouvelle est créée avec la nouvelle taille.
Convertir une image qcow2 en raw :
# qemu-img convert -f qcow2 -O raw test0.qcow2 test0.img
Il est aussi possible de convertir un volume LVM par exemple vers du qcow2. Note : Dans la définition d’une VM il ne faut pas oublié de changer le type pour spécifier que c’est un fichier de type qcow2
# qemu-img convert -O qcow2 /dev/LV_GROUP/LV_NAME /home/images/ma-super-vm.qcow
Monter une image QCOW2 via qemu-nbd
qemu-nbd
permet de créer un point de montage NBD
(Network Block Device) :
# modprobe nbd max_part=16;
# qemu-nbd -c /dev/nbd0 test0.qcow2;
# partprobe /dev/nbd0;
/dev/nbd0
est ensuite utilisable pour fdisk :
# fdisk /dev/nbd0
Command (m for help): p
Vous pouvez ensuite (un)mounter vos partitions situées dans votre
image QCOW2. Note : si vous avez du LVM, vous devez activer les VG via
vgscan && vgchange -ay
Cela peut ensuite être stoppé via :
# qemu-nbd -d /dev/nbd0
# rmmod nbd
Format RAW
L’avantage de ce format est sa simplicité ! C’est tout simplement une suite d’octets.. Cela permet de monter les partitions facilement (merci kpartx). Sous Linux, grâce au principe du sparse file (fichier à trou), c’est également un format à taille variable.
Création de l’image :
# qemu-img create -f raw test0.img 5G
Mountage de l’image (attention à ne jamais la monter en cours de fonctionnement) :
# modprobe dm-mod # Si kpartx renvoi un /proc/misc: No entry for device-mapper found
# kpartx -v -a test0.img
loop1p1 : 0 9912042 /dev/loop1 63
loop1p2 : 0 562275 /dev/loop1 9912105
loop1p5 : 0 562212 loop1p1 63
# fdisk -l /dev/loop1
# mount /dev/mapper/loop1p1 /mnt/test0
# umount /mnt/test0
# kpartx -d test0.img
Convertir ume image raw en qcow2 :
# qemu-img convert -f raw -O qcow2 test0.img test0.qcow2
On peut préciser des options pour la création de l’image, par exemple :
# qemu-img convert -f raw -O qcow2 -o cluster_size=2M test0.img test0.qcow2
Editer un fichier à l’intérieur d’une image (une fois la VM éteinte) :
# virt-edit -d domain /path/to/file
Agrandir une image
- Vérifier qu’aucun processus n’accède à l’image (la VM doit notamment être éteinte !)
- Agrandir le fichier image avec la taille désirée :
# qemu-img resize host.img +50G
Image resized.
ou on peut utiliser dd
, exemple pour une taille finale
de 80G :
# dd if=/dev/zero of=host.img seek=80G count=0 bs=1
0+0 records in
0+0 records out
0 bytes (0 B) copied, 1.302e-05 s, 0.0 kB/s
- Monter l’image et vérifier qu’elle a la bonne taille :
# kpartx -v -a host.img
add map loop0p1 (254:4): 0 314572737 linear /dev/loop0 63
# fdisk -l /dev/loop0
Disk /dev/loop0: 161.1 GB, 161061273600 bytes
[…]
- Supprimer puis recréer la partition avec la bonne taille à l’intérieur de l’image, après avoir sauvegardé la table des partitions :
# sfdisk -d /dev/loop0 >~/loop0.parts
# parted /dev/loop0
[…]
Voir http://trac.evolix.net/infogerance/wiki/HowtoParted
- Démonter et remonter l’image (
partprobe
ne suffit visiblement pas pour détecter la nouvelle taille de la partition) :
# kpartx -d host.img
loop deleted : /dev/loop0
# kpartx -v -a host.img
add map loop0p1 (254:4): 0 314572737 linear /dev/loop0 63
- Lancer un
fsck
puis unresize2fs
pour redimensionner le système de fichiers :
# e2fsck -f /dev/mapper/loop0p1
e2fsck 1.42.5 (29-Jul-2012)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/loop0p1: 46712/6111232 files (8.3% non-contiguous), 20257932/24414775 blocks
# resize2fs /dev/mapper/loop0p1
resize2fs 1.42.5 (29-Jul-2012)
Resizing the filesystem on /dev/mapper/loop0p1 to 39321592 (4k) blocks.
The filesystem on /dev/mapper/loop0p1 is now 39321592 blocks long.
- Vérifier que le système de fichiers voit la bonne taille en montant la partition :
# mount /dev/mapper/loop0p1 /mnt
# df -h /mnt
/dev/mapper/loop0p1 148G 76G 72G 52% /mnt
# umount /mnt
- Puis démonter l’image :
# kpartx -d host.img
loop deleted : /dev/loop0
Réseau
Les interfaces réseau en place doivent être visibles par libvirt :
# virsh iface-list --all
# virsh net-list --all
# virsh help interface
Interface (help keyword 'interface'):
iface-begin create a snapshot of current interfaces settings, which can be later committed (iface-commit) or restored (iface-rollback)
iface-bridge create a bridge device and attach an existing network device to it
iface-commit commit changes made since iface-begin and free restore point
iface-define define (but don't start) a physical host interface from an XML file
iface-destroy destroy a physical host interface (disable it / "if-down")
iface-dumpxml interface information in XML
iface-edit edit XML configuration for a physical host interface
iface-list list physical host interfaces
iface-mac convert an interface name to interface MAC address
iface-name convert an interface MAC address to interface name
iface-rollback rollback to previous saved configuration created via iface-begin
iface-start start a physical host interface (enable it / "if-up")
iface-unbridge undefine a bridge device after detaching its slave device
iface-undefine undefine a physical host interface (remove it from configuration)
# virsh help network
Networking (help keyword 'network'):
net-autostart autostart a network
net-create create a network from an XML file
net-define define (but don't start) a network from an XML file
net-destroy destroy (stop) a network
net-dhcp-leases print lease info for a given network
net-dumpxml network information in XML
net-edit edit XML configuration for a network
net-event Network Events
net-info network information
net-list list networks
net-name convert a network UUID to network name
net-start start a (previously defined) inactive network
net-undefine undefine a persistent network
net-update update parts of an existing network's configuration
net-uuid convert a network name to network UUID
Adresse MAC
On peut générer l’adresse MAC d’une VM KVM avec la commande suivante :
$ echo $(echo -n 52:54:00 ; for i in `seq 1 3`; do echo -n `echo ":$RANDOM$RANDOM" | cut -n -c -3`; done)
Mode bridge
Attention : Cette procédure est seulement pour Stretch.
On va créer le bridge à chaud et basculer l’interface principale dedans (eth0, eno1, …). Pour éviter de perdre bêtement la main, on va sauvegarder la configuration actuelle.
# apt install bridge-utils
# cp /etc/network/interfaces /var/backups/
# vim /etc/network/interfaces
auto eth0
iface eth0 inet manual
auto br0
iface br0 inet static
bridge_ports eth0
up echo 0 > /sys/class/net/br0/bridge/multicast_snooping
address <address>/<netmask>
gateway <gateway>
# screen -S network -dm bash -c "sleep 300; cp /var/backups/interfaces /etc/network/; systemctl stop networking; systemctl start networking"
# screen -S reboot -dm bash -c "sleep 600; reboot"
# systemctl restart networking; ip a d <address>/<netmask> dev eth0; ip a a <address>/<netmask> dev br0; ip r d default via <gateway> dev eth0; ip r a default via <gateway> dev br0
Si tout se passe bien, tuez les screen. Sinon attendez 5 min, si vous récupérez la main, tuer le screen de reboot. Sinon attendre 10 min que le serveur redémarre avec l’ancienne configuration réseau.
Mode bridge + VLAN
Vous pouvez faire passer plusieurs VLANs dans votre bridge, afin de permettre l’accès depuis vos VMs à différents VLANs.
Sur l’hyperviseur on aura ainsi une configuration réseau du type (paquet vlan à installer) :
auto br0
iface eth0 inet manual
iface br0 inet manual
bridge_ports eth0
up echo 0 > /sys/class/net/br0/bridge/multicast_snooping
auto br0.42
iface br0.42 inet static
address <address>/netmask>
gateway <gateway>
Dans les VMs, on aura ainsi une configuration réseau « VLANisée », voir http://trac.evolix.net/infogerance/wiki/HowtoDebian/Reseau#VLAN
Mode bridge avec openvswitch
Notamment utile pour utiliser avec le réseau RPN Online de l’hébergeur français ONLINE/Dedibox.
/etc/network/interfaces
:
# LAN bridge over RPN
# https://documentation.online.net/fr/dedicated-server/tutorials/network/rpn-proxmox-openvswitch
auto br1
iface br1 inet manual
ovs_type OVSBridge
post-up ovs-vsctl add-port br1 gre0 -- set interface gre0 type=gre options:remote_ip='10.XX.XX.XX'
post-up ip link set ovs-system up
post-up ip link set br1 up
Créer un fichier XML définissant le réseau :
<network>
<name>br1</name>
<forward mode='bridge'/>
<bridge name='br1'/>
<virtualport type='openvswitch'/>
</network>
# virsh net-define br1.xml
# virsh net-start br1
# virsh net-autostart br1
Mode réseau NAT (avec libvirt)
Le mode NAT peut être intéressant si l’on ne peut pas avoir d’IP dans le réseau de l’hyperviseur.
Avec libvirt, il suffit d’installer :
# apt install dnsmasq ebtables
Et l’on peut configurer avec un réseau NAT avec
virt-manager
ou virsh net-create
et un fichier
XML du type :
<network connections='1'>
<name>nat0</name>
<uuid>f94578a3-3b7f-4c60-a441-d1f86920fb59</uuid>
<forward dev='eth0' mode='nat'>
<nat>
<port start='1024' end='65535'/>
</nat>
<interface dev='eth0'/>
</forward>
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:de:ad:41'/>
<domain name='nat0'/>
<ip address='192.0.2.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.0.2.128' end='192.0.2.254'/>
</dhcp>
</ip>
</network>
Mode réseau NAT (sans libvirt)
Note : une raison d’utiliser le NAT est qu’une interface Wi-Fi n’est pas toujours utilisable dans un bridge :
# brctl addif br0 wlan0
can't add wlan0 to bridge br0: Operation not supported
On va donc prendre l’exemple où vous avez une interface Wi-Fi wlan0 :
# echo 1 > /proc/sys/net/ipv4/ip_forward
# iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
Vous pouvez ainsi lancer votre KVM ainsi (on lance un CD-ROM d’OpenBSD dans notre cas) :
# kvm -hda routeur0.qcow2 -cdrom cd48.iso -boot d -m 384 -k fr -net nic,macaddr=52:54:00:de:ad:42,model=e1000 -net tap,vlan=0,ifname=tap0
Une fois démarré, attribuez l’IP 192.0.2.1/24 à l’interface tap0 sur votre portable. Dans vos machines virtuelles, prenez une adresse IP dans la plage 192.0.2.0/24 et indiquez 192.0.2.1 comme route par défaut.
Normalement, c’est tout !
Si vous lancez plusieurs machines virtuelles, vous penserez à modifier l’adresse MAC et à utiliser des tapN différents. Si vous voulez les faire communiquer entre elles, vous devrez simplement créer un bridge entre les interfaces tap :
# brctl addbr br0
# brctl addif br0 tap0
# brctl addif br0 tap1
# brctl addif br0 tap2
etc.
QoS / Limitation de bande passante
Libvirt permet aussi de faire de la QoS sur l’interface réseau. On va
utiliser un bloc bandwidth
qui va permettre de contrôler le
débit.
<interface type='bridge'>
<mac address='00:00:00:00:00:00'/>
<source bridge='br0'/>
<bandwidth>
<inbound average='1000' peak='5000' burst='1024'/>
<outbound average='128' peak='256' burst='256'/>
</bandwidth>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
On peut jouer sur plusieurs paramètres :
- average : La vitesse moyenne désirée pour le traffic (en Ko/s)
- peak (optionnel) : La vitesse maximale souhaitée (en Ko/s) lors d’un dépassement
- burst (optionnel) : La quantité de données (en Ko) qui peut être transmise en pic en une seule fois
La documentation complète se trouve sur https://libvirt.org/formatdomain.html#elementQoS
Snapshots
L’utilisation du format de stockage QCOW2 permet d’avoir des
snapshots à chaud !
On peut créer plusieurs snapshots de l’état disque/mémoire, et restaurer
en quelques secondes.
Avec libvirt, création/restauration/suppression de snapshots
se gèrent de façon conviviale avec virt-manager
ou on peut
aussi utiliser virsh
:
# virsh snapshot-create-as template-evolinux snapshot1
# virsh snapshot-list template
Name Creation Time State
------------------------------------------------------------
snapshot1 2016-12-27 01:46:58 +0000 running
# virsh snapshot-info --snapshotname snapshot1 template
Name: snapshot1
Domain: template
Current: yes
State: running
Location: internal
Parent: -
Children: 0
Descendants: 0
Metadata: yes
# virsh help snapshot
Snapshot (help keyword 'snapshot'):
snapshot-create Create a snapshot from XML
snapshot-create-as Create a snapshot from a set of args
snapshot-current Get or set the current snapshot
snapshot-delete Delete a domain snapshot
snapshot-dumpxml Dump XML for a domain snapshot
snapshot-edit edit XML for a snapshot
snapshot-info snapshot information
snapshot-list List snapshots for a domain
snapshot-parent Get the name of the parent of a snapshot
snapshot-revert Revert a domain to a snapshot
On peut aussi gérer les snapshots via le Mode
Monitor et les commandes savevm
, loadvm
,
info snapshots
.
Note : les snapshots créés avec savevm
ne
seront pas visible via libvirt.
Options -loadvm / -snapshot (non gérées avec libvirt)
On peut démarrer directement sur un snapshot s0 avec
l’option -loadvm
:
$ kvm -hda debian1.qcow2 -m 512 -net nic,macaddr=<mac_address> -net tap,script=/etc/qemu-ifup \
-curses -monitor tcp:127.0.0.1:<port monitor>,server,nowait -loadvm s0
On peut démarrer une VM avec le mode -snapshot
où rien
n’est réellement écrit sur le disque :
$ kvm -hda debian1.qcow2 -m 512 -net nic,macaddr=<mac_address> -net tap,script=/etc/qemu-ifup \
-curses -monitor tcp:127.0.0.1:<port monitor>,server,nowait -snapshot
Au prochain redémarrage, le système revient à son état précédent. Si nécessaire on peut tout de même forcer l’écriture en passant l’option commit all en mode monitor :
(qemu) commit all
Images dérivées d’une image QCOW2
http://wiki.qemu.org/Documentation/CreateSnapshot
Une option intéressante avec le format QCOW2 est la possibilité de créer une image d’une installation de base et de créer des dérivées à partir de cette image. Non seulement cela permet de repartir d’une installation déjà faite, mais cela permet aussi une optimisation de la place (l’image dérivée est en Copy-on-Write de celle de base) voire même de la mémoire selon les rumeurs :-)
Création d’une image dérivée :
# qemu-img create -f qcow2 -b install-debian-base.qcow2base serveur01.qcow2snap
Formatting 'serveur01.qcow2snap', fmt=qcow2 size=12884901888 backing_file='install-debian-base.qcow2base' encryption=off cluster_size=0
# qemu-img info serveur01.qcow2snap
image: serveur01.qcow2snap
file format: qcow2
virtual size: 12G (12884901888 bytes)
disk size: 140K
cluster_size: 65536
backing file: install-debian-base.qcow2base (actual path: install-debian-base..qcow2base)
/!\ Attention, ne jamais modifier une image de base si elle a des images dérivées sous peine de tout perdre !
Mode monitor
http://en.wikibooks.org/wiki/QEMU/Monitor
https://doc.opensuse.org/documentation/leap/virtualization/html/book.virt/cha.qemu.monitor.html
Le mode monitor est une option de kvm et permet d’effectuer diverses actions (état de la VM, action sur la VM, snapshots, etc.).
libvirt crée automatiquement un mode monitor qu’il utilise (donc non accessible directement), mais on peut aussi l’utiliser via :
# virsh qemu-monitor-command <vm-name> --hmp "info block"
Si on utilise kvm sans libvirt, on peut créer un
mode monitor accessible via telnet
:
$ kvm […] -monitor tcp:127.0.0.1:<port monitor>,server,nowait
$ telnet 127.0.0.1 <port monitor>
Trying 127.0.0.1…
Connected to 127.0.0.1.
Escape character is '^]'.
QEMU 0.9.1 monitor - type 'help' for more information
(qemu)
$ echo system_powerdown | nc 127.0.0.1 <port monitor>
Infos sur une VM
(qemu) info block
(qemu) info blockstats
(qemu) info network
(qemu) info uuid
Actions sur une VM
Extinction ACPI d’une VM :
(qemu) system_powerdown
Pause/Resume d’une VM :
(qemu) stop
(qemu) cont
Envoyer une combinaison clavier :
(qemu) sendkey ctrl-alt-f1
Mot de passe VNC :
(qemu) change vnc password
Ajout de disques/périphériques à chaud :
(qemu) drive_add ?
(qemu) device_add ?
Actions sur les snapshots
Ceci n’est disponible que pour les VMs utilisant un stockage QCOW2.
Créer et lister les snapshots :
(qemu) savevm s0
savevm s0
(qemu) info snapshots
info snapshots
Snapshot devices: ide0-hd0
Snapshot list (from ide0-hd0):
ID TAG VM SIZE DATE VM CLOCK
1 s0 20M 2010-11-14 20:07:09 00:16:01.182
(qemu)
Restauration à chaud :
(qemu) loadvm s0
Pour réaliser des snapshots automatiques sans arrêt de la machine, on pourra avoir un script du type :
#!/bin/sh
echo "savevm snap.current" | telnet 127.0.0.1 <port>
sync
cp debian1.qcow2 debian.current.qcow2
/!\ Attention, avec libvirt si l’on passe directement par le mode monitor les snapshots ne seront pas visibles par libvirt qui gère un état XML des snapshots. On pourra néanmoins faire :
# virsh qemu-monitor-command <vm-name> --hmp "savevm snap.current"
# virsh qemu-monitor-command <vm-name> --hmp "info snapshots"
virsh
http://libvirt.org/sources/virshcmdref/html-single/
La commande virsh permet de faire de nombreuses manipulations en ligne de commande :
## Lister les VMs actives
# virsh list
## Lister les VMs actives/inactives
# virsh list --all
## Démarrer/Stopper proprement une VM
# virsh start <vm-name>
# virsh shutdown <vm-name>
## Forcer l'extinction d'une VM (elle n'est pas détruite !)
# virsh destroy <vm-name>
## Informations avancées sur une VM
# virsh dominfo <vm-name>
## Activer/désactiver le démarrage automatique d'une VM
# virsh autostart <vm-name>
# virsh autostart --disable <vm-name>
## Dumper la configuration d'une VM dans un fichier de définition XML
# virsh dumpxml <vm-name> > <vm-name>.xml
## Créer/détruire une définition de VM
# virsh define <vm-name>.xml
# virsh undefine <vm-name>
## Mettre sur pause/réactiver une VM
# virsh suspend <vm-name>
# virsh resume <vm-name>
## Modifier les options d'une VM
# virsh edit <vm-name>
/!\ Attention, il faut toujours utiliser virsh edit
et
ne jamais éditer le fichier dans /etc/libvirt/qemu/
qui est
régulièrement écrasé !
La commande virsh peut également être utilisée à distance :
# VIRSH_DEFAULT_CONNECT_URI='qemu+ssh://root@kvm.example.com/system' virsh list --all
Note : par défaut VIRSH_DEFAULT_CONNECT_URI=‘qemu:///system’
Cloner une VM
Via clic-droit sur virt-manager ou en CLI :
# virt-clone --original <mytemplate-domainame> --name <newmachine> --file <newmachine>.img
Cela permet de dupliquer un domaine existant avec notamment changement de l’adresse MAC de la carte réseau.
Une fois la machine démarrée, il faudra modifier son hostname, son adresse IP et ses clés SSH.
# rm /etc/udev/rules.d/70-persistent-net.rules
# hostname foo ; echo foo > /etc/hostname
# rm /etc/ssh/ssh_host_* ; dpkg-reconfigure openssh-server
# vim /etc/network/interfaces
On peut utiliser l’option --preserve-data
pour copier
les données vers une image vierge existante (par exemple de taille
différente) :
# virt-clone --original <mytemplate-domainame> --name <newmachine> --file <newmachine>.img --preserve-data
Migrer une VM
https://libvirt.org/migration.html
Note : Il faut s’assurer d’ouvrir les ports TCP 49152 à 49215 entre les machines car par défaut libvirtd utilise ces ports pour faire des netcat des données !
Pour une migration à chaud, il faut avoir un CPU identique (à voir selon l’option un storage commun pour les disques (SAN, réplication DRBD, etc.).
Pour envoyer une VM locale test vers l’hyperviseur foo :
# VIRSH_DEFAULT_CONNECT_URI='qemu:///system' virsh migrate --live --unsafe --verbose test qemu+ssh://foo/system
Migration: [100 %]
Pour rappatrier une VM test depuis l’hyperviseur foo :
# VIRSH_DEFAULT_CONNECT_URI='qemu+ssh://foo/system' virsh migrate --live --unsafe --verbose test qemu:///system
Migration: [100 %]
Note : on peut faire cela via virt-manager mais le mode
--unsafe
(utile si un cache disque est configuré) n’est pas supporté…
Si l’on a plusieurs interfaces réseau sur l’hyperviseur (par exemple un réseau dédié entre les hyperviseurs), il faut l’indiquer à libvirt sinon il tente de passer par l’interface principale :
# virsh migrate --live --unsafe --verbose test qemu+ssh://192.0.2.2/system tcp://192.0.2.2/
Migration: [100 %]
Attention la migration d’une VM ne déplace pas sa définition ! Il est donc impératif de faire un
virsh define
de son fichier de définition sur l’hyperviseur de destination de la migration sous peine de n’avoir plus aucune trace de la VM une fois éteinte ! On conseille aussi de nettoyervirsh undefine
sur l’hyperviseur de départ pour éviter les confusions.
Astuce : si le lien entre les deux hyperviseurs n’est pas rapide et que la mémoire de ma VM est très sollicitée, la migration peut ne jamais se finir et boucler entre 80 et 99%… si c’est le cas, mettez sur “pause” la VM et cela devrait permettre de terminer la migration sans avoir à éteindre la VM (évidemment pendant qu’elle est sur “pause” la VM sera inaccessible).
internal error: Attempt to migrate guest to the same host
Sur des machines très proches matériellement, il est possible d’avoir un souci du fait d’un system-uuid identique sur les deux hyperviseurs :
error: internal error: Attempt to migrate guest to the same host 12341234-1234-1234-1234-1234123412341234
Il faut éditer /etc/libvirt/libvirtd.conf
(cf # UUID of
the host) et ajouter un autre uuid puis redémarrer le service
libvirtd pour prise en compte.
Renommer une VM
Si un mauvais choix a été fait au départ et qu’il faut renommer toute la VM (y compris la partie LVM et DRBD), la procédure est facile et rapide mais elle doit se faire à froid (VM éteinte). La plupart des opération doit se faire sur les 2 nœuds DRBD (ici tic et tac, et la VM est active seulement sur tic).
- Une fois la VM éteinte il faut couper la synchro DRBD :
tic $ drbdadm down <old resource>
tac $ drbdadm down <old resource>
- Il faut ensuite faire le renommage de la partie LVM, pour chaque volume de la VM
tic $ lvrename <VG name> <old LV name> <new LV name>
tac $ lvrename <VG name> <old LV name> <new LV name>
- On renomme le fichier de définition de la ressource :
tic $ mv /etc/drbd.d/<old resource>.res /etc/drbd.d/<new resource>.res
tac $ mv /etc/drbd.d/<old resource>.res /etc/drbd.d/<new resource>.res
- On renomme la ressource elle-même sur la première ligne de la définition et on adapte les chemins LVM.
tic $ vim /etc/drbd.d/<new resource>.res
tac $ vim /etc/drbd.d/<new resource>.res
- On peut alors reconnecter les nœuds DRBD :
tic $ drbdadm up <new resource>
tac $ drbdadm up <new resource>
- Sur le nœud DRBD principal, on remet la ressource en primaire :
tic $ drbdadm primary <new resource>
- On renomme la VM elle même :
tic $ virsh domrename <old DOM name> <new DOM name>
Pour Debian 7 et inférieur, la commande virsh domrename
n’existe pas. On peut alors contourner de cette manière :
# cd /etc/libvirt/qemu/
# cp <old DOM name>.xml <new DOM name>.xml
# virsh undefine <old DOM name>
# vim <new DOM name>.xml
# : faire les modifications de l'étape 8 ainsi que le changement de nom dans la balise <name>
# virsh define <new DOM name>.xml
- On ajuste les chemins des volumes dans la définition de la VM
tic $ virsh edit <new DOM name>
- On peut enfin démarrer la VM
tic $ virsh start <new DOM name>
Systemd
libvirt fait appel à systemd (machinectl/systemd-run) pour lancer les processus des VM et les suivre.
Pour avoir le statut :
# machinectl
MACHINE CONTAINER SERVICE
qemu-mavm vm libvirt-qemu
1 machines listed.
# machinectl status qemu-mavm
qemu-mavm(db0b0ff5e71e4ed9813b226f6843729a)
Since: Mon 2016-02-22 18:17:49 CET; 8 months 25 days ago
Leader: 33012 (qemu-system-x86)
Service: libvirt-qemu; class vm
Address: 192.0.2.1
OS: Debian GNU/Linux 8 (jessie)
Unit: machine-qemu\x2dmavm.scope
??33012 qemu-system-x86_64 -enable-kvm -name mavm -S -machine pc-i440fx-2.1,accel=kvm,usb=off -cpu SandyBridge…
En cas de plantage du processus qemu-system, il sera peut
être nécessaire de faire un systemctl reset-failed
avant de
redémarrer la VM :
# systemctl reset-failed machine-qemu\\x2dmavm.scope
Modifier les ressources d’une VM
Nombre de vCPU
Il faut éditer le fichier de définition de la VM et modifier la
valeur de la partie <vcpu>
:
# virsh edit <vm-name>
Il faut ensuite stopper la VM (bien attendre qu’elle soit réellement stoppée :
# virsh shutdown <vm-name> && watch "virsh list --all"
Ensuite la redémarrer
# virsh start <vm-name>
RAM
L’opération est presque identique à celle pour les vCPU. Il faut
changer 2 valeurs dans la définition de la VM :
<memory>
et <currentMemory>
.
Ajout un disque
Créer un fichier XML qui définit le nouveau disque. Exemple :
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='writeback' io='threads'/>
<source dev='/dev/hdd0/mondisque'/>
<target dev='vdc' bus='virtio'/>
</disk>
Puis l’ajouter à la machine, et à sa définition.
# virsh attach-device <nomMachine> add-disk.xml --persistent
De la même manière, on peut détacher un disque avec
virsh detach-device
.
Interfaces réseau
L’ajout d’une interface réseau à chaud ne fonctionne pas sur les VMs avec des systèmes plus anciens, où l’interface ne sera pas reconnue et un reboot sera nécessaire. Pour les systèmes plus récents, l’interface sera directement visible et utilisable :
# virsh attach-interface <nomMachine> bridge <nomBridge> --live --config --mac 52:54:00:XX:YY:ZZ --model virtio
L’option --live
indique d’appliquer la configuration à
chaud.
L’option --config
indique d’enregistrer la configuration de
manière persistente.
L’option --mac
est facultative, et une adresse MAC sera
automatiquement définie si elle n’est pas indiquée.
On peut également supprimer une interface à chaud :
# virsh detach-interface <nomMachine> bridge --live --config --mac 52:54:00:XX:YY:ZZ
Ici, l’option --mac
est obligatoire puisqu’elle permet
d’identifier l’interface à supprimer.
Monitoring
Munin
Il existe des plugins Munin pour grapher les ressources CPU/IO/Mémoire de chaque VM :
$ wget https://raw.githubusercontent.com/munin-monitoring/contrib/master/plugins/virtualization/kvm_cpu
$ wget https://raw.githubusercontent.com/munin-monitoring/contrib/master/plugins/virtualization/kvm_io
$ wget https://raw.githubusercontent.com/munin-monitoring/contrib/master/plugins/virtualization/kvm_mem
$ sed -i 's/pidof kvm/pidof qemu-system-x86_64/' kvm_*
Le plugin kvm_io nécessite de tourner en root,
/etc/munin/plugin-conf.d/munin-node
:
[kvm_io]
user root
Déduplication de pages mémoire avec KSM
KSM est l’acronyme de Kernel Samepage Merging, le noyau Linux analyse la mémoire consommée et fusionne les données identiques qui sont stockées en mémoire.
Lorsque vous avez plusieurs instances du même logiciel, il est très courant que la mémoire soit utilisée pour stocker plussieurs fois la même chose, KSM permet déviter celà.
Ce système ne fonctionne pas avec tout les logiciels, car ils doivent être prévu pour cela, mais c’est le cas de KVM : https://www.linux-kvm.org/page/KSM
Activation de KSM sur Debian
On vérifie que KSM n’est pas activé sur la machine avec la commande :
# cat /sys/kernel/mm/ksm/run
0
S’il retourne 1 c’est que KSM est déjà activé sur la machine.
On installe le paquet ksmtuned
# apt install ksmtuned --no-install-recommends
Le service qui nous instéresse est ksm.service
on peux
arrêter et désactivé le service ksmtuned :
# systemctl stop ksmtuned.service
# systemctl disable ksmtuned.service
Puis on redémarre ksm.service
:
# systemctl restart ksm.service
On vérifie que KSM est bien activé :
# cat /sys/kernel/mm/ksm/run
1
On peux regarder les statistiques d’utilisation de KMS comme ceci :
# grep -H '' /sys/kernel/mm/ksm/pages_*
/sys/kernel/mm/ksm/pages_shared:204
/sys/kernel/mm/ksm/pages_sharing:54476
/sys/kernel/mm/ksm/pages_to_scan:100
/sys/kernel/mm/ksm/pages_unshared:44874
/sys/kernel/mm/ksm/pages_volatile:95
On peux avoir les explications sur chaques variables de ces statistiques ici : https://blog.siphos.be/2013/05/enabling-kernel-samepage-merging-ksm/
FAQ
http://www.linux-kvm.org/page/FAQ
Erreur avec certaines commandes virsh
Solution : tester de positionner la variable VIRSH_DEFAULT_CONNECT_URI
Dans certains cas, elle se positionne par défaut à vbox:///system On peut donc la forcer :
VIRSH_DEFAULT_CONNECT_URI='qemu:///system' virsh list
En Debian 8, je ne trouve pas kvm-img
C’est désormais qemu-img inclu dans le paquet qemu-utils. a priori en Debian 6, c’était qemu-img (inclus par défaut) et en Debian 7 c’était kvm-img (inclus par défaut).
Soucis réseau avec machine clonée
Lorsqu’une machine est clonée avec virt-manager ou virsh, une nouvelle adresse MAC est générée (pour éviter les conflits). Cependant, comme il s’agit d’un clone, l’adresse MAC connue de Udev est toujours présente (dans /etc/udev/rules.d/z25_persistent-net.rules) et l’interface apparait donc comme eth1.
Deux solutions, utiliser eth1 au lieu de eth0, ou corriger /etc/udev/rules.d/z25_persistent-net.rules en mettant à jour l’adresse MAC de eth0 et en supprimant eth1.
Installation d’une VM sans libvirt
# qemu-img create -f qcow2 debian1.qcow2 20G
# kvm -hda debian1.qcow2 -cdrom debian-amd64-netinst.iso -boot d -m 512 -net nic,macaddr=<mac_address> -net tap,script=/etc/qemu-ifup -vnc :1 -k fr
<installation via VNC 127.0.0.1:5901 puis boot final>
# /usr/bin/screen -S debian1 -d -m kvm -hda debian1.qcow2 -m 512 -net nic,macaddr=<mac_address> -net tap,script=/etc/qemu-ifup \
-curses -k fr -monitor tcp:127.0.0.1:<port>,server,nowait
Accéder à virt-manager sur un hyperviseur
Installer sur l’hyperviseur et se connecter en ssh -X
.
Options recommandées :
$ ssh -X -C -c arcfour root@kvm.example.com
Désactiver l’interface réseau d’une VM à chaud
Pour ne pas avoir besoin de redémarrer une VM pour retirer une
interface, on peut retirer son interface vnetX sur l’hyperviseur du
bridge associé. Le nom de cette interface se trouve avec la commande
virsh dumpxml
:
# virsh dumpxml <vm-name>
[…]
<interface type='bridge'>
<mac address='52:54:00:de:ad:43'/>
<source bridge='br2'/>
<target dev='vnet7'/>
<model type='virtio'/>
<alias name='net1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</interface>
# virsh detach-interface […]
Il suffit ensuite de la retirer du bridge :
# brctl delif br2 vnet7
Tips performance
http://www.linux-kvm.org/page/Tuning_KVM
Utiliser le même CPU que sur l’hyperviseur via l’option
kvm -cpu host
qui se positionne avecvirt-install --cpu mode=host-passthrough
(attention, la VM ne pourra être migrée que sur un hyperviseur avec un CPU identique)Utiliser autant que possible les drivers virtio (pour les disques et les interfaces réseau) sur les VMs
Dans le cas d’un hyperviseur avec une carte RAID hardware disposant d’un cache avec batterie, on peut positionner
cache=none
pour les disques… une autre stratégie est d’utilisercache=writeback
et d’avoir beaucoup de mémoire disponible sur son hyperviseur.Désactiver les barrières si Ext4 est utilisé.
Le scheduler deadline semble également donner les meilleures performances tant sur l’hôte que sur les invités.
On peut aussi présenter toutes les instructions du CPU hôte aux machines virtuelles :
<cpu mode='host-model'>
<model fallback='allow'/>
</cpu>
Étendre une image RAW
Pour le sport, voici différentes méthodes pour étendre une image RAW :
# qemu-img resize host.img +50G
# dd if=/dev/zero of=host.img seek=80G count=0 bs=1
# dd oflag=append conv=notrunc if=/dev/zero of=host.img bs=1MB count=20480
Étendre un volume disque à chaud
Note : Ne fonctionne qu’à partir de Jessie
Par exemple avec LVM :
# lvresize -L+100G /dev/vg0/example
# virsh blockresize domain path sizeB
Le blockresize indiquera à la VM de redimenssioner son disque à chaud.
- domain : Nom de la machine ;
- path : Chemin du disque dans la définition XML ;
- sizeB : Taille en octets,
lvs --units B
.
# virsh blockresize myvm /dev/vg0/myvm_rootfs 214748364800B
Erreur “Unable to create cgroup”
Si votre VM a crashé et n’est pas “redémarrable” avec un message “Unable to create cgroup for $VIRTIMAGE: No such file or directory”, notamment il reste des « traces » dans /run/systemd/system/machine-qemu2dfoo.scope vous pouvez faire un reset-failed :
# systemctl status machine-qemu\\x2dfoo.scope
# systemctl reset-failed machine-qemu\\x2dfoo.scope
Souci d’allocation CPU
Admettons que vous avez sur l’hyperviseur 32 CPU (cores ou threads,
qu’importe), vous affectez 32 vCPU à une VM. Vous constatez que la VM ne
peut monter qu’à 1600% d’utilisation, soit 16 vCPU, et vous constatez un
steal important (voir top
, htop
ou
Munin). Cela signifie en fait que la VM a démarré avec 32 vCPU, mais
ceux-ci sont mappés seulement sur 16 CPU physiques (le premier CPU avec
16 cores par exemple).
C’est un bug lié à libvirt, bug qui est bien connu et corrigé, cependant il impacte toujours le libvirt de Debian Jessie.
Pour corriger le souci à chaud, on peut faire les actions suivantes. Autoriser le CGroup de la machine à utiliser tous les CPU :
# cgset -r cpuset.cpus=0-31 /machine.slice/machine-qemu\\x2d<NOMVM>.scope
Mapper tous les vCPU sur les CPU physiques :
# for i in {0..31}; do virsh vcpupin <NOMVM> $i $i; done
Problème lors de l’installation
Il se peut que apt n’arrive pas à installer complètement kvm. Pour pouvoir finir l’installation :
# systemctl disable libvirtd
# dpkg --configure libvirt-daemon-system
# apt install -f
Cela ne résoud pas forcément le problème.
Le bloc nécessaire pour une iso
Parfois suite à la commande virt-install on n’a toujours pas de CD dans la définition de la VM. Un bloc fonctionnel ressemble à :
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/home/iso/install61.iso'/>
<target dev='hda' bus='ide'/>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
Il faudra possiblement rajouter
avant hd
dans le block
afin de bien booter sur le CD.
Disposition qwerty
Si on veut que le vnc mis en place utilise une disposition de clavier qwerty
Virtualisation imbriquée
Dans le cas où l’on veut créer des VMs dans une VM, il peut être nécessaire d’activer la virtualisation imbriquée.
Il faut pour cela éteindre toutes les VMs sur l’hyperviseur, et activer l’option nested avant de redémarrer les VMs :
# modprobe -r kvm_intel
# echo "options kvm-intel nested=1" > /etc/modprobe.d/kvm.conf
# modprobe kvm_intel
Machine reboot lors du boot sur fichier .iso pour installation d’un systeme (Debian ou autre).
Sur certains hyperviseurs et certains CPU, il est possible que le
mode CPU host-passthrough
provoque un reboot de la VM
lorsque l’on boot sur le cd d’install, et que l’on sélectionne le début
de l’installation.
Il faut donc, dans le fichier xml, mettre le modèle de CPU de l’hyperviseur correspondant, exemple avec un modèle Sandy Bridge :
Erreur de redémarrage d’une machine virtuelle
Le client virsh qui ne parvient plus à contacter le service libvirtd :
root@kvmXX:/etc# virsh start $VM
error: Failed to start domain $VM
error: error from service: ListActivatableNames: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
On peut relancer le service qui devrait pas provoquer d’effets de bords avec les autres VM qui tournent déjà :
systemctl restart libvirtd.service
Erreur de connection en tant qu’utilisateur
Même avec une configuration valide et utilisteur ayant les droits approriés, il est possible que libvirt ne veuille pas laisser les utilisateurs non root à se connecter à l’instance système de libvirt en produisant l’erreur suivante :
$ virsh --connect qemu:///system --debug 4
error: failed to connect to the hypervisor
error: error from service: CheckAuthorization: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
Erreur avec Virt-Manager :
Unable to connect to libvirt qemu+ssh://- user@server/system.
authentication unavailable: no polkit agent avaible eto authenticate action 'org.libvirt.unix.manage'
Vérifiez que le démon « libvirtd » est en cours d'exécution sur l'hôte distant.
- Vérifier que l’utilisateur est bien dans le groupe
libvirt
- Vérifier le statut du service « libvirtd » Dans ce cas il faut
redémarrer l’instance libvirt
systemctl restart libvirtd
, cela n’arretera pas les machines en cours d’exécution.
Erreur de migration de VM relative à AppArmor
Exemple d’erreur rencontrée :
error: unsupported configuration: Unable to find security driver for model apparmor
Il est probable que la migration tentée pousse la machine virtuelle vers un hôte où AppArmor n’est pas actif, ou n’a pas les profils relatifs à libvirt.
Pour vérifier, on utilise la commande aa-status
sur
l’hôte de destination.
Exemple :
# aa-status
apparmor module is loaded.
0 profiles are loaded.
0 profiles are in enforce mode.
0 profiles are in complain mode.
0 processes have profiles defined.
0 processes are in enforce mode.
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
Dans ce cas, AppArmor est bien présent, chargé et actif. Mais il n’a
pas de profils de configurés (ils sont définis dans
/etc/apparmor.d/
en temps normal). C’est la raison de
l’échec de la migration de la machine virtuelle. On peut forcer AppArmor
à recharcher tous les profils avec la commande
apparmor_parser /etc/apparmor.d/
Si ça marche, on obtient après le résultat suivant en rejouant
aa-status
(l’important est de voir les profils AppArmor
relatifs à libvirt dans la liste) :
# aa-status
apparmor module is loaded.
10 profiles are loaded.
10 profiles are in enforce mode.
/usr/bin/man
/usr/sbin/libvirtd
/usr/sbin/libvirtd//qemu_bridge_helper
/usr/sbin/ntpd
/usr/sbin/tcpdump
man_filter
man_groff
nvidia_modprobe
nvidia_modprobe//kmod
virt-aa-helper
0 profiles are in complain mode.
2 processes have profiles defined.
2 processes are in enforce mode.
/usr/sbin/libvirtd (2642)
/usr/sbin/ntpd (2654)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
Normalement, re-esayer la migration de la machine virtuelle marchera.
Note : Bien vérifier que apparmor.service soit enabled pour systemd. C’est le lancement de ce service au démarrage qui s’assure que tous les profils soient bien chargés. Un coup de
systemctl enable --now apparmor.service
Nested
# echo 'options kvm_intel nested=1' >> /etc/modprobe.d/qemu-system-x86.conf
# modprobe kvm_intel nested=1
# cat /sys/module/kvm_intel/parameters/nested
Y
https://www.server-world.info/en/note?os=Debian_11&p=kvm&f=8 https://docs.fedoraproject.org/en-US/quick-docs/using-nested-virtualization-in-kvm/