
Vous avez besoin d'un terrain de jeu réaliste pour apprendre Ansible : pas une seule VM jouet, mais une vraie topologie multi-hôtes que vous pouvez détruire et recréer à volonté. Ce guide monte en moins de 10 minutes la topologie pédagogique de référence du parcours RHCE, 1 control node + 3 managed nodes AlmaLinux 10 sur KVM/libvirt, avec cloud-init et baux DHCP statiques. Tous les guides suivants s'appuient sur cette infrastructure. L'approche est minimale et reproductible : virt-install + cloud-init, scriptés via un Makefile unique. Pas de Terraform pour démarrer, pas d'agent à installer.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Créer un réseau libvirt isolé avec NAT et baux DHCP statiques sans toucher à NetworkManager côté VMs ;
- Provisionner 4 VMs AlmaLinux 10 via
virt-installavec une image cloud mutualisée ; - Pré-configurer chaque VM via cloud-init : utilisateur
ansible, clé SSH, sudo NOPASSWD ; - Vérifier que les 4 VMs sont accessibles en SSH avec une seule commande Make ;
- Naviguer entre les 103 labs avec la CLI
dsoxlab(suivi de progression SQLite local, README rendus en terminal, suggestion du prochain lab) ; - Détruire proprement le lab pour le recréer rapidement.
Prérequis
Section intitulée « Prérequis »dsoxlab provision installe tout l'outillage logiciel nécessaire : libvirt, virt-install, cloud-utils, wget, pipx, ansible, ansible-lint, pytest, testinfra. Vous n'avez pas à installer ces paquets manuellement, le script scripts/bootstrap.sh détecte votre distribution (Fedora/RHEL/AlmaLinux/Ubuntu/Debian/Arch) et lance les bonnes commandes.
Côté matériel et système, vérifiez seulement :
| Élément | Comment vérifier |
|---|---|
| Au moins 8 Go de RAM libre | free -h |
Au moins 40 Go d'espace disque dans /var/lib/libvirt/images/ | df -h /var/lib/libvirt/images |
| Une paire de clés SSH (Ed25519 recommandé) | ls ~/.ssh/id_ed25519* (sinon dsoxlab provision la génère sous ssh/id_ed25519) |
| Distribution Linux avec KVM activé dans le BIOS | egrep -c '(vmx|svm)' /proc/cpuinfo retourne ≥ 1 |
La topologie du lab
Section intitulée « La topologie du lab »Le lab pédagogique reprend la topologie minimale qui couvre 80 % des objectifs RHCE EX294 sans sur-dimensionner :
| Hôte | IP | MAC (fixe) | RAM | vCPU | Disque | Rôle |
|---|---|---|---|---|---|---|
control-node.lab | 10.10.20.10 | 52:54:00:ab:00:10 | 2 GiB | 2 | 20 GiB | Poste Ansible |
web1.lab | 10.10.20.21 | 52:54:00:ab:00:21 | 1 GiB | 1 | 10 GiB | Web (groupe webservers) |
web2.lab | 10.10.20.22 | 52:54:00:ab:00:22 | 1 GiB | 1 | 10 GiB | Web (groupe webservers) |
db1.lab | 10.10.20.31 | 52:54:00:ab:00:31 | 1.5 GiB | 1 | 15 GiB | DB (groupe dbservers) |
Le réseau libvirt lab-ansible utilise le sous-réseau 10.10.20.0/24 avec :
- NAT sortant pour que les VMs accèdent à Internet (mise à jour des paquets, dnf install) ;
- Plage DHCP dynamique
10.10.20.100-200(pour d'éventuels hôtes additionnels) ; - 4 baux DHCP statiques mappés par MAC pour les 4 VMs du lab, IPs garanties stables.
Pourquoi des baux statiques côté hyperviseur
Section intitulée « Pourquoi des baux statiques côté hyperviseur »Les distributions récentes de la famille RedHat s'appuient sur NetworkManager, pas sur Netplan. Le bloc de configuration réseau de cloud-init n'est pas appliqué par NetworkManager dans la plupart des images officielles : les machines récupèrent alors une adresse au hasard, malgré la configuration écrite.
La parade fonctionne partout : fixer les adresses matérielles dans le réseau virtuel et déclarer des baux statiques qui les associent à une adresse et à un nom. Le gestionnaire réseau fait son travail habituel, mais l'adresse qu'il reçoit est imposée par l'hyperviseur. Aucune ligne de configuration réseau n'est alors nécessaire dans l'initialisation des machines.
Cloud-init minimal : la philosophie « Ansible se prépare lui-même »
Section intitulée « Cloud-init minimal : la philosophie « Ansible se prépare lui-même » »Le cloud-init des 4 VMs ne fait que trois choses :
- Pose le hostname et le FQDN (
web1.lab,db1.lab…) ; - Crée un utilisateur
ansibleavec la clé SSH publique enauthorized_keyset sudo NOPASSWD ; - Désactive le compte root et le SSH par mot de passe.
Aucun dnf install, aucun service activé, aucune config sysctl. Tout le reste est fait par Ansible lui-même dans la page suivante (Préparer les nœuds gérés). C'est volontaire : ça matérialise concrètement le principe « Ansible converge la cible vers son état désiré » et accélère le dsoxlab provision (pas de paquets à télécharger côté cloud-init).
Voici le template managed-node.user-data.tmpl (les __VARIABLES__ sont substituées par le script de provisioning) :
#cloud-confighostname: __HOSTNAME__fqdn: __HOSTNAME__.labmanage_etc_hosts: truepreserve_hostname: false
users: - name: ansible groups: [wheel] sudo: "ALL=(ALL) NOPASSWD:ALL" shell: /bin/bash lock_passwd: true ssh_authorized_keys: - __SSH_PUBKEY__
disable_root: truessh_pwauth: falseStructure du projet de lab
Section intitulée « Structure du projet de lab »Le lab pédagogique du site est hébergé dans le dépôt stephrobert/ansible-training, à cloner par exemple dans ~/Projets/ansible-training/. Voici l'arborescence racine et un aperçu des sections de labs (103 labs au total répartis sur 23 sections) :
Répertoireansible-training/
- Makefile
- ansible.cfg
- conftest.py (fixture pytest globale)
- requirements.txt
- requirements.yml
- meta.yml (source de vérité de la liste des labs)
Répertoirebin/
- dsoxlab (CLI suivi de progression)
Répertoireinventory/
- hosts.yml
Répertoireinfra/
Répertoirevirt-install/ (provision/destroy + cloud-init templates)
- …
Répertoireee/ (Execution Environment, image OCI)
- …
Répertoiredocs/ (doc interne du lab)
- …
Répertoirescripts/ (bootstrap, lint-all, snapshot, restore)
- …
Répertoiressh/ (clés SSH locales, gitignored)
- …
Répertoirecollected/ (cible des fetch, gitignored)
- …
Répertoirelabs/
Répertoirebootstrap/prepare-managed-nodes/
- …
Répertoiredecouvrir/ (4 labs : declaratif-vs-imperatif, installation-ansible, configuration-ansible, prise-en-main-cli)
- …
Répertoirepremiers-pas/ (2 labs : premier-playbook, ansible-vault)
- …
Répertoireecrire-code/ (28 labs : plays-et-tasks, handlers, tags, variables-base, jinja2-base, conditions-when, boucles-loop, block-rescue-always…)
- …
Répertoiremodules-fichiers/ (copy, file, blockinfile, fetch, archive-unarchive)
- …
Répertoiremodules-paquets/ (package, dnf-options)
- …
Répertoiremodules-services/ (systemd, cron)
- …
Répertoiremodules-utilisateurs/ (user, group, authorized-key, sudoers)
- …
Répertoiremodules-rhel/ (firewalld, selinux, sysctl, mount, lvm-storage)
- …
Répertoiremodules-reseau/ (get-url, uri)
- …
Répertoiremodules-diagnostic/ (stat, find, assert-fail, wait-for-pause)
- …
Répertoireinventaires/ (group-vars-host-vars, patterns-hotes, dynamique-kvm)
- …
Répertoireroles/ (creer-premier-role, variables-defaults-vars, handlers-meta, argument-specs, consommer-role, dependencies)
- …
Répertoiremolecule/ (introduction, installation-config, tdd-cycle, scenarios-multi-distro)
- …
Répertoiretests/ (testinfra, tox-multiversion, ansible-lint-production)
- …
Répertoireci/ (github-actions, gitlab)
- …
Répertoiregalaxy/ (ansible-galaxy-cli, installer-roles, auditer-role-existant, versionner-publier)
- …
Répertoirevault/ (introduction, chiffrer-fichier-variable, id-multiples, playbooks-mixtes, dans-roles, integration-hashicorp, integration-passbolt)
- …
Répertoireee/ (hello, inspection, builder-custom, ci-pipeline, debug)
- …
Répertoiretroubleshooting/ (verbosité, debugger, idempotence-perfs)
- …
Répertoirecollections/ (découvrir, requirements, creer-custom, ci-tests, migration-role)
- …
Répertoirepratiques/ (ansible-pull-gitops)
- …
Répertoirerhce/ (mock-ex294, examen blanc 4 h chrono)
- …
Chaque lab labs/<section>/<page>/ est autonome : README.md (tutoriel guidé), Makefile (cible clean pour reset), challenge/README.md (consigne du challenge final) + challenge/tests/test_*.py (validation pytest+testinfra). Le Makefile racine orchestre l'infrastructure, vous n'appelez jamais virt-install directement. La CLI dsoxlab suit votre progression dans une SQLite locale (~/.local/share/dsoxlab/progress.db).
Étapes de provisionnement
Section intitulée « Étapes de provisionnement »-
Cloner le dépôt et exécuter le bootstrap.
Le
dsoxlab provisioninstalle les paquets système requis (libvirt, virt-install, cloud-utils), vérifie les outils Ansible (ansible-core,ansible-lint,ansible-navigator,pytest), installe les collections Galaxy depuisrequirements.yml, et génère la paire de clés SSH du lab dansssh/id_ed25519:Fenêtre de terminal git clone https://github.com/stephrobert/ansible-training.git ~/Projets/ansible-trainingcd ~/Projets/ansible-trainingdsoxlab provisionLa clé du lab est séparée de votre clé personnelle pour pouvoir la jeter avec le lab. Elle est gitignorée, chaque utilisateur génère la sienne au premier
dsoxlab provision. -
Lancer le provisioning complet.
Une seule commande crée le réseau libvirt, télécharge l'image AlmaLinux (mise en cache), crée les 4 VMs et exécute le playbook de préparation :
Fenêtre de terminal dsoxlab provisionLe script affiche en couleurs ce qu'il fait :
[provision] Création du réseau libvirt 'lab-ansible' (10.10.20.0/24) avec baux DHCP statiques...[OK] Réseau 'lab-ansible' créé avec 4 baux DHCP statiques[OK] Image AlmaLinux 10 déjà présente : /var/lib/libvirt/images/AlmaLinux-10-GenericCloud-latest.x86_64.qcow2[provision] === control-node (10.10.20.10, MAC 52:54:00:ab:00:10, 2048 MiB RAM, 2 vCPU, 20 GiB) ===[provision] === web1 (10.10.20.21, MAC 52:54:00:ab:00:21, 1024 MiB RAM, 1 vCPU, 10 GiB) ===[provision] === web2 (10.10.20.22, MAC 52:54:00:ab:00:22, 1024 MiB RAM, 1 vCPU, 10 GiB) ===[provision] === db1 (10.10.20.31, MAC 52:54:00:ab:00:31, 1536 MiB RAM, 1 vCPU, 15 GiB) ===[provision] Attente SSH (~30s)...SSH OK sur les 4 hôtes[OK] Lab prêt : lance 'dsoxlab next' ou 'mise run test-all' -
Vérifier l'état des VMs.
Fenêtre de terminal virsh list --all | grep -E 'control-node|web|db'Sortie attendue :
49 control-node running50 web1 running51 web2 running52 db1 running -
Vérifier les baux DHCP attribués.
Fenêtre de terminal virsh net-dhcp-leases lab-ansibleLes 4 IPs doivent correspondre à la topologie attendue :
Expiry Time MAC address Protocol IP address Hostname------------------------------------------------------------------------------2026-04-25 15:08:51 52:54:00:ab:00:10 ipv4 10.10.20.10/24 control-node2026-04-25 15:06:39 52:54:00:ab:00:21 ipv4 10.10.20.21/24 web12026-04-25 15:09:16 52:54:00:ab:00:22 ipv4 10.10.20.22/24 web22026-04-25 15:06:43 52:54:00:ab:00:31 ipv4 10.10.20.31/24 db1 -
Tester la connectivité Ansible.
Fenêtre de terminal dsoxlab check <id-du-lab>-connVous devez voir 4
pong:db1.lab | SUCCESS => {"changed": false,"ping": "pong"}control-node.lab | SUCCESS => {"changed": false,"ping": "pong"}web2.lab | SUCCESS => {"changed": false,"ping": "pong"}web1.lab | SUCCESS => {"changed": false,"ping": "pong"}À ce point, le lab est fonctionnel bout en bout : Ansible voit les 4 hôtes, SSH passe, Python 3 répond. Vous pouvez attaquer les guides suivants.
Naviguer dans les labs avec dsoxlab
Section intitulée « Naviguer dans les labs avec dsoxlab »Avec 103 labs répartis sur 23 sections, naviguer manuellement devient vite pénible. Le repo embarque une CLI Python appelée dsoxlab (chemin : bin/dsoxlab) qui répond à trois besoins simultanés :
- Afficher un README de lab rendu en Markdown riche directement dans le terminal (titre, gras, blocs de code colorés, tableaux), sans ouvrir un navigateur ni un éditeur.
- Suggérer le prochain lab à attaquer en fonction de votre progression, pour éviter le syndrome « par où je commence ? ».
- Suivre objectivement les résultats : chaque exécution
pytestd'un challenge est inscrite automatiquement dans une SQLite locale, avec un dashboard pour voir où vous en êtes.
Comment fonctionne le suivi (sans configuration)
Section intitulée « Comment fonctionne le suivi (sans configuration) »Le suivi est automatique et silencieux : un plugin pytest interne (livré dans conftest.py du repo) intercepte chaque run lancé sur un dossier labs/<section>/<page>/challenge/tests/ et inscrit le résultat dans la base. Vous n'avez rien à activer : dès que vous lancez pytest sur un challenge, votre progression se met à jour.
Aucun service externe n'est sollicité, pas de réseau, pas d'authentification, pas de données qui sortent de votre poste. Le suivi est conforme RGPD par construction.
Stockage : une SQLite locale dans ~/.local/share/
Section intitulée « Stockage : une SQLite locale dans ~/.local/share/ »Les résultats sont stockés dans ~/.local/share/dsoxlab/progress.db (fichier SQLite). Cet emplacement suit la spec XDG Base Directory, propre, isolé, sauvegardable, gitignored.
Chaque ligne de la base correspond à un run pytest : timestamp, lab concerné, nombre de tests passed/failed, statut dérivé. La même base sert à plusieurs repos ansible-training clonés (utile si vous avez un fork). Pour utiliser une base alternative (sandbox, formation), exportez ANSIBLE_TRAINING_DB=/tmp/test.db avant pytest.
Installer dsoxlab dans votre PATH
Section intitulée « Installer dsoxlab dans votre PATH »Pour pouvoir taper dsoxlab depuis n'importe où sans préfixer bin/, créez un lien symbolique dans ~/.local/bin/ (qui doit être dans votre PATH) :
mkdir -p ~/.local/binln -sf "$(pwd)/bin/dsoxlab" ~/.local/bin/dsoxlab
# Vérificationwhich dsoxlab # doit afficher /home/<vous>/.local/bin/dsoxlabdsoxlab show # plus besoin de bin/dsoxlabSi ~/.local/bin n'est pas dans votre PATH, ajoutez à ~/.bashrc ou ~/.zshrc :
export PATH="$HOME/.local/bin:$PATH"Si vous gérez plusieurs forks d'ansible-training, utilisez plutôt un wrapper qui pointe vers le bon repo :
cat > ~/.local/bin/dsoxlab <<'EOF'#!/usr/bin/env bashexec "$HOME/Projets/ansible-training/bin/dsoxlab" "$@"EOFchmod +x ~/.local/bin/dsoxlabCommandes essentielles
Section intitulée « Commandes essentielles »| Commande | Effet |
|---|---|
dsoxlab | Tableau de bord par section avec icônes (✅ ⏳ ❌ · ⊘) |
dsoxlab next | Suggère le prochain lab à attaquer (selon progression) |
dsoxlab stats | Pourcentage de réussite par section |
dsoxlab show --section vault | Filtrer le dashboard sur une section |
dsoxlab show --status completed | Lister uniquement les labs validés |
dsoxlab lab decouvrir/installation-ansible | Afficher le README du tutoriel (rendu Markdown) |
dsoxlab lab vault/introduction --challenge | Afficher le challenge/README.md |
dsoxlab lab vault/introduction --both | Tutoriel + challenge à la suite |
dsoxlab reset --lab vault/introduction -y | Effacer la progression d'un lab pour le rejouer |
dsoxlab reset --all | Reset complet (avec confirmation) |
dsoxlab export -o progress.json | Exporter la progression en JSON portable |
L'option --width 100 force la largeur de rendu (par défaut 80, 0 = largeur du terminal). Le commande dsoxlab lab est l'usage le plus fréquent, elle remplace l'aller-retour vers GitHub ou un éditeur Markdown.
Statuts d'un lab
Section intitulée « Statuts d'un lab »Cinq statuts résument l'état d'un exercice, et ils se déduisent tous des exécutions de tests enregistrées : aucune exécution donne un exercice non commencé, une exécution entièrement passée le déclare validé, et tout ce qui se trouve entre les deux se lit dans les colonnes du tableau. Aucun de ces statuts ne se pose à la main.
| Icône | Statut | Signification |
|---|---|---|
| ✅ | completed | Au moins un run avec 100 % de tests passed |
| ⏳ | in_progress | Run(s) existant(s) avec une partie passed/failed |
| ❌ | failed | Tous les tests échouent |
| · | not_started | Aucun run inscrit en base |
| ⊘ | skipped | Run skippé (challenge non écrit, replay désactivé) |
Désactiver le suivi ponctuellement
Section intitulée « Désactiver le suivi ponctuellement »Si vous voulez lancer pytest sans inscrire le résultat (debug, expérimentation) :
PROGRESS_DISABLED=1 pytest -v labs/ecrire-code/block-rescue-always/challenge/tests/Workflow type sur la formation
Section intitulée « Workflow type sur la formation »dsoxlab next # 1. Que faire ensuite ?dsoxlab lab decouvrir/installation-ansible # 2. Lire le tutoriel# ... vous écrivez lab.yml et challenge/solution.yml ...pytest -v labs/decouvrir/installation-ansible/challenge/tests/ # 3. Validerdsoxlab show # 4. Voir l'avancement globalSi ~/.local/bin n'est pas dans votre PATH, appelez la CLI par son chemin complet (~/.local/bin/dsoxlab next) ou ajoutez ce répertoire au PATH de votre shell : les tâches du dépôt passent désormais par mise run, plus par make.
Détruire le lab proprement
Section intitulée « Détruire le lab proprement »Quand vous voulez repartir d'une base propre, pour rejouer le provisioning de zéro, par exemple, :
dsoxlab destroyLe script demande confirmation, arrête les 4 VMs, supprime leurs disques et démantèle le réseau libvirt. L'image cloud AlmaLinux est conservée dans /var/lib/libvirt/images/ pour ne pas la retélécharger au prochain dsoxlab provision.
Pour automatiser dans un script, utilisez :
dsoxlab destroy --forceSnapshot / restore avant un test risqué
Section intitulée « Snapshot / restore avant un test risqué »Avant de tester un playbook destructif (changement de SELinux, partitionnement, durcissement OS), prenez un snapshot des 4 VMs :
mise run snapshot # Crée un snapshot 'lab-checkpoint-<timestamp>' sur les 4 VMsmise run restore # Restaure les 4 VMs depuis le dernier snapshotC'est un filet de sécurité pédagogique, sur une vraie fleet, vous ne snapshotez pas avant chaque playbook.
Variantes pour les environnements sans KVM
Section intitulée « Variantes pour les environnements sans KVM »| Environnement | Alternative |
|---|---|
| Mac M1/M2 (pas de KVM nested) | UTM + virtio-fs, ou Multipass + Lima |
| Windows + WSL2 | KVM-on-WSL2 (KVM nested activé), ou Multipass natif |
| Pas d'accès root | Vagrant + VirtualBox (config Vagrantfile équivalente) |
| VMs cloud (Hetzner, OVH, AWS) | Provisionnement via Terraform (cf. cours Terraform du site) |
| Tout-en-un Docker | docker-compose avec 4 conteneurs rastasheep/ubuntu-sshd (limité : pas de systemd PID 1) |
Les commandes Ansible des guides suivants restent identiques, seule l'infrastructure d'hébergement change.
Dépannage
Section intitulée « Dépannage »Les pannes de provisionnement se répartissent en deux familles, et les distinguer fait gagner du temps : celles qui viennent du poste, virtualisation indisponible, ressources insuffisantes, droits manquants, et celles qui viennent des machines créées, adresse non attribuée ou initialisation incomplète. Les premières se corrigent avant de relancer, les secondes se diagnostiquent sur la console de la machine.
| Symptôme | Cause | Fix |
|---|---|---|
error: Failed to start network lab-ansible | Conflit de sous-réseau avec un autre réseau libvirt | Lister avec virsh net-list --all puis adapter la plage IP dans provision.sh |
Permission denied sur /var/lib/libvirt/images/ | Utilisateur pas dans le groupe libvirt | sudo usermod -aG libvirt $USER && newgrp libvirt |
VM bloquée à [OK] Started cloud-init.service | Image qcow2 corrompue | Supprimer /var/lib/libvirt/images/AlmaLinux-10-*.qcow2, rejouer dsoxlab provision |
ssh: connect to host 10.10.20.10 port 22: Connection refused | VM démarrée mais SSH pas encore prêt | Attendre 30 s supplémentaires, ou virsh console control-node pour suivre le boot |
Permission denied (publickey) sur le premier ping | Mauvais utilisateur SSH ou clé mal propagée | Vérifier ansible_user: ansible dans inventory/hosts.yml et ~/.ssh/authorized_keys côté VM |
| Connexion redirigée vers la mauvaise IP | ~/.ssh/config avec un bloc Host 10.* ProxyJump | Lancer ssh -vvv ansible@10.10.20.21 pour voir l'IP réelle, surcharger via ~/.ssh/config.d/lab-ansible.conf |
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Le lab utilise virt-install + cloud-init pour provisionner 4 VMs AlmaLinux 10 reproductibles.
- Les baux DHCP statiques côté libvirt garantissent des IPs stables sans toucher à NetworkManager, la parade qui marche sur RHEL 10.
- Le cloud-init reste minimal : utilisateur, clé SSH, sudo NOPASSWD. Le reste est fait par Ansible.
- Une seule commande
dsoxlab provisionmonte tout,dsoxlab destroydémantèle proprement. - L'image cloud AlmaLinux est mise en cache entre runs pour économiser le téléchargement.
- Si KVM n'est pas disponible, Vagrant, Multipass ou des VMs cloud prennent le relais sans changer les commandes Ansible.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Premier inventaire : déclarer les VMs qui viennent d'être provisionnées pour qu'Ansible les voie.
- Première connexion SSH : valider la chaîne SSH avant d'aller chercher un problème ailleurs.
- Commandes ad-hoc : la première utilisation concrète du lab, sans écrire une ligne de YAML.