←Tous les articles
Jeu. 3 septembre 2026·6 min de lecture

đŸ–„ïž KubeVirt : faire tourner des machines virtuelles dans Kubernetes

Schéma KubeVirt : un objet VirtualMachine déclaré en YAML, exécuté dans un pod virt-launcher avec libvirtd et QEMU, puis migré à chaud d'un noeud à l'autre

📚 Introduction

Ton infra est passĂ©e Ă  Kubernetes. Les applications sont en conteneurs, la CI construit des images, Argo CD synchronise le cluster sur Git. Et puis il reste ça : une VM Windows pour un logiciel mĂ©tier, une appliance rĂ©seau livrĂ©e en qcow2, un vieux serveur applicatif dont personne n’a plus les sources. Elle tourne sur un hyperviseur Ă  part, avec sa propre console, ses propres sauvegardes et ses propres droits d’accĂšs.

Deux plateformes Ă  maintenir pour une seule plateforme de charges de travail. C’est exactement le problĂšme que KubeVirt attaque : plutĂŽt que de containeriser cette VM de force, il la fait entrer dans le cluster telle quelle, dĂ©crite en YAML et pilotĂ©e par kubectl.

Le projet est entrĂ© Ă  la CNCF en septembre 2019 et est passĂ© en incubation le 19 avril 2022. La version stable au moment oĂč j’écris est la v1.9.0, sortie fin juillet 2026 et construite pour Kubernetes v1.36.

🔎 Comment une VM devient-elle une ressource Kubernetes ?

Par des CRD et un pod, essentiellement. KubeVirt enregistre de nouveaux types dans l’API — VirtualMachine, VirtualMachineInstance, VirtualMachineInstanceMigration — puis fait tourner chaque machine dans un pod ordinaire nommĂ© virt-launcher, qui encapsule libvirtd et QEMU.

Cette encapsulation est tout l’intĂ©rĂȘt du projet. Le scheduler place la VM comme il placerait un pod. Les requests et limits s’appliquent. Le RBAC vaut pour la VM comme pour le reste. Et le manifeste de la machine se commit Ă  cĂŽtĂ© des Deployments.

Autour de ce pod, l’opĂ©rateur installe trois composants dans le namespace kubevirt : virt-api pour l’API et les webhooks, virt-controller pour la logique de cycle de vie, et virt-handler, un DaemonSet qui pilote les VM sur chaque noeud, aux cĂŽtĂ©s du kubelet.

Architecture de KubeVirt : virt-api et virt-controller dans le plan de contrĂŽle, virt-handler en DaemonSet sur chaque noeud, et la VM dans un pod virt-launcher qui encapsule libvirtd et QEMU

🚀 Installer KubeVirt

L’installation se fait en deux manifestes : l’opĂ©rateur, puis la ressource personnalisĂ©e qui lui dit de se dĂ©ployer.

export VERSION=$(curl -s https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt)
kubectl create -f "https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml"
kubectl create -f "https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml"
 
kubectl -n kubevirt wait kv kubevirt --for condition=Available

Il faut ensuite virtctl, le CLI qui fait ce que kubectl ne sait pas faire sur une VM : dĂ©marrer, ouvrir une console sĂ©rie, brancher un Ă©cran VNC. Il s’installe aussi en plugin kubectl via krew.

kubectl krew install virt

CĂŽtĂ© prĂ©requis, l’apiserver doit tourner avec --allow-privileged=true, et les noeuds ont tout intĂ©rĂȘt Ă  exposer KVM — virt-host-validate le vĂ©rifie. Sur un cluster k3s de dev sans virtualisation imbriquĂ©e, l’émulation logicielle dĂ©panne via spec.configuration.developerConfiguration.useEmulation: true dans la CR. C’est lent. Pour du test d’API, ça suffit.

đŸ§± VirtualMachine et VirtualMachineInstance

Deux objets, une nuance qui compte. Le VirtualMachineInstance est la machine qui tourne : la supprimer, c’est l’éteindre pour de bon, sans possibilitĂ© de la relancer. Le VirtualMachine est l’objet durable qui dĂ©crit la machine et son Ă©tat souhaitĂ© ; c’est lui qui fabrique un VMI quand on dĂ©marre, et lui qu’on versionne.

