1409 lines
45 KiB
Markdown
1409 lines
45 KiB
Markdown
# Howto KVM
|
||
|
||
* Documentation KVM : <http://www.linux-kvm.org/page/Documents>
|
||
* Documentation libvirt : <https://libvirt.org/docs.html>
|
||
* virsh(1) : <https://manpages.debian.org/jessie/libvirt-clients/virsh.1.en.html>
|
||
|
||
[KVM](http://www.linux-kvm.org/) est une technologie de virtualisation intégrée au noyau Linux.
|
||
On l'utilise avec [libvirt](https://libvirt.org), 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 2.8.1(Debian 1:2.8+dfsg-6+deb9u4)
|
||
Copyright (c) 2003-2016 Fabrice Bellard and the QEMU Project developers
|
||
|
||
$ virsh -V
|
||
Virsh command line tool of libvirt 3.0.0
|
||
See web site at http://libvirt.org/
|
||
|
||
Compiled with support for:
|
||
Hypervisors: QEMU/KVM LXC UML Xen LibXL OpenVZ VMware VirtualBox Test
|
||
Networking: Remote Network Bridging Interface netcf Nwfilter VirtualPort
|
||
Storage: Dir Disk Filesystem SCSI Multipath iSCSI LVM RBD Sheepdog ZFS
|
||
Miscellaneous: Daemon Nodedev AppArmor SELinux Secrets Debug DTrace Readline Modular
|
||
~~~
|
||
|
||
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](#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](https://libvirt.org/formatdomain.html) 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`
|
||
|
||
### 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 <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](http://bugs.debian.org/740114)
|
||
|
||
/!\\ : 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 :
|
||
|
||
~~~
|
||
systcl -w net.bridge.bridge-nf-call-iptables=0
|
||
echo "net.bridge.bridge-nf-call-iptables=0" >> /etc/sysctl.d/zzz-evolinux_custom.conf
|
||
~~~
|
||
|
||
### 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 identique
|
||
* l'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 *--disk*
|
||
* si 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 ;
|
||
|
||
[Lien vers le ticket de ce bug](https://www.redhat.com/archives/libvirt-users/2014-October/msg00133.html)
|
||
|
||
~~~
|
||
--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 :
|
||
|
||
~~~
|
||
$ 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
|
||
|
||
voir [HowtoLVM]() et [HowtoDRBD]()
|
||
|
||
### 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 :
|
||
|
||
De façon similaire au format RAW, on peut agrandir une image QCOW2. Voir <http://blog.majerti.fr/resize-qcow2.html>
|
||
|
||
Convertir une image RAW en QCOW2 :
|
||
|
||
~~~
|
||
# 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
|
||
~~~
|
||
|
||
### 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
|
||
~~~
|
||
|
||
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 un `resize2fs` 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 <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 :
|
||
|
||
~~~{.xml}
|
||
<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 :
|
||
|
||
~~~{.xml}
|
||
<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.
|
||
|
||
~~~{.xml}
|
||
<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](#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 :
|
||
|
||
~~~{.bash}
|
||
#!/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 nettoyer `virsh 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**).
|
||
|
||
1. Une fois la VM éteinte il faut couper la synchro DRBD :
|
||
|
||
~~~
|
||
tic $ drbdadm down <old resource>
|
||
tac $ drbdadm down <old resource>
|
||
~~~
|
||
|
||
2. 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>
|
||
~~~
|
||
|
||
3. 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
|
||
~~~
|
||
|
||
4. 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
|
||
~~~
|
||
|
||
5. On peut alors reconnecter les nœuds DRBD :
|
||
|
||
~~~
|
||
tic $ drbdadm up <new resource>
|
||
tac $ drbdadm up <new resource>
|
||
~~~
|
||
|
||
6. Sur le nœud DRBD principal, on remet la ressource en primaire :
|
||
|
||
~~~
|
||
tic $ drbdadm primary <new resource>
|
||
~~~
|
||
|
||
7. On renomme la VM elle même :
|
||
|
||
~~~
|
||
tic $ virsh domrename <old DOM name> <new DOM name>
|
||
~~~
|
||
|
||
8. On ajuste les chemins des volumes dans la définition de la VM
|
||
|
||
~~~
|
||
tic $ virsh edit <new DOM name>
|
||
~~~
|
||
|
||
9. 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 --live --config
|
||
~~~
|
||
|
||
De la même manière, on peut détacher un disque avec `virsh detach-device`.
|
||
|
||
## 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
|
||
~~~
|
||
|
||
|
||
## 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 avec `virt-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'utiliser `cache=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>
|
||
~~~
|
||
|
||
### Etendre 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
|
||
~~~
|
||
|
||
### 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-qemu\x2dfoo.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é](https://bugzilla.redhat.com/show_bug.cgi?id=1207257), 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
|
||
|
||
~~~
|
||
<boot dev='cdrom'/>
|
||
~~~
|
||
|
||
avant `hd` dans le block
|
||
|
||
~~~
|
||
<os>
|
||
<type arch='x86_64' machine='pc-0.12'>hvm</type>
|
||
<boot dev='hd'/>
|
||
</os>
|
||
~~~
|
||
|
||
afin de bien booter sur le CD.
|
||
|
||
### Disposition qwerty
|
||
|
||
Si on veut que le vnc mis en place utilise une disposition de clavier qwerty
|
||
|
||
~~~
|
||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'>
|
||
~~~
|
||
|
||
### 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
|
||
~~~
|