
Sur le lab du site, make provision s’occupe de tout — vous n’avez rien à faire. Cette page n’est pas un how-to où vous lancez quoi que ce soit : c’est l’ouverture du capot. On regarde ce qui se passe quand make provision enchaîne virt-install + cloud-init + le playbook de préparation, on apprend les 5 prérequis techniques qu’un managed node doit fournir à Ansible, et on décortique ligne par ligne le playbook qui les pose. Objectif : sortir de cette page capable de reproduire la préparation sur n’importe quelle fleet existante, hors du lab.
C’est aussi le moment où vous découvrez le principe « Ansible se prépare lui-même » : cloud-init pose le strict minimum (utilisateur + clé SSH), et Ansible converge le reste via un playbook idempotent. Cette approche reste valable partout : à condition d’avoir SSH + Python 3, un seul ansible-playbook aligne tout.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Identifier les 5 prérequis techniques d’un managed node Ansible et savoir les vérifier ;
- Comprendre ce que
make provisionjoue derrière le rideau, et donc ce que vous devrez faire à la main sur une fleet existante ; - Bootstrapper un host sans Python via le module
raw(cas RHEL minimal, Alpine, équipements réseau) ; - Lire le playbook
bootstrap/prepare-managed-nodes/playbook.ymlligne par ligne et comprendre chaque module utilisé ; - Vérifier l’idempotence avec un second
ansible-playbookqui doit afficherchanged=0.
Prérequis
Section intitulée « Prérequis »Cette page suppose que :
- Le lab KVM est provisionné (cf. Préparer le lab KVM) ;
- Vous avez un inventaire fonctionnel sous
inventory/hosts.ymlavec un groupe parentrhce_labregroupantwebserversetdbservers; - L’utilisateur
ansibleexiste sur les managed nodes avec sudo NOPASSWD et la clé SSH publique enauthorized_keys.
Les 5 prérequis d’un managed node
Section intitulée « Les 5 prérequis d’un managed node »| Prérequis | Pourquoi | Comment vérifier |
|---|---|---|
| Python 3 (3.6+) | Tous les modules Ansible (sauf raw) sont du Python exécuté côté cible | ssh ansible@web1.lab python3 --version |
| Accès SSH par clé (compte non-root) | Modèle agentless, pas de mot de passe interactif | ssh -i ssh/id_ed25519 ansible@web1.lab doit passer |
| Sudo NOPASSWD sur ce compte | become: true doit fonctionner sans saisie interactive | ssh ansible@web1.lab sudo -n true doit retourner 0 |
| Firewall ouvert sur SSH | Le moteur push s’appuie sur tcp/22 | nc -z web1.lab 22 doit réussir |
| Horloge synchronisée | Les modules de fichiers (mtime), les certificats, les logs corrélés | chronyc tracking côté managed node |
Quatre des cinq sont déjà couverts par le cloud-init du lab. Le firewall, la synchro NTP, SELinux en mode enforcing, et l’inscription dans /etc/hosts sont posés par le playbook de préparation.
Le playbook de préparation, ligne par ligne
Section intitulée « Le playbook de préparation, ligne par ligne »Le lab fournit labs/bootstrap/prepare-managed-nodes/playbook.yml. Voici la structure complète, commentée.
---- name: Préparation des managed nodes (chrony, paquets utiles, /etc/hosts) hosts: rhce_lab # cible le groupe parent (webservers + dbservers) gather_facts: true # récupère ansible_distribution, ansible_default_ipv4... become: true # toutes les tâches s'exécutent en root via sudo
vars: lab_packages: - python3-libselinux # indispensable quand SELinux est enforcing - firewalld # firewall standard RHEL (objectif RHCE) - python3-firewall # binding Python pour ansible.posix.firewalld - chrony # synchro horaire entre managed nodes - bash-completion - vim-enhanced - tar - rsync
lab_hosts_entries: - { ip: 10.10.20.10, name: control-node } - { ip: 10.10.20.21, name: web1 } - { ip: 10.10.20.22, name: web2 } - { ip: 10.10.20.31, name: db1 }Le bloc vars regroupe toutes les valeurs du playbook au même endroit — ajouter un paquet ou un hôte ne demande qu’une ligne.
Tâche 1 — Installer les paquets de base
Section intitulée « Tâche 1 — Installer les paquets de base » - name: Installer les paquets de base ansible.builtin.dnf: name: "{{ lab_packages }}" state: presentLe module dnf est idempotent : il vérifie chaque paquet, n’installe que ceux qui manquent. Au second run, changed=0.
Tâches 2-3 — Activer chrony et firewalld
Section intitulée « Tâches 2-3 — Activer chrony et firewalld » - name: Activer et démarrer chronyd ansible.builtin.systemd: name: chronyd enabled: true # démarrage au boot state: started # démarré maintenant
- name: Activer et démarrer firewalld ansible.builtin.systemd: name: firewalld enabled: true state: startedLe module systemd combine enable + start en une seule tâche. Sans enabled: true, le service redémarrerait pas après reboot.
Tâche 4 — Ouvrir SSH dans firewalld
Section intitulée « Tâche 4 — Ouvrir SSH dans firewalld » - name: Autoriser le service SSH dans firewalld (zone publique par défaut) ansible.posix.firewalld: service: ssh permanent: true # écrit dans /etc/firewalld/zones/public.xml immediate: true # applique aussi à la session runtime en cours state: enabledpermanent: true + immediate: true est le combo standard : la règle survit au reboot et s’applique tout de suite. Sans immediate: true, il faudrait recharger firewalld manuellement.
Tâche 5 — Inscrire les hôtes dans /etc/hosts
Section intitulée « Tâche 5 — Inscrire les hôtes dans /etc/hosts » - name: Inscrire chaque hôte du lab dans /etc/hosts ansible.builtin.lineinfile: path: /etc/hosts line: "{{ item.ip }} {{ item.name }}.lab {{ item.name }}" regexp: "^{{ item.ip | regex_escape }}\\s" state: present owner: root group: root mode: "0644" loop: "{{ lab_hosts_entries }}" loop_control: label: "{{ item.name }}"lineinfile ajoute la ligne si elle n’existe pas, ou la remplace si une ligne match regexp: (utile quand les IPs changent). Le loop_control.label: rend la sortie plus lisible (affiche web1 au lieu du dict complet).
Tâches 6-7 — SELinux et timezone
Section intitulée « Tâches 6-7 — SELinux et timezone » - name: Vérifier que SELinux est en mode enforcing ansible.posix.selinux: state: enforcing policy: targeted
- name: Régler la timezone du lab (Europe/Paris) community.general.timezone: name: Europe/ParisSELinux enforcing est attendu en production RHEL et sur l’examen RHCE. Le module détecte l’état courant et n’agit que si nécessaire.
Rejouer le playbook pour observer (optionnel)
Section intitulée « Rejouer le playbook pour observer (optionnel) »make provision a déjà joué ce playbook une fois pour vous. Le rejouer manuellement n’est pas obligatoire — c’est un exercice utile pour observer l’idempotence en action et se familiariser avec la sortie d’ansible-playbook avant de basculer sur les guides suivants.
Depuis la racine du repo ansible-training :
ansible-playbook labs/bootstrap/prepare-managed-nodes/playbook.yml(L’option -i inventory/hosts.yml est implicite : ansible.cfg à la racine du repo pointe déjà sur ce fichier.)
Au second passage sur un lab déjà préparé, vous devez voir le PLAY RECAP suivant :
PLAY RECAP *********************************************************************db1.lab : ok=8 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0web1.lab : ok=8 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0web2.lab : ok=8 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0changed=0 est la preuve d’idempotence : tous les modules ont vérifié l’état réel, l’ont trouvé conforme à l’état désiré, et n’ont rien modifié. Au premier run sur un lab fraîchement provisionné, vous verrez plutôt changed=6 ou changed=7 car les paquets, services, règles firewall et lignes /etc/hosts doivent être ajoutés.
Cas particulier — Bootstrap d’un host sans Python 3
Section intitulée « Cas particulier — Bootstrap d’un host sans Python 3 »Sur certaines images minimales (RHEL UBI, Alpine, équipements réseau), Python 3 n’est pas installé. Vous ne pouvez pas faire un ansible all -m ping directement — vous devez passer par le module raw qui exécute du shell brut via SSH, sans Python côté cible.
---- name: Bootstrap Python 3 sur les managed nodes minimaux hosts: rhce_lab gather_facts: false # désactivé, sinon Ansible essaie d'utiliser setup et plante become: true
tasks: - name: Vérifier la présence de Python 3 ansible.builtin.raw: which python3 || dnf install -y python3 register: python_check changed_when: "'Installed' in python_check.stdout"Une fois Python 3 installé via raw, vous bascule sur les modules normaux (dnf, systemd, etc.) dans les plays suivants. Le gather_facts: false est obligatoire dans le play de bootstrap — sinon Ansible essaie d’exécuter le module setup qui demande Python.
À retenir
Section intitulée « À retenir »- Un managed node doit fournir : Python 3, SSH par clé, sudo NOPASSWD, firewall ouvert, horloge synchronisée.
- Le cloud-init du lab ne fait que poser l’utilisateur et la clé SSH ; Ansible converge le reste via le playbook de préparation.
- Le module
dnfest idempotent ;systemdcombine enable + start ;firewalldavecpermanent: true+immediate: trueest le combo standard. - Sans Python 3 côté cible, on bootstrappe via le module
raw(avecgather_facts: false). changed=0au second passage est la preuve d’idempotence — le critère de qualité d’un playbook bien écrit.
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/bootstrap/prepare-managed-nodes/ dans
stephrobert/ansible-training. Il contient
un README.md guidé, un Makefile (make verify lance les tests), et un
challenge final auto-évalué : préparer les 3 managed nodes (chrony, firewalld, SELinux, /etc/hosts) via un playbook idempotent.
Une fois le lab provisionné :
cd ~/Projets/ansible-training/labs/bootstrap/prepare-managed-nodes/
cat README.md # tuto pas à pascat challenge/README.md # consigne du challenge finalpytest -v challenge/tests/ # lancer les tests testinfraSi les tests passent, vous maîtrisez les concepts couverts dans ce guide. En
cas de blocage, docs/troubleshooting.md
à la racine du repo couvre les pièges fréquents (rate-limit SSH, clé absente,
collection manquante).