Aller au contenu
English
English
medium

dsoxlab côté formateur : monter l'infrastructure des labs vm

Read this page in English

20 min de lecture

Un catalogue ne livre aucun Terraform ni aucun cloud-init : il déclare ses machines dans le bloc infra: de son meta.yml, et dsoxlab fait le reste avec les templates empaquetés dans l'outil. Cette leçon s'adresse à qui monte les machines dont les labs vm ont besoin, formateur d'une classe ou auteur qui teste son catalogue : la topologie, la clé SSH par clone, le choix du provider KVM, Incus ou Outscale, la virtualisation imbriquée, les snapshots et les machines qui survivent à leur state. Elle décrit la version 0.2.5, et se termine sur un usage dérivé : obtenir des machines jetables sans écrire le moindre exercice.

  • Déclarer une topologie de machines dans meta.yml, et ce que le contrat impose au nom du réseau.
  • Générer la clé SSH que provision exige, une fois par clone.
  • Choisir un provider, et savoir que chacun garde son propre state.
  • Activer la virtualisation imbriquée au bon endroit quand dsoxlab tourne dans une VM.
  • Comprendre les deux comptes posés sur chaque machine, les snapshots et les orphelins.
  • Détourner dsoxlab en fournisseur de VM jetables, sans lab.

Un catalogue fait de labs shell n'a besoin d'aucune infrastructure : l'exercice se joue sur la machine de l'apprenant, dsoxlab provision n'est jamais appelé, et le meta.yml ne porte aucun bloc infra:. C'est un catalogue conforme, pas un catalogue incomplet, et le catalogue Terraform du site en est l'exemple. Tout ce qui suit concerne les catalogues qui déclarent au moins un lab en runtime.type: vm.

Les modules Terraform des trois providers, kvm, incus et outscale, et les templates cloud-init des distributions empaquetées, AlmaLinux, Ubuntu et Debian, vivent dans dsoxlab. provision les recopie vers ~/.local/state/dsoxlab/<catalog-id>/, génère un fichier de variables depuis le meta.yml, et lance Terraform là. Le state n'atterrit jamais dans le dépôt de labs. Un catalogue déclare donc ceci, et rien de plus :

# meta.yml, bloc infra
infra:
provider: kvm # ou une liste de candidats
network: lab-linux # réseau libvirt de ce catalogue
cidr: 10.10.10.0/24
hosts:
- name: alma-1.lab
distro: alma10
ram_mb: 2048
vcpu: 2
disk_gb: 20
extra_disk_gb: 5 # second disque (/dev/vdb), pour les labs LVM ou RAID

Ne déclarez pas d'adresses IP : elles viennent des sorties Terraform, et l'inventaire en est dérivé. Chaque catalogue a intérêt à posséder son propre réseau libvirt, pour que deux catalogues ne se disputent jamais le même sous-réseau. Les distributions empaquetées sont alma10, alma9, ubuntu26, ubuntu24, ubuntu22, debian13 et debian12 ; ce nom pilote l'image et le cloud-init.

Une clé de infra.providers.kvm mérite d'être connue parce qu'une machine neuve en a besoin : storage_pool, le pool libvirt où sont créés les volumes, default par défaut. Sur une Ubuntu 24.04 fraîche, virsh pool-list --all est vide, et provision s'arrête sur un Pool Not Found brut. Deux sorties possibles : créer le pool default, et dsoxlab doctor affiche les commandes qui le font, ou pointer cette clé sur un pool que l'on possède déjà. On n'édite jamais le template empaqueté.

provision déploie <catalogue>/ssh/id_ed25519.pub sur chaque nœud, et refuse de démarrer sans la moitié privée à côté. Les deux viennent de dsoxlab instructor bootstrap, qui régénère la paire dès qu'une moitié manque, et vérifie au passage que Terraform et ansible-runner sont installés. Une clé publique commitée par l'auteur ne servirait à personne, sa moitié privée restant sur son disque, et les catalogues publiés ignorent tout le répertoire ssh/.

Fenêtre de terminal
dsoxlab instructor bootstrap # génère <catalogue>/ssh/id_ed25519 si absente

