
Ce guide vous fait executer une premiere stack Pulumi vraiment concrete.
Vous allez creer un reseau NAT, un disque clone depuis une cloud image Ubuntu,
un disque cloud-init, puis une vraie VM KVM. Ensuite, vous verifierez
avec virsh que le domaine est bien en etat running, avant de rejouer
pulumi destroy pour revenir a un etat propre.
Le scenario a ete rejoue integralement le 1 avril 2026 sur KVM/libvirt. Le
resultat attendu n’est plus seulement une ressource reseau, mais une VM
pulumi-lab-vm qui demarre reellement.
Ce que vous allez obtenir
Section intitulée « Ce que vous allez obtenir »- un
previewannoncant le reseau, le disque clone, le cloud-init et la VM ; - un reseau libvirt nomme
pulumi-lab-net; - une VM pulumi-lab-vm en etat
running; - une verification concrete via
virsh; - un
destroyqui supprime toutes les ressources sans residu.
Etape 1 - Ouvrir le projet local
Section intitulée « Etape 1 - Ouvrir le projet local »Placez-vous dans le projet prepare au guide precedent :
cd ~/pulumi-kvm-localsource venv/bin/activatepulumi stack select devVerification : pulumi stack select dev ne doit pas retourner d’erreur.
Etape 2 - Remplacer le code de la stack
Section intitulée « Etape 2 - Remplacer le code de la stack »Remplacez le contenu de __main__.py par ce programme :
import pulumiimport pulumi_libvirt as libvirt
provider = libvirt.Provider( "libvirt-provider", uri="qemu:///system",)
lab_network = libvirt.Network( "pulumi-lab-network", name="pulumi-lab-net", autostart=True, domain=libvirt.NetworkDomainArgs(name="pulumi.lab"), forward=libvirt.NetworkForwardArgs(mode="nat"), ips=[ libvirt.NetworkIpArgs( address="192.168.151.1", prefix=24, dhcp=libvirt.NetworkIpDhcpArgs( ranges=[ libvirt.NetworkIpDhcpRangeArgs( start="192.168.151.50", end="192.168.151.200", ) ] ), ) ], opts=pulumi.ResourceOptions(provider=provider),)
vm_disk = libvirt.Volume( "pulumi-lab-vm-disk", name="pulumi-lab-vm.qcow2", pool="default", capacity=20, capacity_unit="GiB", backing_store=libvirt.VolumeBackingStoreArgs( path="/var/lib/libvirt/images/ubuntu-22.04-cloudimg.qcow2", format=libvirt.VolumeBackingStoreFormatArgs(type="qcow2"), ), target=libvirt.VolumeTargetArgs( format=libvirt.VolumeTargetFormatArgs(type="qcow2"), ), opts=pulumi.ResourceOptions(provider=provider),)
cloudinit_disk = libvirt.CloudinitDisk( "pulumi-lab-cloudinit", name="pulumi-lab-cloudinit.iso", meta_data="""instance-id: pulumi-lab-vmlocal-hostname: pulumi-lab-vm""", user_data="""#cloud-confighostname: pulumi-lab-vmmanage_etc_hosts: truepackage_update: truepackages: - qemu-guest-agentruncmd: - systemctl enable --now qemu-guest-agent""", opts=pulumi.ResourceOptions(provider=provider),)
lab_vm = libvirt.Domain( "pulumi-lab-vm", type="kvm", name="pulumi-lab-vm", memory=2048, memory_unit="MiB", vcpu=2, running=True, os=libvirt.DomainOsArgs( type="hvm", type_arch="x86_64", ), devices=libvirt.DomainDevicesArgs( disks=[ libvirt.DomainDevicesDiskArgs( device="disk", source=libvirt.DomainDevicesDiskSourceArgs( volume=libvirt.DomainDevicesDiskSourceVolumeArgs( pool="default", volume=vm_disk.name, ), ), target=libvirt.DomainDevicesDiskTargetArgs( dev="vda", bus="virtio", ), ), libvirt.DomainDevicesDiskArgs( device="cdrom", read_only=True, source=libvirt.DomainDevicesDiskSourceArgs( file=libvirt.DomainDevicesDiskSourceFileArgs( file=cloudinit_disk.path, ), ), target=libvirt.DomainDevicesDiskTargetArgs( dev="hda", bus="ide", ), ), ], interfaces=[ libvirt.DomainDevicesInterfaceArgs( source=libvirt.DomainDevicesInterfaceSourceArgs( network=libvirt.DomainDevicesInterfaceSourceNetworkArgs( network=lab_network.name, ), ), model=libvirt.DomainDevicesInterfaceModelArgs(type="virtio"), ), ], ), opts=pulumi.ResourceOptions(provider=provider),)
pulumi.export("network_name", lab_network.name)pulumi.export("network_id", lab_network.id)pulumi.export("network_uuid", lab_network.uuid)pulumi.export("vm_name", lab_vm.name)pulumi.export("vm_disk_name", vm_disk.name)Ce premier vrai exemple assemble quatre briques que vous devez apprendre a distinguer :
- le reseau NAT ;
- le disque clone qui part d’une cloud image Ubuntu ;
- le disque cloud-init qui donne son identite initiale a la VM ;
- le domaine libvirt qui correspond a la VM elle-meme.
Etape 3 - Lancer le preview
Section intitulée « Etape 3 - Lancer le preview »pulumi preview --stack devLe preview doit annoncer la creation des elements suivants :
- la stack Pulumi ;
- le provider libvirt ;
- le reseau
pulumi-lab-net; - le disque
pulumi-lab-vm.qcow2; - le disque
pulumi-lab-cloudinit.iso; - le domaine
pulumi-lab-vm.
Si ce n’est pas le cas, corrigez le projet avant de lancer up.
Etape 4 - Appliquer la stack
Section intitulée « Etape 4 - Appliquer la stack »pulumi up --stack dev --yesVerification : le resume final doit annoncer la creation du domaine et
exposer au minimum network_name, vm_name et vm_disk_name.
Etape 5 - Verifier le resultat cote libvirt
Section intitulée « Etape 5 - Verifier le resultat cote libvirt »Controlez maintenant le resultat du point de vue de libvirt :
virsh net-list --all | grep pulumi-lab-netvirsh net-dumpxml pulumi-lab-netvirsh list --all | grep pulumi-lab-vmvirsh domstate pulumi-lab-vmvirsh domiflist pulumi-lab-vmVous devez observer au minimum :
- un reseau
pulumi-lab-netenactive; Autostartayes;- un domaine
pulumi.lab; - l’adresse
192.168.151.1/24; - une plage DHCP de
192.168.151.50a192.168.151.200; - une VM
pulumi-lab-vmen etatrunning; - une interface
virtioraccordee au reseaupulumi-lab-net.
Cette verification est importante : elle prouve que le state Pulumi et l’etat reel de libvirt racontent la meme histoire.
Etape 6 - Detruire proprement la stack
Section intitulée « Etape 6 - Detruire proprement la stack »pulumi destroy --stack dev --yesPuis verifiez l’absence des ressources :
virsh net-list --all | grep pulumi-lab-netvirsh list --all | grep pulumi-lab-vmSi ces commandes ne retournent rien, le nettoyage est correct et le scenario est rejouable.
Comment lire ce code
Section intitulée « Comment lire ce code »Le provider
Section intitulée « Le provider »Le bloc libvirt.Provider(...) indique a Pulumi quelle cible il doit
piloter. Ici, qemu:///system signifie que le provider travaille contre votre
instance systeme de libvirt.
Le reseau
Section intitulée « Le reseau »Le bloc libvirt.Network(...) decrit un reseau NAT. Vous y fixez :
- son nom ;
- son comportement d’autostart ;
- le domaine DNS local ;
- l’adressage IP et la plage DHCP.
Le disque clone
Section intitulée « Le disque clone »Le bloc libvirt.Volume(...) cree un disque de travail a partir d’une cloud
image Ubuntu deja presente sur l’hote. Cela permet de partir d’une base propre
sans retaper toute l’installation d’un systeme.
Le disque cloud-init
Section intitulée « Le disque cloud-init »Le bloc libvirt.CloudinitDisk(...) donne une identite initiale a la VM : nom
d’hote, mise a jour initiale et installation de qemu-guest-agent.
Le domaine libvirt
Section intitulée « Le domaine libvirt »Le bloc libvirt.Domain(...) represente la VM elle-meme. C’est lui qui assemble
les disques, le reseau, la memoire et les vCPU, puis demande a libvirt de
demarrer la machine.
Les exports
Section intitulée « Les exports »Les appels pulumi.export(...) rendent visibles des informations utiles a la
fin du deploiement. C’est une bonne habitude des le premier guide : vous voyez
ce que la stack a produit sans aller lire tout de suite le state brut.
Depannage
Section intitulée « Depannage »| Symptome | Cause probable | Solution |
|---|---|---|
preview echoue sur pulumi_libvirt | Le package n’a pas ete ajoute ou installe | Rejouez le guide de preparation locale puis relancez pulumi package add terraform-provider dmacvicar/libvirt |
permission denied ou erreur qemu:///system | Acces libvirt insuffisant | Corrigez l’environnement libvirt avant de poursuivre |
network already exists | Un ancien run a laisse le reseau en place | Verifiez avec virsh net-list --all, detruisez proprement puis relancez le workflow |
la VM ne passe pas en running | le domaine n’a pas pu booter correctement | Verifiez virsh list --all, virsh domstate pulumi-lab-vm et la presence de l’image Ubuntu de base |
destroy termine mais une ressource existe encore | La suppression n’a pas atteint l’etat reel | Relancez pulumi destroy --stack dev --yes, puis reverifiez virsh |
A retenir
Section intitulée « A retenir »- Pulumi suit ici une boucle claire :
preview -> up -> verification -> destroy. - Le premier vrai exemple de la section fait demarrer une VM KVM, pas seulement une ressource abstraite.
virshsert de preuve externe que le domaine et le reseau existent vraiment.- Un bon premier lab n’est pas seulement un
upreussi, c’est aussi undestroypropre.