Déployer une machine virtuelle à partir d'une image cloud de Fedora ou Centos

On trouve des images de Fedora ou de Centos à télécharger, portant la mention de "cloud image". Contrairement à une image iso, cette image contient un système déja installé, et évite d'avoir à passer par toutes les étapes de l'installation avant de pouvoir l'utiliser.

Les avantages sont la rapidité de déploiement: déployer une machine est presque aussi rapide que de copier un image disque. L'inconvénient est qu'une telle image n'est pas utilisable telle quelle. Il faudra la personnaliser lors de son premier déploiement avec cloud-init afin de créer les utilisateurs et leurs clés ssh, par exemple.

Les commandes de cet article ont étés testées sur Fedora 33, mais devraient fonctionner sur les versions récentes de Fedora, de Red Hat Enterprise Linux ou de CentOS.

Installation de libvirt

Commençons par installer libvirt, afin de pouvoir lancer des VM Vérifier que le processeur supporte la virtualisation

Commençons par vérifier que les instructions du processeur sont présentes afin d'avoir de bonnes performances:

    host# cat /proc/cpuinfo | egrep "vmx|svm"

Si aucune ligne n'apparait en lançant cette commande, soit votre processeur est très ancien, soit vous devez activer les instructions "vt" dans le bios de votre machine.

Installation de libvirt et quelques outils

Lancer la commande suivante pour installer les packages requis host# sudo dnf -y install libvirt virt-install qemu-kvm cloud-utils bridge-utils wget

Les paquets installés sont :

    libvirt, qemu-kvm: ce sont les paquets requis pour lancer des VM
    virt-install : un outil pour créer des VM à partir d'options fournies en ligne de commande
    cloud-utils : un outil permettant de manipuler des fichiers cloud-init
    bridge-utils : un outil pour manipuer les interfaces bridges. On ne l'utilise pas dans cet article, mais ça peut être utile pour vérifier le fonctionnement du réseau
    wget : permet de télécherger facilement des fichiers depuis une URL

Lancer et démarrer le démon libvirt

Lancer Libvirt et l'activer au démarrage du système: host# sudo systemctl enable libvirtd --now

On peut vérifier que les modules kvm et kvm_intel (ou kvm_amd) sont chargés

    host# lsmod | grep kvm
    kvm_intel             319488  0
    kvm                   823296  1 kvm_intel
    irqbypass              16384  1 kvm

Si seul le module kvm est chargé, les instructions de virtualisation intégrées au processeur ne seront pas utilisées, et les performances des VM ne seront pas optimales

Récupération et redimensionnement de l'image centos stream 8

Récupérer l'image de CentOS depuis https://cloud.centos.org/centos/8-stream/x86_64/images/ :

    host# wget https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-20200113.0.x86_64.qcow2

Copier l'image dans /var/lib/libvirt/images

host# cp CentOS-Stream-GenericCloud-8-20200113.0.x86_64.qcow2 /var/lib/libvirt/images/server.qcow2

Ce répertoire est le répertoire par défaut où sont stockées les images des VMs. Il est possible de les stocker ailleurs, mais il faut changer les contextes selinux pour que tout fonctionne bien. Donc, par facilité, on utilise le répertoire par défaut

Redimensionner l'image, par exemple à 30Go:

    host# qemu-img resize /var/lib/libvirt/images/server.qcow2 30G
    Image resized.

Cloud-init

Cloud-init est un fichier yaml qui décrit les modifiations à appliquer à la machine lors de son premier démarrage. Dans cet exemple, on va faire le minimum pour avoir une machine sur laquelle on peut se connecter et utiliser sudo pour devenir root.

Créer un fichier. Son nom et sa location n'est pas importante dans cette étape:

    vi cloud-user
    #cloud-config
    users:
      - name: nicolas
        groups: [ wheel ]
        sudo: [ "ALL=(ALL) NOPASSWD:ALL" ]
        shell: /bin/bash
        ssh-authorized-keys:
        - ssh-rsa AAAA[...]ErC+Ak7bUUdvjVGsAlDeNPFsck= root@tiger.local

Dans ce fichier, nous définissons un utilisateur, dont le nom est "nicolas", qui est dans le groupe wheel, qui a un shell bash, et qui peut se connecter avec la clé privée qui correspond à la clé publique renseignée. La ligne sudo permet d'utiliser la commande sudo sans mot de passe. Sur CentOS ou RHEL, les membres du groupe wheel peuvent utiliser sudo, mais doivent taper leur mot de passe. Et je ne voulais pas créer un mot de passe pour cet utilisateur. Cette ligne a pour effet de créer dans la VM un fichier /etc/sudoers.d/90-cloud-init-users contenant :

    # User rules for nicolas
    nicolas ALL=(ALL) NOPASSWD:ALL

