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.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- 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
provisionexige, 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.
Seuls les labs vm demandent tout cela
Section intitulée « Seuls les labs vm demandent tout cela »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.
L'infrastructure est empaquetée dans l'outil
Section intitulée « L'infrastructure est empaquetée dans l'outil »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 infrainfra: 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 RAIDNe 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é.
La clé SSH est par clone, pas par catalogue
Section intitulée « La clé SSH est par clone, pas par catalogue »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/.
dsoxlab instructor bootstrap # génère <catalogue>/ssh/id_ed25519 si absenteChaque 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é.
Versions prises en charge
Section intitulée « Versions prises en charge »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.
| Composant | Pris en charge | Comment cela a été établi |
|---|---|---|
| libvirt | 8.0 ou plus récent | Provisionnement réel sur 8.0, 9.0 et 10.0, avec réponse SSH |
Provider Terraform dmacvicar/libvirt | ~> 0.9 | La 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é.
Faire tourner dsoxlab dans une machine virtuelle
Section intitulée « Faire tourner dsoxlab dans une machine virtuelle »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ôte | Où 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 Fusion | Virtualize Intel VT-x/EPT, dans les réglages processeur de la VM, machine éteinte |
| VirtualBox | L'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 Silicon | Ni 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.
Démarrer, et choisir un provider
Section intitulée « Démarrer, et choisir un provider »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.
dsoxlab instructor bootstrap # la clé, une fois par clonedsoxlab doctor # ce que ce catalogue exige, et ce qui manquedsoxlab provision # terraform apply sur le provider courantdsoxlab infra status # atteint-on chaque hôte déclaré, et sinon pourquoidsoxlab ssh alma-1.lab # une session interactive sur l'un d'euxdsoxlab destroy # tout démonterprovision --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.
dsoxlab use --provider kvm # durablement, pour ce catalogueDSOXLAB_PROVIDER=incus dsoxlab provision # le temps d'une commandeChaque 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.
Deux comptes, et ce que cela change pour les labs
Section intitulée « Deux comptes, et ce que cela change pour les labs »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.
| Compte | Rôle |
|---|---|
ansible | Le 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é |
student | Le 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.
Les snapshots
Section intitulée « Les snapshots »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.
Les machines qui survivent à leur state
Section intitulée « Les machines qui survivent à leur state »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é.
| Code | Sens |
|---|---|
5 | provision a trouvé des domaines orphelins et s'est arrêté. Le message nomme la commande qui les retire |
6 | destroy 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 fichierInclude ~/.ssh/config.d/*.confSe 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: ubuntu24Aucun 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.
Dépannage
Section intitulée « Dépannage »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ôme | Cause | Solution |
|---|---|---|
provision refuse de démarrer, sans clé | Aucune paire sous ssh/ dans ce clone | dsoxlab instructor bootstrap |
provision sort en 5 | Des domaines orphelins existent sur l'hyperviseur | Jouer la ligne virsh undefine affichée, ou dsoxlab destroy, puis relancer |
provision sort en 8 | Un hôte n'a pas répondu dans les 180 secondes | dsoxlab infra status, puis plus de vCPU ou DSOXLAB_HOST_READY_TIMEOUT plus long |
| Code 7 sur une commande qui écrit | Une autre commande dsoxlab tient le verrou du catalogue, éventuellement depuis un autre clone | Attendre, 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 stable | Ajouter la ligne Include avant tout bloc Host |
doctor refuse la version de libvirt | Version inférieure à 8.0, jamais éprouvée | Mettre libvirt à jour ; seul provision est concerné, un catalogue shell n'est pas bloqué |
À retenir
Section intitulée « À retenir »- 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
kvmest borné à 9 caractères aprèslab-, etprovisionrefuse 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 statusest l'habitude qui évite d'oublier une flotte allumée. - Tout ce qui restreint la connexion vise le compte
ansible, jamaisstudent. - 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.ymlsanslabs/fait de dsoxlab un fournisseur de VM jetables, avec les mêmes quatre commandes.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Formation KVM : libvirt, les pools de stockage et les réseaux que le provider
kvmde 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
provisionexécute réellement, pour lire la sortie d'unapplyen échec.