Chaque machine qui provisionne un catalogue joue donc cette commande une fois, apprenants compris : le mot « instructor » nomme la commande, pas son public. C'est l'oubli le plus fréquent après un catalog add, et start le rend visible en nommant l'étape qui a cassé.

Le plancher est libvirt 8.0, et il n'a pas été choisi sur un tableau de compatibilité : les trois versions ont provisionné pour de vrai, et la machine devait répondre en SSH, pas seulement voir Terraform ne pas protester. libvirt 8.0 dans une VM Ubuntu 22.04, 9.0 dans une VM Debian 12, 10.0 sur la machine de référence avec un vrai lab vm du catalogue Linux. Rien en dessous de 8.0 n'a été éprouvé, et c'est la seule raison pour laquelle un plancher subsiste.

ComposantPris en chargeComment cela a été établi
libvirt8.0 ou plus récentProvisionnement réel sur 8.0, 9.0 et 10.0, avec réponse SSH
Provider Terraform dmacvicar/libvirt~> 0.9La contrainte que déclare le template empaqueté ; aucun plancher connu dans cette plage

dsoxlab doctor contrôle ce plancher et refuse une version en dessous, en nommant la cause. Il affiche aussi la version du provider réellement épinglée pour ce catalogue, celle que terraform init a écrite dans l'état, et non celle que le template réclame : deux machines qui honorent ~> 0.9 peuvent faire tourner des versions différentes, et cette version figure dans dsoxlab support. Le template désigne explicitement le chargeur de firmware EFI de ses machines, ce qui évite qu'une version ancienne de libvirt le relise de travers et impose un plancher de provider plus élevé.

Un lab vm a besoin de /dev/kvm. Dans une machine virtuelle, cela suppose la virtualisation imbriquée, et l'imbrication est une caractéristique de l'hôte, pas de l'invité : rien d'installé dans l'invité ne la produit. Elle s'active à l'extérieur, invité éteint, et l'endroit dépend de l'hyperviseur qui héberge dsoxlab.

HôteOù elle s'active
KVM, libvirt ou Incus/sys/module/kvm_intel/parameters/nested, ou kvm_amd, doit valoir Y ; un options kvm_intel nested=1 dans /etc/modprobe.d/ le rend permanent
VMware Workstation ou FusionVirtualize Intel VT-x/EPT, dans les réglages processeur de la VM, machine éteinte
VirtualBoxL'imbrication VT-x/AMD-V, qui dépend du processeur, et qui est indisponible sur un Windows où Hyper-V ou WSL2 tient déjà l'hyperviseur
macOS sur Apple SiliconNi VirtualBox ni KVM n'y existent, et les images empaquetées sont en x86-64 : c'est une voie distincte, pas une case à cocher

dsoxlab doctor nomme ce cas au lieu de le laisser deviner. Quand /dev/kvm manque, il commence par regarder où il tourne, et dans une machine virtuelle il dit que l'imbrication n'est pas disponible en nommant l'hyperviseur détecté ; sur une machine physique, il renvoie au BIOS. Il proposait avant les deux d'un coup, ce qui envoyait la moitié de ses lecteurs visiter un BIOS que leur machine n'a pas. Pour le dimensionnement de l'invité, 4 vCPU et 8 Go sont mesurés, et la leçon Dimensionner sa machine pour les labs en donne le détail.

Six commandes couvrent tout le cycle de vie, et doctor range ses constats en deux tableaux dont le classement ne dépend que de trois faits, jamais du domaine : le catalogue a-t-il des labs vm, quel provider est actif, quels providers déclare-t-il. Un hyperviseur que ce catalogue n'utilise pas n'apparaît jamais en rouge.

Fenêtre de terminal
dsoxlab instructor bootstrap # la clé, une fois par clone
dsoxlab doctor # ce que ce catalogue exige, et ce qui manque
dsoxlab provision # terraform apply sur le provider courant
dsoxlab infra status # atteint-on chaque hôte déclaré, et sinon pourquoi
dsoxlab ssh alma-1.lab # une session interactive sur l'un d'eux
dsoxlab destroy # tout démonter