Créer une image iso contenant ce fichier de paramétrage pour cloud-init : host# cloud-localds /var/lib/libvirt/images/server-user.iso cloud-user

Création de la VM et premier lancement

Entrer la commande suivante pour créer une VM qui s'appelle "serveur", avec 2Go de RAM, et les disques que nous avons créés précédemment :

    host#  virt-install --name server \
          --memory 2048 \
          --disk /var/lib/libvirt/images/server.qcow2,device=disk,bus=virtio \
          --disk /var/lib/libvirt/images/server-user.iso,device=cdrom \
          --os-type linux --os-variant centos8 \
          --virt-type kvm --graphics none \
          --network network=default,model=virtio \
          --import

L'installation débute

    Starting install...

Running text console command: virsh --connect qemu:///system console server Connected to domain server

    Escape character is ^] (Ctrl + ])
    [    0.000000] Linux version 4.18.0-147.3.1.el8_1.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 8.3.1 20190507 (Red Hat 8.3.1-4) (GCC)) #1 SMP Fri Jan 3 23:55:26 UTC 2020
    [    0.000000] Command line: BOOT_IMAGE=(hd0,msdos1)/boot/vmlinuz-4.18.0-147.3.1.el8_1.x86_64 root=UUID=6fcd25ee-bbf3-4fc5-b449-c6a23ac51c07 ro console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=auto
    [..]
    [  OK  ] Started Update UTMP about System Runlevel Changes.

    CentOS Linux 8 (Core)
    Kernel 4.18.0-147.3.1.el8_1.x86_64 on an x86_64

    Activate the web console with: systemctl enable --now cockpit.socket

    localhost login:

L'invite de login s'affiche, mais comme nous ne possédons pas de mot de passe, ni pour root, ni pour utilisateur standard, il faut se connecter avec ssh à la machine. Appuyer sur [CRTL]+[$] pour quitter la console de la VM, et revenir sur l'hôte

    Domain creation completed.
    host#
    Connexion à la VM

Libvirt affecte une adresse aux machines crées sur le bridge virbr0 que nous avons utilisé. Entrez la commande suivante pour obtenir l'adresse de la VM:

    host#  virsh net-dhcp-leases default
    Expiry Time           MAC address         Protocol   IP address          Hostname   Client ID or DUID
    -----------------------------------------------------------------------------------------------------------
    2020-12-26 17:06:38   52:54:00:fa:9e:b7   ipv4       192.168.122.71/24   -          01:52:54:00:fa:9e:b7

Dans mon exemple, l'adresse de la VM est 192.168.122.71.

    # ssh nicolas@192.168.122.71
    The authenticity of host '192.168.122.71 (192.168.122.71)' can't be established.
    ECDSA key fingerprint is SHA256:HWeKa0vLmqHpfoFm+95AIxmmO8oH+Pjqy2H4YwmSLpo.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added '192.168.122.71' (ECDSA) to the list of known hosts.
    Activate the web console with: systemctl enable --now cockpit.socket

    [nicolas@localhost ~]$ sudo su
    [root@localhost nicolas]#

On peut se connecter à la VM, et devenir root.

NSS et utilisation des noms de VM à la place de leur adresse IP

Jusqu'à présent, il faut chercher l'IP de la machine. On ne peut pas utiliser son nom directement :

host# ping server
ping: server: Name or service not known

Le paquet libvirt-nss permet d'utiliser les infos provenant de libvirt au sein de nns afin d'effectuer la résolution de noms. La commande suivante permet de l'installer:

    host# dnf install libvirt-nss

Ajouter "libvirt libvirt_guest" dans la ligne "host:" du fichier /etc/nsswitch.conf afin d'ajouter libvirt dans les sources de résolutions de noms d'hôtes:

    hosts:      files libvirt libvirt_guest resolve [!UNAVAIL=return] myhostname dns

Il est maintenant possible d'utiliser le nom de la VM dans des commandes :

    # ping server
    PING server (192.168.122.151) 56(84) bytes of data.
    64 bytes from 192.168.122.151 (192.168.122.151): icmp_seq=1 ttl=64 time=0.224 ms
    64 bytes from 192.168.122.151 (192.168.122.151): icmp_seq=2 ttl=64 time=0.171 ms
    ^C
    --- server ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1002ms
    rtt min/avg/max/mdev = 0.171/0.197/0.224/0.026 ms

Comments !

links

social