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

đ 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.
đ 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=AvailableIl 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 virtCĂŽ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-demorunStrategy: 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 testvmLe 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: AlwaysCĂŽ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-fedoraLa 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-fedoraLes 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: larryEt 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 unStorageClasscouvert par unVolumeSnapshotClass. Un cluster montĂ© sur du local-path ne fera ni lâun ni lâautre. - Le feature gate
Snapshotdoit ĂȘtre ajoutĂ© Ă la liste des feature gates de la CR KubeVirt pour que lâAPI snapshot rĂ©ponde. SansVolumeSnapshotClass, la sauvegarde se limite Ă la configuration de la VM. - Le binding
bridgebloque la migration Ă chaud, tout comme les ports 49152-49153 sâils ne sont pas joignables dans le podvirt-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.