Aller au contenu
Infrastructure as Code medium

Sous le capot : ce qu'un managed node Ansible doit fournir

12 min de lecture

Logo Ansible

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.

  • Identifier les 5 prérequis techniques d’un managed node Ansible et savoir les vérifier ;
  • Comprendre ce que make provision joue 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.yml ligne par ligne et comprendre chaque module utilisé ;
  • Vérifier l’idempotence avec un second ansible-playbook qui doit afficher changed=0.

Cette page suppose que :

  • Le lab KVM est provisionné (cf. Préparer le lab KVM) ;
  • Vous avez un inventaire fonctionnel sous inventory/hosts.yml avec un groupe parent rhce_lab regroupant webservers et dbservers ;
  • L’utilisateur ansible existe sur les managed nodes avec sudo NOPASSWD et la clé SSH publique en authorized_keys.
PrérequisPourquoiComment vérifier
Python 3 (3.6+)Tous les modules Ansible (sauf raw) sont du Python exécuté côté ciblessh ansible@web1.lab python3 --version
Accès SSH par clé (compte non-root)Modèle agentless, pas de mot de passe interactifssh -i ssh/id_ed25519 ansible@web1.lab doit passer
Sudo NOPASSWD sur ce comptebecome: true doit fonctionner sans saisie interactivessh ansible@web1.lab sudo -n true doit retourner 0
Firewall ouvert sur SSHLe moteur push s’appuie sur tcp/22nc -z web1.lab 22 doit réussir
Horloge synchroniséeLes modules de fichiers (mtime), les certificats, les logs corréléschronyc 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 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.

- name: Installer les paquets de base
ansible.builtin.dnf:
name: "{{ lab_packages }}"
state: present

Le module dnf est idempotent : il vérifie chaque paquet, n’installe que ceux qui manquent. Au second run, changed=0.

- 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: started

Le module systemd combine enable + start en une seule tâche. Sans enabled: true, le service redémarrerait pas après reboot.

- 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: enabled

permanent: 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.

- 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).

- 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/Paris

SELinux 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.

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 :

Fenêtre de terminal
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=0
web1.lab : ok=8 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2.lab : ok=8 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

changed=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.

  • 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 dnf est idempotent ; systemd combine enable + start ; firewalld avec permanent: true + immediate: true est le combo standard.
  • Sans Python 3 côté cible, on bootstrappe via le module raw (avec gather_facts: false).
  • changed=0 au second passage est la preuve d’idempotence — le critère de qualité d’un playbook bien écrit.

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é :

Fenêtre de terminal
cd ~/Projets/ansible-training/labs/bootstrap/prepare-managed-nodes/
cat README.md # tuto pas à pas
cat challenge/README.md # consigne du challenge final
pytest -v challenge/tests/ # lancer les tests testinfra

Si 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).

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn