Skip to content

stephrobert/ansible-training

Repository files navigation

Ansible Training — RHCE 2026

Bienvenue ! Ce dépôt est le lab pédagogique public de la formation Ansible RHCE EX294 (2026) du blog blog.stephane-robert.info.

Vous y trouverez :

  • Une infra reproductible (4 VMs AlmaLinux 10 sur KVM/libvirt) provisionnée en une commande, prête à recevoir vos playbooks.
  • 103 labs progressifs répartis en 23 sections (découvrir, premiers pas, écrire du code, modules incontournables, rôles, Molecule, CI/CD, Galaxy, Vault, Execution Environments, troubleshooting, collections, mock RHCE).
  • Des tests automatisés (pytest + testinfra) pour chaque challenge — vous savez immédiatement si votre solution est correcte.
  • Un Makefile par lab pour réinitialiser l'état des managed nodes entre deux essais.

🧭 Sommaire


🚀 Démarrage rapide

Si votre poste est déjà équipé (cf. Pré-requis) :

git clone https://github.com/stephrobert/ansible-training.git
cd ansible-training

# 1. Installer les outils (1ʳᵉ fois uniquement, ~3 min)
make bootstrap

# 2. Créer les 4 VMs + préparer les managed nodes (~5 min)
make provision

# 3. Rendre les hostnames du lab résolvables localement
make hosts-add        # → ssh web1.lab fonctionne, plus besoin d'IPs

# 4. Configurer SSH pour utiliser la clé du repo automatiquement
make ssh-config-add   # → ssh ansible@web1.lab fonctionne sans -i

# 5. Vérifier la connectivité Ansible (4 "pong" attendus)
make verify-conn

# 6. Voir le prochain lab à attaquer
dsoxlab next          # ou : make dsoxlab-next

À ce stade, vos 4 VMs tournent, leurs hostnames sont résolvables, et Ansible les voit. Vous pouvez commencer n'importe quel lab — pas besoin de les faire dans l'ordre.

Cycle de vie complet

Action Commande Quand ?
Installer les outils make bootstrap 1ʳᵉ fois uniquement
Créer les VMs make provision Au début, après chaque destroy
Résoudre les hostnames make hosts-add Après provision (ajout /etc/hosts)
Configurer SSH (clé du repo) make ssh-config-add Après provision (ssh ansible@web1.lab sans -i)
Tester la connectivité make verify-conn Vérification rapide à tout moment
Voir l'avancement dsoxlab show / dsoxlab next Pendant la formation
Snapshot (avant lab risqué) make snapshot Avant un lab destructif
Restaurer le snapshot make restore Après un crash de lab
Détruire les VMs make destroy Fin de formation ou reset complet
Nettoyer /etc/hosts make hosts-remove Après destroy (cleanup symétrique)
Nettoyer la config SSH make ssh-config-remove Après destroy (cleanup symétrique)

💡 Vous arrivez directement à un lab précis sans avoir fait les précédents ? C'est OK. La seule chose qui compte, c'est que les 4 VMs répondent au ping (make verify-conn). Chaque lab est autonome : son README.md explique ce qu'il faut savoir, et son Makefile clean nettoie l'état avant de rejouer.


🌐 Topologie du lab

Hôte IP Rôle Groupe(s)
control-node.lab 10.10.20.10 Poste Ansible (push SSH) control
web1.lab 10.10.20.21 Web 1 webservers, rhce_lab
web2.lab 10.10.20.22 Web 2 webservers, rhce_lab
db1.lab 10.10.20.31 Base de données dbservers, rhce_lab
  • Réseau libvirt : lab-ansible (10.10.20.0/24, NAT, baux DHCP statiques par MAC).
  • Auth : utilisateur ansible avec sudo NOPASSWD, clé SSH ssh/id_ed25519 (générée localement, jamais commitée).
  • Provisionning : cloud-init minimal (user + clé + sudo) ; le reste (firewalld, chrony, SELinux, /etc/hosts) est appliqué par Ansible lui-même via labs/bootstrap/prepare-managed-nodes/playbook.yml« Ansible se prépare lui-même ».

Pour la liste complète des hôtes, des groupes et la convention de ciblage (quand viser db1.lab vs webservers vs all), voir aussi meta.yml et la section Liste des labs.


📂 Structure du dépôt

