L'essentiel
- La règle la plus mal comprise des rôles Ansible :
defaults/main.ymla la priorité la plus basse et sert aux variables que l'utilisateur doit pouvoir changer (ports, chemins, versions) ;vars/main.ymla une priorité élevée et sert aux constantes internes (noms de paquets par OS, chemins système). Aucun secret ne va dans l'un ou l'autre — c'est le rôle d'Ansible Vault. - Une collection est le format de distribution moderne : elle empaquette roles, modules, plugins et playbooks dans un artefact versionné en semver —
ansible.builtinen est une. Déclarez tout dansrequirements.ymlavec des bornes (amazon.aws: ">=7.0.0,<8.0.0") et installez dans le projet viaansible-galaxy collection install -r requirements.yml -p ./collectionspour figer les versions par dépôt. - AWX, Ansible Tower et Automation Controller sont trois états du même produit : AWX est l'upstream open source sans support, Tower était le produit commercial 3.x, Automation Controller est son nom actuel dans Ansible Automation Platform 2.x. L'API REST est quasi identique, ce qui permet de configurer AWX as code avec la collection
awx.awxouawxkit(awx job_templates launch --monitor 42). molecule testenchaîne le cycle complet create → prepare → converge → idempotency → verify → destroy : la phase idempotency rejoue le rôle et échoue s'il signale encore des changements, ce qui est le vrai test d'un rôle. Le multi-distribution passe parMOLECULE_DISTRO=rocky9 molecule testen local et une matrice rôle × distro en CI.- En CI/CD, le mot de passe Vault vit dans le coffre du runner, jamais dans le dépôt :
echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > .vault_pass, puis--vault-password-file .vault_passetrm -f .vault_passenafter_script. Ajoutezno_log: truesur toute tâche qui manipule un secret ; le vault-id étant inscrit dans l'en-tête$ANSIBLE_VAULT;1.2;AES256;prod, Ansible choisit seul la bonne clé.
Ce guide suppose une bonne connaissance d'Ansible (playbooks, inventaires, modules). Si vous débutez, commencez par le guide d'introduction Ansible. Pour ce tutoriel : Ansible Core 2.15+, Python 3.10+, Docker installé localement.
Pourquoi Ansible basique ne suffit pas à grande échelle
Ansible est séduisant dans sa forme la plus simple : un fichier hosts, un playbook YAML, et le tour est joué. Cette simplicité cache cependant des limitations structurelles qui deviennent douloureuses à mesure que l'infrastructure grandit.
Les symptômes sont toujours identiques. Des playbooks de 1500 lignes impossibles à maintenir. Des variables copiées-collées entre dix projets. Impossible de savoir quelle version d'un rôle est déployée en production. Aucun moyen de tester un changement avant de le pousser en prod. Des secrets en clair dans le dépôt git. Et zéro visibilité sur qui a lancé quoi et quand.
Ce guide couvre les solutions à chacun de ces problèmes :
- Roles avancés : structure professionnelle, variables, dépendances, tags
- Collections : packaging, versioning, Galaxy vs Automation Hub
- Inventaires dynamiques : AWS EC2, GCP, groupes construits
- AWX : interface web, RBAC, workflows graphiques, schedules
- CI/CD : lint, test Molecule, déploiement automatisé
- Sécurité : Vault avancé, secrets CI/CD, no_log
1. Roles avancés
Structure best practice d'un rôle
Un rôle bien structuré est un composant autonome, testable et réutilisable. La commande ansible-galaxy role init crée le squelette standard, que vous pouvez enrichir selon vos besoins.
# Créer un role avec la structure complète
ansible-galaxy role init mon_role
# Structure générée
mon_role/
├── README.md # Documentation obligatoire
├── meta/
│ └── main.yml # Métadonnées et dépendances
├── defaults/
│ └── main.yml # Variables par défaut (basse priorité)
├── vars/
│ └── main.yml # Variables internes (haute priorité)
├── tasks/
│ ├── main.yml # Point d'entrée des tâches
│ ├── install.yml # Tâches d'installation
│ ├── configure.yml # Tâches de configuration
│ └── debian.yml # Tâches spécifiques Debian
├── handlers/
│ └── main.yml # Handlers (restart service, reload config)
├── templates/
│ └── nginx.conf.j2 # Templates Jinja2
├── files/
│ └── logrotate.conf # Fichiers statiques
├── tests/
│ ├── inventory # Inventaire de test minimal
│ └── test.yml # Playbook de test basique
└── molecule/ # Tests Molecule (voir section 7)
└── default/
defaults/main.yml vs vars/main.yml
La distinction entre ces deux répertoires est fondamentale et souvent mal comprise. Elle détermine qui peut surcharger quelle variable et à quel niveau.
# defaults/main.yml — Variables configurables par l'utilisateur
# Priorité la plus BASSE → facilement surchargées
nginx_port: 80
nginx_ssl_port: 443
nginx_worker_processes: auto
nginx_user: www-data
nginx_log_path: /var/log/nginx
nginx_sites_available: /etc/nginx/sites-available
nginx_sites_enabled: /etc/nginx/sites-enabled
# Ces valeurs peuvent être surchargées depuis :
# - group_vars/, host_vars/
# - -e "nginx_port=8080" en ligne de commande
# - Le playbook appelant
# vars/main.yml — Constantes internes du role
# Priorité HAUTE → difficiles à surcharger (usage avancé uniquement)
_nginx_packages:
Debian:
- nginx
- nginx-extras
RedHat:
- nginx
- nginx-mod-http-geoip2
_nginx_service_name: nginx
_nginx_config_dir: /etc/nginx
_nginx_pid_file: /run/nginx.pid
# Règle : jamais de secrets ici, uniquement des constantes structurelles
# tasks/main.yml — Point d'entrée avec include conditionnel
---
- name: Inclure les variables selon l'OS
ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
tags: always
- name: Installation Nginx
ansible.builtin.include_tasks: install.yml
tags: [nginx, install]
- name: Configuration Nginx
ansible.builtin.include_tasks: configure.yml
tags: [nginx, configure]
- name: Activation et démarrage du service
ansible.builtin.service:
name: "{{ _nginx_service_name }}"
state: started
enabled: true
tags: [nginx, service]
meta/main.yml : dépendances et métadonnées
Le fichier meta/main.yml est crucial pour deux raisons : il documente le rôle pour Galaxy et définit ses dépendances qui seront résolues automatiquement.
# meta/main.yml
galaxy_info:
author: votre_pseudo
description: Role Nginx production-ready avec SSL et hardening
company: Mon Entreprise
license: MIT
min_ansible_version: "2.15"
platforms:
- name: Ubuntu
versions:
- "22.04"
- "24.04"
- name: Debian
versions:
- "12"
- name: EL
versions:
- "9"
galaxy_tags:
- nginx
- web
- proxy
- ssl
# Dépendances : ces roles seront exécutés AVANT celui-ci
dependencies:
- role: geerlingguy.certbot
vars:
certbot_email: [email protected]
when: nginx_ssl_enabled | bool
- role: common.firewall
vars:
firewall_allowed_tcp_ports:
- "{{ nginx_port }}"
- "{{ nginx_ssl_port }}"
handlers/main.yml
# handlers/main.yml
---
- name: Restart nginx
ansible.builtin.service:
name: "{{ _nginx_service_name }}"
state: restarted
listen: restart nginx
- name: Reload nginx
ansible.builtin.service:
name: "{{ _nginx_service_name }}"
state: reloaded
listen: reload nginx
- name: Test nginx config
ansible.builtin.command: nginx -t
changed_when: false
listen: test nginx config
include_role dynamique et when conditionnel
La directive include_role permet d'inclure dynamiquement des roles à l'intérieur d'un play, avec des conditions et des variables calculées à l'exécution — impossible avec roles: statique.
# playbook avec include_role dynamique
---
- name: Configuration des serveurs web
hosts: webservers
become: true
tasks:
- name: Installer Nginx ou Apache selon le groupe
ansible.builtin.include_role:
name: "{{ 'nginx' if 'nginx_servers' in group_names else 'apache2' }}"
vars:
web_port: 80
- name: Configurer SSL uniquement en production
ansible.builtin.include_role:
name: ssl_termination
when: ansible_env.ENVIRONMENT | default('dev') == 'prod'
- name: Appliquer les roles de monitoring pour chaque service
ansible.builtin.include_role:
name: "monitoring_{{ item }}"
loop:
- nginx
- php_fpm
- postgresql
when: monitoring_enabled | default(true)
Contenu Premium
Ce tutoriel avancé est réservé aux membres premium.
- Tous les tutoriels avancés
- Nouveaux contenus chaque semaine
- Suivi de progression
- Annulation à tout moment