Voici le manifeste d’exemple du guide officiel, dans sa forme minimale :

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: testvm
spec:
  runStrategy: Halted
  template:
    metadata:
      labels:
        kubevirt.io/size: small
        kubevirt.io/domain: testvm
    spec:
      domain:
        devices:
          disks:
            - name: containerdisk
              disk:
                bus: virtio
          interfaces:
            - name: default
              masquerade: {}
        resources:
          requests:
            memory: 64M
      networks:
        - name: default
          pod: {}
      volumes:
        - name: containerdisk
          containerDisk:
            image: quay.io/kubevirt/cirros-container-disk-demo

runStrategy: Halted crée la machine sans la démarrer. Le reste se pilote au CLI :

virtctl start testvm
virtctl console testvm    # ctrl+] pour sortir
virtctl pause vm testvm
virtctl stop testvm

Le containerDisk utilisĂ© ici embarque l’image disque dans une image de conteneur : pratique pour une dĂ©mo, Ă©phĂ©mĂšre par nature. Pour une VM qui doit garder son Ă©tat, on passe par un PVC alimentĂ© par CDI (Containerized Data Importer), le projet frĂšre qui importe une image qcow2 depuis une URL, un registre ou un upload local dans un DataVolume.

export TAG=$(curl -s -o /dev/null -w %{redirect_url} https://github.com/kubevirt/containerized-data-importer/releases/latest)
export VERSION=$(echo ${TAG##*/})
kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-operator.yaml
kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-cr.yaml

🧰 Instance types, prĂ©fĂ©rences et rĂ©seau

Recopier le mĂȘme bloc CPU/mĂ©moire dans quinze manifestes n’a aucun intĂ©rĂȘt. KubeVirt propose pour ça deux paires de CRD : VirtualMachineInstancetype (et sa variante cluster) fige les ressources — CPU, mĂ©moire, GPU, pĂ©riphĂ©riques hĂŽte —, tandis que VirtualMachinePreference dĂ©crit les choix prĂ©fĂ©rĂ©s de topologie et de pĂ©riphĂ©riques. La diffĂ©rence est nette : ce que fixe un instance type ne peut pas ĂȘtre surchargĂ© dans la VM, ce que suggĂšre une prĂ©fĂ©rence, si.

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: example-vm
spec:
  instancetype:
    kind: VirtualMachineInstancetype
    name: example-instancetype
  preference:
    kind: VirtualMachinePreference
    name: example-preference
  runStrategy: Always

CĂŽtĂ© rĂ©seau, la VM se branche par dĂ©faut sur le rĂ©seau du pod. Le binding masquerade est celui que recommande la documentation : la machine reçoit une adresse interne cachĂ©e derriĂšre du NAT, ce qui Ă©vite les frictions avec les solutions tierces que provoque le binding bridge. Pour un VLAN dĂ©diĂ© ou une seconde carte, Multus attache des rĂ©seaux secondaires, Ă  raison d’une interface dĂ©clarĂ©e par rĂ©seau.

🎯 Migration à chaud et snapshots

C’est lĂ  que le pari devient intĂ©ressant : la migration Ă  chaud, activĂ©e par dĂ©faut depuis longtemps, dĂ©place un VMI d’un noeud Ă  l’autre pendant que la charge continue de tourner.

virtctl migrate vmi-fedora
virtctl migrate-cancel vmi-fedora

La mĂȘme chose se dĂ©clare en YAML, ce qui la rend automatisable comme le reste :

apiVersion: kubevirt.io/v1
kind: VirtualMachineInstanceMigration
metadata:
  name: migration-job
spec:
  vmiName: vmi-fedora

Les sauvegardes suivent la mĂȘme logique avec le groupe d’API snapshot.kubevirt.io, qui s’appuie sur les VolumeSnapshot du driver CSI sous-jacent. Si l’agent invitĂ© QEMU est prĂ©sent, le contrĂŽleur gĂšle les systĂšmes de fichiers avant la capture, ce qui donne un instantanĂ© nettement plus propre.

apiVersion: snapshot.kubevirt.io/v1beta1
kind: VirtualMachineSnapshot
metadata:
  name: snap-larry
spec:
  source:
    apiGroup: kubevirt.io
    kind: VirtualMachine
    name: larry

Et puisque tout ça reste du YAML dans l’API Kubernetes, une VM se dĂ©ploie en GitOps et se surveille avec la stack Prometheus habituelle. Un seul jeu d’outils pour les deux mondes.

⚠ Quelques prĂ©cautions

  • Le stockage dĂ©cide de ce que tu pourras faire. La migration Ă  chaud exige des volumes en ReadWriteMany, et les snapshots demandent un StorageClass couvert par un VolumeSnapshotClass. Un cluster montĂ© sur du local-path ne fera ni l’un ni l’autre.
  • Le feature gate Snapshot doit ĂȘtre ajoutĂ© Ă  la liste des feature gates de la CR KubeVirt pour que l’API snapshot rĂ©ponde. Sans VolumeSnapshotClass, la sauvegarde se limite Ă  la configuration de la VM.
  • Le binding bridge bloque la migration Ă  chaud, tout comme les ports 49152-49153 s’ils ne sont pas joignables dans le pod virt-launcher. Le choix du binding rĂ©seau n’est pas qu’une affaire de connectivitĂ©.
  • KubeVirt n’est pas une plateforme de virtualisation clĂ© en main. Pas d’interface web, pas d’inventaire, pas d’assistant de crĂ©ation. C’est une API. Si tu cherches l’équivalent d’un Proxmox VE, regarde plutĂŽt Harvester ou OpenShift Virtualization, qui posent une couche produit par-dessus.
  • La v1.9 active par dĂ©faut tous les feature gates en bĂȘta. Bonne nouvelle pour l’ergonomie, point de vigilance lors d’une montĂ©e de version : relis les notes de release avant de mettre Ă  jour un cluster en production.

🎉 Conclusion

KubeVirt ne rend pas les VM plus modernes, et ce n’est pas son ambition. Il supprime la seconde plateforme. Ton hyperviseur, ton ordonnanceur, ton RBAC et ton pipeline de dĂ©ploiement deviennent les mĂȘmes pour un conteneur et pour une machine complĂšte, ce qui vaut surtout quand la migration vers les conteneurs s’étale sur des annĂ©es et qu’il faut bien opĂ©rer les deux en attendant.

Le prix Ă  payer est rĂ©el : des exigences de stockage plus strictes qu’un hyperviseur classique, une couche de plus Ă  diagnostiquer, et une ergonomie qui suppose d’ĂȘtre dĂ©jĂ  Ă  l’aise avec l’API Kubernetes. Sur un cluster dĂ©jĂ  en place et dĂ©jĂ  maĂźtrisĂ©, c’est un bon marchĂ©.

🔗 Liens utiles

/faq

Questions fréquentes

Qu'est-ce que KubeVirt ?

+

KubeVirt est un projet CNCF en incubation qui ajoute des CRD Ă  Kubernetes pour dĂ©crire et piloter des machines virtuelles. Chaque VM tourne dans un pod « virt-launcher » qui encapsule libvirt et QEMU, ce qui lui donne le mĂȘme ordonnancement, le mĂȘme RBAC et la mĂȘme API que n'importe quelle autre charge du cluster.

Quelle est la différence entre VirtualMachine et VirtualMachineInstance ?

+

Le VirtualMachineInstance (VMI) est l'instance Ă©phĂ©mĂšre qui tourne rĂ©ellement : le supprimer Ă©teint la VM dĂ©finitivement. Le VirtualMachine (VM) est l'objet stable qui dĂ©crit la machine et son Ă©tat souhaitĂ©, et qui recrĂ©e le VMI Ă  chaque dĂ©marrage — c'est celui qu'on versionne dans Git.

Faut-il de la virtualisation matérielle pour installer KubeVirt ?

+

C'est fortement recommandĂ© : les noeuds doivent exposer KVM, ce que « virt-host-validate » permet de vĂ©rifier. À dĂ©faut, l'Ă©mulation logicielle s'active avec « spec.configuration.developerConfiguration.useEmulation: true » dans la CR KubeVirt, mais les performances sont sans commune mesure et ce mode reste rĂ©servĂ© au test.

KubeVirt peut-il remplacer Proxmox ou VMware ?

+

Pas tel quel : KubeVirt est une API, pas une plateforme clé en main, et il n'embarque ni interface web ni gestion d'inventaire. Les distributions qui s'appuient dessus, comme Harvester ou OpenShift Virtualization, apportent cette couche produit par-dessus.