ansible-training/
├── README.md                    # ce fichier
├── Makefile                     # bootstrap, provision, destroy, snapshot, restore, test-all
├── meta.yml                     # source de vérité de l'ordre des labs (23 sections, 103 labs)
├── ansible.cfg                  # config Ansible (forks, become, result_format=yaml)
├── conftest.py                  # fixture pytest qui rejoue solution.yml avant les tests
├── inventory/hosts.yml          # inventaire YAML : control + webservers + dbservers
├── infra/virt-install/          # provision/destroy + cloud-init templates
├── ee/                          # Execution Environment (image OCI)
├── scripts/                     # bootstrap, lint-all, snapshot-vms, restore-vms, hosts/ssh
├── bin/dsoxlab                  # CLI de suivi de progression
├── dsoxlab/                     # implémentation Python de la CLI
├── solution/                    # solutions formateur chiffrées via ansible-vault
├── ssh/                         # clés SSH générées localement (gitignored)
├── collected/                   # cible des fetch (gitignored)
└── labs/
    ├── bootstrap/prepare-managed-nodes/   # bootstrap système des managed nodes
    ├── decouvrir/                         # 4 labs (déclaratif/impératif, install, config, CLI)
    ├── premiers-pas/                      # 2 labs (premier playbook, vault basics)
    ├── ecrire-code/                       # 28 labs (plays, handlers, vars, Jinja, conditions, …)
    ├── modules-fichiers/                  # 5 labs (copy, file, blockinfile, fetch, archive)
    ├── modules-paquets/ modules-services/ # paquets, systemd, cron
    ├── modules-utilisateurs/ modules-rhel/ modules-reseau/ modules-diagnostic/
    ├── inventaires/ roles/ molecule/ tests/ ci/ galaxy/
    ├── vault/ ee/ troubleshooting/ collections/ pratiques/
    └── rhce/mock-ex294/                   # mock examen EX294 (12 tâches en 4h)

Chaque lab labs/<section>/<lab>/ est autonome. Sa structure type :

labs/<section>/<lab>/
├── README.md              # tutoriel guidé (objectifs, exercices, observations)
├── Makefile               # cible `clean` pour reset l'état des managed nodes
└── challenge/
    ├── README.md          # consigne du challenge final + squelette à compléter
    └── tests/
        └── test_*.py      # pytest+testinfra qui valide la solution écrite

⚠️ Important : les fichiers lab.yml (tutoriel) et challenge/solution.yml (challenge) ne sont pas livrés — c'est à l'apprenant de les écrire à partir des consignes. C'est le cœur de la pédagogie de ce dépôt.


🎓 Comment fonctionne un lab

Un lab pédagogique se déroule en 2 phases :

Phase 1 — Tutoriel guidé (README.md du lab)

Le README.md à la racine du lab contient un tuto pas-à-pas :

  • 🧠 Rappel — concept clé + lien vers la page du blog.
  • 🎯 Objectifs — ce que vous saurez faire à la fin.
  • 🔧 Préparation — vérifier que les VMs répondent, nettoyer un état antérieur.
  • 📚 Exercices — vous écrivez lab.yml à la racine du lab, étape par étape, en suivant les snippets fournis dans le README. Chaque exercice se termine par une section 🔍 Observation qui explique ce que vous devez voir.
  • 🤔 Questions de réflexion — pour ancrer la compréhension.

Phase 2 — Challenge final (challenge/README.md)

Une fois le tuto digéré, le challenge propose une variation autonome :

  • 🎯 Objectif — ce qu'il faut produire.
  • 🧩 Indices / Squelette — le squelette solution.yml avec des ??? à remplacer par vous.
  • 🚀 Lancement — la commande ansible-playbook ....
  • 🧪 Validation automatiséepytest qui vérifie objectivement votre solution.
  • 🧹 Resetmake clean pour rejouer à blanc.
  • 💡 Pour aller plus loin — concepts avancés + lint avec ansible-lint.

💡 Convention : lab.yml (à la racine du lab) = code du tuto. challenge/solution.yml = code du challenge. Les deux sont à écrire par l'apprenant.

💻 Configuration recommandée : terminal en deux colonnes

Pour un confort optimal, dédiez une colonne à la consigne et une autre aux commandes. Vous lisez le tutoriel à gauche, vous tapez à droite :

┌─────────────────────────────────┬─────────────────────────────────┐
│  📖  dsoxlab lab decouvrir/...  │  $ ansible all -m ping          │
│                                 │  $ vim lab.yml                  │
│  Lab 01 — Déclaratif vs ...     │  $ ansible-playbook lab.yml     │
│                                 │  ...                            │
│  ## 🎯 Objectifs                │                                 │
│  ...                            │                                 │
└─────────────────────────────────┴─────────────────────────────────┘
              consigne                       actions

Au choix selon votre environnement :

Outil Comment splitter
tmux (universel, recommandé) tmux new-session \; split-window -h puis Ctrl+b ←/→ pour naviguer
VS Code terminal Ctrl+Shift+5 (split à droite)
Terminator (GTK) Ctrl+Shift+E (split vertical)
Tilix Ctrl+Alt+R (split à droite)
Konsole Ctrl+(
Windows Terminal Alt+Shift+D
iTerm2 (macOS) Cmd+D

Recette tmux prête à coller :

tmux new-session -d -s lab \; \
    send-keys 'dsoxlab lab decouvrir/declaratif-vs-imperatif' C-m \; \
    split-window -h \; \
    attach
# Ctrl+b ← / Ctrl+b → pour passer d'une colonne à l'autre
# Ctrl+b z pour zoomer/dézoomer une colonne
# Ctrl+b d pour détacher (la session reste vivante)
# tmux attach -t lab pour reprendre plus tard

💡 Astuce : laissez tourner dsoxlab lab xxx à gauche sans pager (--no-pager) si vous préférez relire le tutoriel en scrollant la sortie du terminal plutôt qu'en restant dans less.


🧪 Lancer les tests pytest

Chaque challenge a une suite de tests pytest + testinfra qui valide la solution sur les managed nodes.

# Un seul lab
pytest -v labs/ecrire-code/block-rescue-always/challenge/tests/

# Toute une section
pytest -v labs/vault/

# Tous les labs (long — selon le nombre de challenges écrits)
pytest -v labs/

La fixture _apply_lab_state (autouse)

Le conftest.py racine contient une fixture qui rejoue automatiquement votre solution.yml avant les tests. Cela garantit :

  • Que vos tests passent indépendamment de l'ordre dans lequel les labs ont été joués manuellement.
  • Que l'état des managed nodes correspond bien à ce que la solution attend.

3 cas pris en compte :

Type de lab Comportement de la fixture
Lab démo (Makefile + playbook.yml racine) make setup + ansible-playbook playbook.yml
Lab pédagogique avec challenge/solution.yml écrit ansible-playbook challenge/solution.yml (+ _EXTRA_ARGS éventuels)
Lab pédagogique sans solution pytest.skip avec message clair (« écrivez d'abord solution.yml »)

Désactiver la fixture

Si vous voulez tester à la main sans qu'Ansible ne rejoue :

LAB_NO_REPLAY=1 pytest -v labs/ecrire-code/block-rescue-always/challenge/tests/

🧹 Reset d'un lab

Chaque lab a un Makefile avec une cible clean qui supprime ce qu'il a posé sur les managed nodes. Indispensable pour rejouer un scénario à blanc.

make -C labs/ecrire-code/block-rescue-always clean

💡 Snapshot global : si vous voulez revenir à un état VMs neuves : make snapshot (avant un lab risqué) puis make restore (après) — utile pour explorer un lab destructif.


📊 Suivi de progression

Le repo embarque une CLI Python (bin/dsoxlab) qui inscrit chaque run pytest dans une SQLite locale (~/.local/share/dsoxlab/progress.db) et affiche un dashboard de votre avancement par section/lab.

Le suivi est automatique : dès que vous lancez pytest sur un lab (pytest labs/<section>/<lab>/challenge/tests/), un plugin pytest interne inscrit le résultat dans la base.

Installer la CLI dans le PATH (recommandé)

Pour pouvoir taper dsoxlab ou lab depuis n'importe où sans préfixer bin/, créez un lien symbolique dans un dossier de votre PATH :

# Option A — lien personnel (~/.local/bin doit être dans votre PATH)
mkdir -p ~/.local/bin
ln -sf "$(pwd)/bin/dsoxlab" ~/.local/bin/dsoxlab

# Option B — wrapper qui pointe vers ce repo (utile si plusieurs repos)
cat > ~/.local/bin/dsoxlab <<'EOF'
#!/usr/bin/env bash
exec /home/bob/Projets/ansible-training/bin/dsoxlab "$@"
EOF
chmod +x ~/.local/bin/dsoxlab

Vérification :

which dsoxlab     # /home/<vous>/.local/bin/dsoxlab
dsoxlab show      # plus besoin de bin/dsoxlab
dsoxlab lab decouvrir/installation-ansible

💡 Si ~/.local/bin n'est pas dans votre PATH, ajoutez à ~/.bashrc ou ~/.zshrc : export PATH="$HOME/.local/bin:$PATH".

Commandes principales

dsoxlab                                          # tableau de bord par section
dsoxlab next                                     # suggère le prochain lab à attaquer
dsoxlab stats                                    # % réussite par section
dsoxlab show --section vault                     # filtrer une section
dsoxlab show --status completed                  # filtrer par statut
dsoxlab lab decouvrir/installation-ansible       # 📖 README rendu Markdown riche (80 col par défaut)
dsoxlab lab vault/introduction --challenge       # 🎯 challenge/README.md rendu
dsoxlab lab vault/introduction --both            # tutoriel + challenge à la suite
dsoxlab lab vault/introduction --width 100       # forcer 100 colonnes (défaut 80, 0 = terminal)
dsoxlab reset --lab vault/introduction -y        # rejouer un lab à blanc
dsoxlab reset --all                              # reset complet (avec confirmation)
dsoxlab export -o my-progress.json                # export JSON pour formateur/agrégation

Cibles Make équivalentes (pas besoin du PATH) :

make dsoxlab / dsoxlab-next / dsoxlab-stats
make lab LAB=decouvrir/installation-ansible
make lab LAB=vault/introduction CHALLENGE=1
make lab LAB=vault/introduction BOTH=1

Statuts d'un lab

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
skipped Run skippé (challenge non écrit, replay désactivé)

Désactiver le suivi

DSOXLAB_DISABLED=1 pytest …                     # un run sans inscription
DSOXLAB_DB=/tmp/test.db pytest …                # DB alternative (sandbox)

Stockage

  • Local par défaut : ~/.local/share/dsoxlab/progress.db (gitignored).
  • Multi-postes : bin/dsoxlab export produit un JSON portable pour archiver sa progression ou la fournir à un formateur.
  • Aucun service externe : pas de réseau, pas d'auth, pas de RGPD.

🔍 Linter avec ansible-lint

ansible-lint détecte les anti-patterns dans vos playbooks (FQCN manquant, modules dépréciés, modes en chaîne, idempotence cassée, etc.). Lancez-le systématiquement avant de commiter ou de lancer pytest :

# Lint ciblé sur votre solution d'un lab
ansible-lint labs/ecrire-code/block-rescue-always/challenge/solution.yml

# Profil production (le plus strict)
ansible-lint --profile production labs/ecrire-code/block-rescue-always/challenge/solution.yml

# Lint global du dépôt
make lint-all

Si ansible-lint retourne sans erreur (Passed: 0 failure(s), 0 warning(s)), votre code est conforme aux bonnes pratiques. Vous pouvez aussi utiliser yamllint pour la pure syntaxe YAML :

yamllint labs/ecrire-code/block-rescue-always/challenge/solution.yml

📚 Liste des labs

103 labs répartis en 23 sections (source de vérité : meta.yml).

Bootstrap

Préparation système des managed nodes (joué auto par make provision).

Découvrir Ansible

Premiers contacts : déclaratif vs impératif, installation, CLI, configuration.

Premiers pas

Premier playbook, premiers secrets vault.

Écrire du code Ansible

Structure d'un play, contrôle d'exécution, variables, Jinja2, conditions, boucles, gestion d'erreurs.

Modules fichiers

Manipulation de fichiers : copy, file, blockinfile, fetch, archive.

Modules paquets

Gestion paquets agnostique (package) et options dnf spécifiques.

Modules services

Gestion services systemd et tâches planifiées cron.

Modules utilisateurs

Gestion users, groups, clés SSH, sudoers.

Modules RHEL

Spécificités RHEL : firewalld, SELinux, sysctl, mount, LVM.

Modules réseau

Téléchargement et appels HTTP : get_url, uri.

Modules diagnostic

Inspection et synchronisation : stat, find, assert/fail, wait_for/pause.

Inventaires

group_vars/host_vars, patterns d'hôtes, inventaire dynamique libvirt.

Rôles

Anatomie d'un rôle, variables, handlers, argument_specs, consommation, dépendances.

Tests Molecule

Cycle TDD avec Molecule, scénarios multi-distro.

Tests Python & lint

testinfra, tox multi-version, ansible-lint profil production.

CI/CD

Pipelines GitHub Actions et GitLab CI pour rôles et collections.

Galaxy & publication

ansible-galaxy CLI, requirements.yml, audit de rôles tiers, versioning et publication.

Ansible Vault

Vault complet : encrypt_string, vault-id multiples, mixtes, dans rôles, intégration HashiCorp/Passbolt.

Execution Environments

ansible-navigator, ansible-builder, EE custom, pipeline CI, debug.

Troubleshooting

Verbosité, debugger interactif, idempotence et performance.

Collections

Découverte, requirements, création, CI tests, migration depuis un rôle.

Pratiques avancées

ansible-pull mode GitOps.

Examen RHCE EX294

Mock examen complet 4h avec 12 tâches.


🔧 Pré-requis poste de travail

Système supporté

  • Linux (Fedora, Ubuntu/Debian, Arch, AlmaLinux/Rocky/RHEL).
  • macOS : possible mais non testé pour la partie libvirt (utilisez WSL2 ou une VM Linux).
  • Windows : non supporté directement (utilisez WSL2 + libvirt sous Linux).

Outils requis

Outil Rôle Installation rapide
pipx Gestionnaire d'apps Python isolées sudo dnf install pipx (Fedora) / sudo apt install pipx (Debian)
ansible Le moteur pipx install --include-deps ansible
ansible-lint Linter pipx install ansible-lint
pytest + testinfra Tests d'infra pipx install pytest && pipx inject pytest pytest-testinfra
libvirt + qemu-kvm Virtualisation make bootstrap (couvre tout le reste)

💡 Tout-en-un : make bootstrap à la racine du repo installe tous les outils ci-dessus. C'est l'option recommandée.

Vérifier l'installation

ansible --version          # core 2.18+
ansible-lint --version     # 25+
pytest --version           # 8+
virsh list --all           # libvirt accessible

Si une commande manque, relancez make bootstrap ou installez-la manuellement. La page MDX installation-ansible détaille les 5 méthodes d'installation possibles.


🆘 Dépannage

make verify-conn échoue (UNREACHABLE)

# Reset complet du lab
make destroy
make provision
make verify-conn

Un lab marque tous ses tests pytest en skipped

C'est attendu : la fixture _apply_lab_state skippe avec un message explicite tant que vous n'avez pas écrit votre challenge/solution.yml.

SKIPPED [...] Aucun challenge/solution.yml ni solution.sh trouvé.
L'apprenant doit l'écrire en suivant challenge/README.md, puis relancer pytest.

Un lab échoue parce qu'un lab précédent a polluéle système

Lancez la cible clean du lab cible :

make -C labs/<section>/<lab>/ clean

Pour un reset radical, relancez tout le bootstrap :

make destroy && make provision

ansible-lint se plaint de FQCN manquant

Préférez toujours ansible.builtin.copy à copy, ansible.posix.firewalld à firewalld, etc. Le FQCN est obligatoire pour la RHCE 2026 et règle ~80 % des warnings d'ansible-lint.

Un challenge ne se déclenche pas avec --extra-vars ou --tags

Le conftest.py racine définit deux mappings (_PRE_CLEANUPS et _EXTRA_ARGS) pour gérer les labs qui demandent un setup particulier (ex : --tags configuration, --extra-vars service_name=…). Si un test échoue parce qu'une variable manque ou qu'un fichier annexe pollue l'état, vérifiez l'entrée correspondante dans conftest.py.


🤝 Contribuer

Les retours, corrections et suggestions sont les bienvenus !

  1. Créez une issue pour signaler un bug ou proposer une amélioration.
  2. Forkez le dépôt et ouvrez une pull request.

Voir contributing.md pour les bonnes pratiques.


☕ Soutenir le projet

Si ce dépôt vous est utile et que vous voulez soutenir l'auteur :

Ko-fi


© Licence

Creative Commons BY-SA

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors