.. meta:: :description: Exercices QEMU/KVM :keywords: Linux, QEMU, KVM, virtualisation, Libvirt, virsh Quelques travaux avec QEMU/KVM et virsh *************************************** .. admonition:: Résumé Administrations de machines virtuelles. Installer une machine virtuelle Linux ------------------------------------- Virt-install ++++++++++++ * Installez une machine virtuelle debian12.5 netinstall dans la machine virtuelle Ubuntu .. code-block:: virt-install \ --name debian12.5 \ --ram 1024 \ --disk size=10 \ --vcpus 1 \ --network bridge=virbr0 \ --location debian-12.5.0-amd64-netinst.iso \ --graphics none \ --console pty,target_type=serial \ --extra-args='console=ttyS0' \ --initrd-inject preseed.cfg \ --os-variant debian12 Utiliser PXE pour installer Linux dans QEMU/KVM +++++++++++++++++++++++++++++++++++++++++++++++ * Modifier la définition du réseau par défaut .. code-block:: default 5c804474-b1ce-4e0f-8b72-b2036b6c735b * Puis rechargez le réseau .. code-block:: # virsh net-destroy default Network default destroyed # virsh net-edit default # virsh net-start default Network default started Installer les fichiers PXE sur le host ++++++++++++++++++++++++++++++++++++++ On peut trouver les fichiers d'installation pour PXE dans le répertoire partagé du paquet syslinux. Attention, le répertoire des fichiers tftp peut être /var/lib/tftp ou /tftpboot. Y copier le fichier de boot et le loader ainsi que le noyau et l'initramfs du CDROM d'installation de la cible. Pour le pxe, il continent un initramfs avec les modules virtio. .. code-block:: # yum install syslinux # cp /usr/share/syslinux/pxelinux.0 /tftpboot # cp /usr/share/syslinux/ldlinux.c32 /tftpboot/ # cp /cdrom/images/pxeboot/vmlinuz /tftpboot # cp /cdrom/images/pxeboot/initrd.img /tftpboot/ Vérifiez que le répertoire tftpboot est accessible en lecture pour tous. * Configurer PXE Créer le répertoire /tftpboot/pxelinux.cfg et le fichier de configuration. .. code-block:: # mkdir /tftpboot/pxelinux.cfg # cat < EOF > /tftpboot/pxelinux.cfg/default PROMPT 1 TIMEOUT 50 DEFAULT Linux LABEL Linux KERNEL vmlinuz INITRD initrd.img APPEND inst.ks=http://xxx.xxx.xxx.xxx/ks.cfg ip=dhcp net.ifnames=0 EOF * Autoriser http à passer le firewall .. code-block:: # firewall-cmd --add-service=http --zone=libvirt # firewall-cmd --add-service=http --zone=libvirt --permanent * Lancer virt-install .. code-block:: # virt-install --pxe --network network=default --os-variant=almalinux9 créer une VM busybox avec virsh define/start ++++++++++++++++++++++++++++++++++++++++++++ Utiliser la définition de busybox.xml que vous pouvez trouver dans les sources de rfs: `rfs `_ , utilisez le noyau de votre host puis fabriquez rfs00.gz en utilisant le script build.me .. code-block:: rfs # cp /boot/vmlinuz . rfs # ./build.me Ou bien, récupérez vmlinuz et rfs00.gz du formateur .. code-block:: $ virsh define busybox.xml $ virsh start Busybox Ensuite vous pouvez utiliser virsh pour travailler sur la nouvelle vm * lister toutes les VM .. code-block:: $ virsh list --all * sauvegarder puis restaurer une VM .. code-block:: $ virsh save Busybox BB.state $ virsh restore BB.state Modifier le XML d'une VM pour autoriser le hotplug ++++++++++++++++++++++++++++++++++++++++++++++++++ .. code-block:: 2 utiliser virsh setcpus et virsh setcpu ++++++++++++++++++++++++++++++++++++++ * Lister les vCPUs disponibles .. code-block:: $ virsh vcpucount Busybox maximum config 2 maximum live 2 current config 1 current live 1 * Ajouter un vCPU .. code-block:: $ virsh setvcpus Busybox 2 • vérifier sur le guest .. code-block:: # cat /proc/cpuinfo * mettre un CPU offline dans le guest .. code-block:: # echo 0 > /sys/devices/system/cpu/cpu1/online * Retirer un CPU du guest .. code-block:: $ virsh setvcpus Busybox 1 Changer la taille de la mémoire dans le XML .. code-block:: 1524288 524288 524288 Modifier pour : .. code-block:: 1524288 524288 524288 Modifier la taille de mémoire utilisée ++++++++++++++++++++++++++++++++++++++ * Effectuer des statistiques toutes les 5s et arrêter la VM .. code-block:: # virsh dommemstat --domain almalinux9-2 --period 5 # virsh shutdown BB2 # virsh destroy BB2 # virsh setmaxmem BB2 2G $ virsh dominfo BB2 Id: - Name: BB UUID: 1e071db9-b12f-40bb-930a-e16ab9d979f5 OS Type: hvm State: shut off CPU(s): 1 Max memory: 1048576 KiB Used memory: 1048576 KiB Persistent: yes Autostart: disable Managed save: no Security model: none Security DOI: 0 Redémarrez la machine virtuelle. Après redémarrage : .. code-block:: $ virsh dominfo BB2 Used memory: 2096128 KiB * Réduire la taille de la mémoire utilisée par la VM .. code-block:: $ virsh setmem BB2 1G $ virsh dominfo BB2 1048576 KiB UItiliser le Stockage --------------------- * Créer un disque QCOW2 et assignez le à une VM existante * Créer Le fichier qcow2 .. code-block:: # qemu-img create -f qcow2 disk_01.qcow2 5G * Monter le disque virtuel et le formater, écrire dedans .. code-block:: # modprobe nbd # qemu-nbd --connect=/dev/nbd0 -f qcow2 disk_01.qcow2 # fdisk /dev/nbd0 -l # mkfs.ext4 /dev/nbd0 # mount /dev/nbd0 /mnt/ # date > /mnt/date.txt # umount /dev/nbd0 # qemu-nbd --disconnect /dev/nbd0 * Créer le fichier XML de définition du disque, disk.xml .. code-block::
* Attacher le disque au domaine .. code-block:: $ virsh attach-device debian12.5 disk.xml * Créer un pool à partir d'un volume groupe LVM et l'assigner à une VM existante * Sur le host, assigner une partition comme physical volume puis créer le Volume Group .. code-block:: # pvcreate /dev/vdb1 # vgcreate vg0 /dev/vdb1 * Définir le pool et le démarrer .. code-block:: # virsh pool-define-as deb-lvm logical --source-name vg0 --target /dev/vg0 # virsh pool-start deb-lvm # virsh pool-autostart deb-lvm * Créer un logical volume dans le pool .. code-block:: $ virsh vol-create-as deb-lvm raw_disk.img 5G --format raw * Vérifier et attacher le disque .. code-block:: $ virsh vol-list --pool deb-lvm --details $ virsh attach-disk debian12.5 /dev/vg0/raw_disk.img vdb Créer un snapshot pour une VM existante et vérifier le nom des périphériques block associés à la VM .. code-block:: # virsh domblklist debian12.5 Target Source ------------------ vda /home/user/OKVM/sn1.qcow2 sda /home/user/OKVM/debian-12.5.0-amd64-netinst.iso * Créez un snapshot et vérifier .. code-block:: # virsh snapshot-create-as debian12.5 snap_01 --disk-only --atomic \ --diskspec vda,file=/var/lib/libvirt/images/snap_01.qcow2 Domain snapshot snap_01 created # virsh snapshot-list debian12.5 Name Creation Time State ------------------------------------------------ snap_01 2024-04-12 16:35:10 +0200 running * Vérifiez que vous pouvez revenir en arrière en créant un fichier sur le guest .. code-block:: # date > /Estampille.txt * Arrêtez la VM .. code-block:: # virsh shutdown debian12.5 * Supprimez le snapshot .. code-block:: # rm /var/lib/libvirt/images/snap_01.qcow2 # virsh snapshot-delete debian12.5 --metadata snap_01 * Editez le XML et définissez l'ancien disque .. code-block::
Utiliser soit 9P soit VIRTIO-FS pour échanger des fichiers entre host et guest ------------------------------------------------------------------------------ * Ajouter le XML au domaine .. code-block:: * Dans le guest charger le module puis monter le fichiers .. code-block:: # modprobe 9p [ 7.102545] 9pnet: Installing 9P2000 support [ 7.113678] FS-Cache: Loaded [ 7.120316] 9p: Installing v9fs 9p2000 file system support [ 7.122468] FS-Cache: Netfs '9p' registered for caching / # modprobe 9pnet-virtio / # lsmod Module Size Used by Not tainted 9pnet_virtio 20480 0 9p 61440 0 fscache 380928 1 9p 9pnet 86016 2 9pnet_virtio,9p / # # mount -t 9p mount_1 /mnt/ NOTE en cas de problème vérifiez que le fichier virtio-9p fait bien partie des modules de votre guest. VFIO: associer une clef USB à un guest -------------------------------------- * Trouver la clef USB avec lsusb .. code-block:: # lsusb * Créer le fichier usb_dev.xml .. code-block:: * Attacher le périphérique au guest .. code-block:: # virsh attach-device deb12 --file usb_dev.xml --config Utiliser un disque encrypté par Luks ------------------------------------ * Soyez sur de démarrer le daemon virtsecretd .. code-block:: $ sudo systemctl enable virtsecretd $ sudo systemctl start virtsecretd * Créer le disque avec qemu-img .. code-block:: $ sudo qemu-img create --object secret,id=sec0,data="super secret" \ -f qcow2 \ -o encrypt.format=luks,encrypt.key-secret=sec0 \ /var/lib/libvirt/images/crypted_volume.img 1G Formatting 'base.qcow2', fmt=qcow2 encrypt.format=luks encrypt.key-secret=sec0 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16 * Générer le UUID .. code-block:: $ uuidgen 65e8ecb8-6141-48b6-bae4-aa879c3e2245 * Définir le secret pour le volume encrypté pour Libvirt .. code-block:: $ cat volume-secret.xml Encryption :Luks 65e8ecb8-6141-48b6-bae4-aa879c3e2245 /var/lib/libvirt/images/crypted_volume.img * Déclarer le secret dans Libvirt .. code-block:: $ virsh secret-define volume-secret.xml Secret 65e8ecb8-6141-48b6-bae4-aa879c3e2245 created * Définir le secret dans Libvirt "super secret" comme lors de la fabrication de l'image disque .. code-block:: $ virsh secret-set-value --interactive 65e8ecb8-6141-48b6-bae4-aa879c3e2245 Enter new value for secret: Secret value set ... * Définir le disque avec l’encryption .. code-block::
* Attacher le disque à la VM Attention, si vous avez une erreur disant que le hotplug PCI n'est pas possible, vérifiez que vous avez bien défini l'ACPI et l'APIC dans le XML du domaine. .. code-block:: $ sudo virsh -c qemu:///system attach-device almalinux9 disk-luks.xml .. code-block:: TP Monitoring ------------- * Utiliser QMP pour vérifier si KVM est activé .. code-block:: $ virsh qemu-monitor-command debian12.5 --pretty '{"execute":"query-kvm"}' { "return": { "enabled": true, "present": true }, "id": "libvirt-12770" } * Utiliser HMP pour afficher les informations sur l'arbre des périphériques (info qtree) et les mémoires (info mtree) .. code-block:: $ virsh qemu-monitor-command debian12.5 --hmp "info qtree" et .. code-block:: $ virsh qemu-monitor-command debian12.5 --hmp "info mtree" * Retrouver pour le guest le nombre d'injections d'interruption et de sortie d'interruption .. code-block:: # cat /sys/kernel/debug/kvm/2360172-16/{irq_injections,irq_exits} 162 187270 Utiliser QMP pour gérer le balooning ------------------------------------ * Ecoutez sur la socket QMP .. code-block:: # virsh -c qemu:///system qemu-monitor-event debian12.5 --pretty --loop * Vous pouvez recevoir ce type d'événement : .. code-block:: <- { "event": "BALLOON_CHANGE", "data": { "actual": 944766976 }, "timestamp": { "seconds": 1267020223, "microseconds": 435656 } } actual représente la taille de la mémoire utilisable par le guest logical_vm_size = vm_ram_size - balloon_size * Définir la taille de la mémoire utilisable par le guest avec QMP .. code-block:: <- {"execute": "balloon", "arguments": {"value": 2147483648}} -> {"return": {}} * Demander la taille du ballon .. code-block:: <- {"execute": "query-balloon"} -> {"return":{"actual":2147483648}} TP Migration ------------ * Suivre avec QMP .. code-block:: $ virsh qemu-monitor-event debian12.5 --pretty --loop event VSERPORT_CHANGE at 1712907760.795105 for domain 'debian12.5': { "open": false, "id": "channel0" } * Effectuer une migration live .. code-block:: $ virsh migrate --live debian12.5 almaLinux * Effectuer une migration de Busybox avec QEMU Dans QEMU monitor effectuer les commandes suivantes (définir la vitesse est optionnel): .. code-block:: (qemu) stop (qemu) migrate_set_speed 4095m (qemu) migrate "exec:gzip -c > STATEFILE.gz" du coté de la cible il sera nécessaire de copier tous les supports de stockage et de rétablir le réseau de l'hôte correctement avant d'ajouter à la commande QEMU: .. code-block:: -incoming "exec: gzip -c -d STATEFILE.gz" .. admonition:: Note Attention à la compatibilité entre les machines distantes et les CPU disponibles sinon la migration sera impossible. TP outils --------- Guestfs +++++++ * Créer un programme utilisant guestfs Libguesrfs propose un nouveau disque comme /dev/sda. Le programme suivant crée un fichier hello à la racine du disque. .. code-block:: #include int main() { guestfs_h \*g = guestfs_create (); guestfs_add_drive (g, "guest.img"); guestfs_launch (g); guestfs_mount (g, "/dev/sda", "/"); guestfs_touch (g, "/hello"); guestfs_umount (g, "/"); guestfs_shutdown (g); guestfs_close (g); } * Le compiler .. code-block:: $ cc do_guest_img.c -o do_guest_img -lguestfs * Fabriquer un disque format raw .. code-block:: $ dd if=/dev/zero of=guest.img bs=1M count=4 $ mkfs.ext2 guest.img * Créer le fichier hello sur le disque .. code-block:: $ /do_guest_img * Analyser le disque avec virt-rescue Virt-rescue lance un mini guest et propose le disque jouté comme /dev/sda .. code-block:: $ virt-rescue -a guest.img … > mount /dev/sda /sysroot/ > ls /sysroot/ hello lost+found > exit polkit ++++++ * Lister les actions disponibles .. code-block:: $ pkaction org.cockpit-project.cockpit.root-bridge org.fedoraproject.FirewallD1.all … org.libvirt.api.storage-pool.delete org.libvirt.api.storage-pool.format org.libvirt.api.storage-pool.getattr org.libvirt.api.storage-pool.read org.libvirt.api.storage-pool.refresh org.libvirt.api.storage-pool.save org.libvirt.api.storage-pool.search-storage-vols org.libvirt.api.storage-pool.start org.libvirt.api.storage-pool.stop org.libvirt.api.storage-pool.write org.libvirt.api.storage-vol.create org.libvirt.api.storage-vol.data-read org.libvirt.api.storage-vol.data-write org.libvirt.api.storage-vol.delete org.libvirt.api.storage-vol.format org.libvirt.api.storage-vol.getattr org.libvirt.api.storage-vol.read org.libvirt.api.storage-vol.resize org.libvirt.unix.manage org.libvirt.unix.monitor * Autoriser tout le monde à manager libvirtd Editer /usr/share/polkit-1/rules.d/01-mylibvirt.rules .. code-block:: polkit.addRule(function(action, subject) { if (action.id == "org.libvirt.unix.manage") { polkit.log("Hello my libvirt rule"); return polkit.Result.YES; } });