provision --host <fqdn> ne vise qu'une machine, et l'option est répétable ; sans elle, tout le plan est appliqué, les ressources partagées, réseau et images de base, étant gérées par le graphe de dépendances de Terraform. Le provider se résout par la première règle qui s'applique : la variable DSOXLAB_PROVIDER, puis le contexte posé par dsoxlab use --provider, puis un meta.yml qui n'en déclare qu'un. Plusieurs candidats sans choix explicite n'est pas une erreur : seules les commandes d'infrastructure refusent d'avancer, et elles le disent.

Fenêtre de terminal
dsoxlab use --provider kvm # durablement, pour ce catalogue
DSOXLAB_PROVIDER=incus dsoxlab provision # le temps d'une commande

Chaque provider garde son propre state Terraform, sous ~/.local/state/dsoxlab/<catalog-id>/terraform/<provider>/. Changer de provider ne détruit donc pas ce que l'autre tient, ce qui est commode, et aussi la façon dont on oublie une flotte allumée. dsoxlab infra status est l'habitude qui ne coûte rien.

cloud-init crée les deux mêmes comptes sur chaque nœud, durcis à l'identique : membre de wheel ou sudo, sudo NOPASSWD:ALL, clé SSH uniquement, sans mot de passe de connexion, ssh_pwauth: false. La séparation est délibérée, pour la traçabilité et la révocation.

CompteRôle
ansibleLe compte de service de l'automatisation. C'est lui que dsoxlab et les playbooks des labs utilisent pour se connecter, repris dans le ssh_config généré
studentLe compte humain, sur la machine que pilote l'apprenant

La conséquence pour les auteurs de labs est concrète : tout ce qui restreint la connexion, un AllowUsers dans sshd_config ou un remote_user, doit viser ansible, jamais student, sous peine de voir la commande dsoxlab suivante s'enfermer dehors.

snapshot_required: true dans le runtime d'un lab engage l'outil, il ne l'informe pas. run prend un point de reprise du disque avant de jouer setup.yaml, et échoue en code 2 s'il n'y arrive pas : un lab qui réclame un filet ne démarre pas sans lui. reset ramène la machine à ce point plutôt que de rejouer cleanup.yaml, puis rejoue setup.yaml. clean retire le point de reprise, et avec lui le fichier de recouvrement qu'il avait créé.

Sur le provider kvm, c'est un snapshot externe de disque, jamais un snapshot interne, parce que le template démarre ses machines en UEFI et que libvirt refuse les snapshots internes sur un firmware pflash. L'état mémoire n'est pas capturé : la reprise repart d'un disque cohérent, pas de la seconde d'avant, et un lab dont l'exercice repose sur un processus en cours doit le relancer. Aucun lab des catalogues publiés ne déclare aujourd'hui ce champ à true.

Un provision en échec peut laisser des domaines définis sur l'hyperviseur mais hors du state Terraform. Reprovisionner par-dessus produirait une flotte que personne ne suit : dsoxlab refuse plutôt, et deux codes de sortie disent de quel côté cela a lâché.

CodeSens
5provision a trouvé des domaines orphelins et s'est arrêté. Le message nomme la commande qui les retire
6destroy n'a pas pu les retirer. Quelque chose sur l'hyperviseur les tient encore

destroy retire aussi ces orphelins, après confirmation, --yes la saute, et sort en non-zéro s'il en reste un. Un destroy qui rapportait un succès en laissant les machines debout est le défaut que cela a remplacé. Deux autres codes complètent la famille : le 7, quand une autre commande dsoxlab tient déjà le verrou de ce catalogue, deux clones partageant le même verrou parce qu'ils partagent le même state, et le 8, quand provision a renoncé à attendre des hôtes qui ne répondaient pas dans la fenêtre de 180 secondes.

Le fragment SSH stable, et le cache qui ne l'est pas

Section intitulée « Le fragment SSH stable, et le cache qui ne l'est pas »

Le ssh_config généré sous ~/.cache/dsoxlab/<catalog-id>/ est un cache : il se régénère à la demande, mais il se purge aussi, et ce qui pointerait dessus, un Include ou un profil d'IDE, doit survivre à sa disparition. Le fragment écrit dans ~/.ssh/config.d/<catalog-id>.conf est celui qui est stable, à condition que ~/.ssh/config porte un Include de ce répertoire avant tout bloc Host. dsoxlab n'écrit pas cette ligne à votre place et le signale à chaque provision tant qu'elle manque : sans elle, le fragment est écrit et jamais lu, et ssh alma-1.lab continue d'échouer.

# ~/.ssh/config, en tête de fichier
Include ~/.ssh/config.d/*.conf

Se servir de dsoxlab comme fournisseur de VM jetables

Section intitulée « Se servir de dsoxlab comme fournisseur de VM jetables »

La couche d'infrastructure ne sait rien des labs : provision, destroy, ssh et infra status lisent le meta.yml et rien d'autre, ni base de progression, ni score, ni découverte. On peut donc se servir de dsoxlab pour rejouer un tutoriel sur une machine propre avant de le publier, reproduire un bogue sur trois distributions, ou obtenir un cluster qu'un conteneur ne peut pas remplacer parce que le test exige un vrai noyau, systemd ou un pare-feu. Un meta.yml à la racine d'un répertoire, et c'est tout :

repo:
id: ma-stack
title: "VM jetables"
infra:
provider: kvm
network: lab-stack
cidr: 10.10.90.0/24
hosts:
- name: db.lab
distro: debian13
ram_mb: 2048
- name: app.lab
distro: ubuntu24

Aucun répertoire labs/, aucun repo.category, aucun Terraform. doctor classe alors Terraform, l'hyperviseur et l'accès sortant en requis dès que infra.hosts n'est pas vide, validate-structure passe, et list-labs affiche « aucun lab trouvé », ce qui n'est pas une erreur. Deux limites sont assumées : les conteneurs ne passent pas par là, runtime.services se déclarant par lab, et les adresses dérivent de la position dans infra.hosts, si bien qu'un hôte s'ajoute toujours en fin de liste, libvirt refusant de mettre à jour un réseau existant.

Chaque ligne nomme un code ou un message, sa cause, et le geste que la CLI attend. Quand le cas ne figure pas ici, dsoxlab support --issue dépose un rapport de diagnostic anonymisé, version du provider épinglée comprise, dans le dépôt qui doit le recevoir.

SymptômeCauseSolution
provision refuse de démarrer, sans cléAucune paire sous ssh/ dans ce clonedsoxlab instructor bootstrap
provision sort en 5Des domaines orphelins existent sur l'hyperviseurJouer la ligne virsh undefine affichée, ou dsoxlab destroy, puis relancer
provision sort en 8Un hôte n'a pas répondu dans les 180 secondesdsoxlab infra status, puis plus de vCPU ou DSOXLAB_HOST_READY_TIMEOUT plus long
Code 7 sur une commande qui écritUne autre commande dsoxlab tient le verrou du catalogue, éventuellement depuis un autre cloneAttendre, ou fermer l'autre terminal, puis réessayer
ssh alma-1.lab échoue alors que dsoxlab ssh fonctionne~/.ssh/config ne porte pas l'Include du fragment stableAjouter la ligne Include avant tout bloc Host
doctor refuse la version de libvirtVersion inférieure à 8.0, jamais éprouvéeMettre libvirt à jour ; seul provision est concerné, un catalogue shell n'est pas bloqué
  • Un catalogue déclare ses machines dans infra: et rien d'autre ; les templates Terraform et cloud-init vivent dans l'outil.
  • Le nom du réseau kvm est borné à 9 caractères après lab-, et provision refuse avant de travailler quand il déborde.
  • La clé SSH se génère par clone avec instructor bootstrap, apprenants compris.
  • Chaque provider garde son propre state ; dsoxlab infra status est l'habitude qui évite d'oublier une flotte allumée.
  • Tout ce qui restreint la connexion vise le compte ansible, jamais student.
  • 5 et 6 disent de quel côté les orphelins ont lâché, 7 se réessaie, 8 demande du temps ou des vCPU.
  • Un meta.yml sans labs/ fait de dsoxlab un fournisseur de VM jetables, avec les mêmes quatre commandes.
  • Formation KVM : libvirt, les pools de stockage et les réseaux que le provider kvm de dsoxlab manipule pour vous.
  • Formation Incus : Le second provider local, et ce qu'une machine virtuelle Incus change par rapport à libvirt.
  • Formation Terraform : Ce que provision exécute réellement, pour lire la sortie d'un apply en échec.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn