Sommaire
Tester son code Ansible : une pratique incontournable
La gestion de configuration est devenue un élément central pour maintenir des environnements complexes de manière répétable et fiable. Ansible, avec sa simplicité et sa flexibilité, est souvent le choix privilégié. Mais, malgré sa popularité, beaucoup de playbooks et de rôles sont encore écrits sans tests, ce qui peut rapidement coûter cher.
Imaginez la situation : vous avez développé un rôle pour installer Nginx. Tout fonctionne parfaitement sur votre poste local… mais en staging, ou pire en production, l’installation échoue à cause d’un handler oublié ou d’une variable mal configurée. Ce genre de problème peut provoquer des interruptions de service, des corrections d’urgence stressantes et des déploiements retardés.
C’est là qu’intervient l’importance de tester son code Ansible. Les bénéfices sont multiples :
- Fiabilité : détecter les erreurs avant qu’elles n’atteignent vos environnements critiques.
- Maintenabilité : des rôles testés sont plus faciles à faire évoluer et à partager avec votre équipe.
- Collaboration : les tests automatisés garantissent que les changements d’un collègue n’introduisent pas de régressions.
- Automatisation : intégrés dans vos pipelines, ils permettent un déploiement continu sécurisé.
En résumé, tester ses playbooks et rôles n’est pas une option : c’est une pratique incontournable pour toute équipe DevOps soucieuse de qualité et de fiabilité.
Pour s’assurer que votre code Ansible est propre, conforme aux bonnes pratiques et réellement fonctionnel, deux outils sont essentiels :
ansible-lint: vérifier la qualité et les conventions de votre code.Molecule: tester vos rôles dans des environnements isolés.
Dans les sections suivantes, nous allons découvrir chacun de ces outils avec des exemples concrets et des démos pas-à-pas, que ce soit sur votre poste local ou dans un pipeline CI/CD.
Ansible Lint : détecter les erreurs avant l’exécution
Avant même de lancer vos playbooks ou vos rôles, il est essentiel de s’assurer que votre code respecte les bonnes pratiques et ne comporte pas d’erreurs évidentes. C’est exactement ce que fait ansible-lint.
Ansible Lint est un outil qui analyse vos playbooks et rôles pour :
- détecter les erreurs de syntaxe et les incohérences,
- vérifier le respect des conventions et bonnes pratiques (nommage des tâches, handlers, variables, etc.),
- signaler les pratiques pouvant nuire à l’idempotence ou à la maintenabilité.
Son utilisation est simple et rapide. En quelques commandes, vous pouvez identifier les problèmes avant qu’ils n’impactent vos environnements. C’est un premier filet de sécurité qui permet de corriger les erreurs de manière proactive, plutôt que de découvrir un problème en production.
Dans un flux de travail typique :
- Vous écrivez votre rôle ou playbook.
- Vous lancez ansible-lint pour vérifier la qualité du code.
- Vous corrigez les avertissements ou erreurs remontés.
- Vous réexécutez le linting pour vous assurer que tout est conforme.
Intégrer ansible-lint dans votre poste local permet un feedback immédiat. L’ajouter à votre pipeline CI/CD garantit que chaque changement soumis au dépôt respecte les standards de qualité définis.
Dans la section suivante, nous verrons comment Molecule complète ce processus en testant concrètement vos rôles dans des environnements isolés.
Tester ses rôles Ansible avec Molecule
Lorsque l’on écrit des rôles Ansible, il ne suffit pas de vérifier la syntaxe ou la conformité aux bonnes pratiques : il faut aussi s’assurer que le rôle fonctionne réellement dans un environnement isolé. C’est là qu’intervient Molecule, l’outil de référence pour tester vos rôles.
Molecule permet de créer des environnements de test temporaires et reproductibles, d’appliquer vos rôles et de vérifier que le résultat correspond bien à ce que vous attendez. Il offre plusieurs avantages :
- Créer un environnement de test temporaire : Docker, Podman ou Vagrant peuvent servir de plateformes, mais le rôle est exécuté comme il le serait en production, via un playbook standard.
- Exécuter le rôle tel quel : Molecule lance votre rôle Ansible dans cet environnement, en utilisant les mêmes tasks, handlers et variables que pour un vrai déploiement.
- Valider l’état final avec Ansible : plutôt que d’utiliser Testinfra ou d’autres frameworks externes, on peut créer des playbooks de vérification Ansible ou des tâches assert pour vérifier l’existence de fichiers, la configuration des services, les permissions, etc.
- Gérer plusieurs scénarios : différents OS, configurations ou versions peuvent être testés via plusieurs scénarios Molecule.
- S’intégrer dans la CI/CD : les tests deviennent un processus automatisé, exécuté à chaque modification du rôle, garantissant que tout fonctionne avant merge ou déploiement.
En pratique, la structure d’un rôle testable avec Molecule comprend :
- Un répertoire
molecule/<scenario>/contenant le fichiermolecule.ymlqui décrit l’environnement et les étapes de test. - Des playbooks ou tasks spécifiques de vérification Ansible (
verify.yml) pour valider l’état final. - Le rôle principal (
tasks/main.yml,handlers,templates, etc.) utilisé sans modification.
Ainsi, Molecule ne se limite pas à exécuter le rôle : il fournit un cadre complet pour tester, valider et documenter le comportement attendu de vos rôles Ansible, ce qui augmente fortement la confiance dans vos déploiements automatisés.
Démonstration pratique : linting et tests automatisés
Après avoir présenté les concepts et les outils, voyons une démonstration concrète d’ansible-lint et de Molecule appliquée à un rôle Nginx. Cette section montre comment vérifier et valider vos rôles localement et comment intégrer ces tests dans un pipeline CI/CD.
Préparer le rôle Nginx
Supposons que nous ayons un rôle structuré comme suit :
.
├── .ansible-lint.yml
├── defaults
│ └── main.yml
├── files
│ └── 99nginx
├── handlers
│ └── main.yml
├── meta
│ ├── argument_specs.yml
│ └── main.yml
├── molecule
│ └── default
│ ├── converge.yml
│ ├── create.yml
│ ├── destroy.yml
│ ├── group_vars
│ │ └── all.yml
│ ├── inventory
│ │ └── inventory.yml
│ ├── molecule.yml
│ ├── templates
│ │ └── index.html.j2
│ └── verify.yml
├── README.md
├── tasks
│ └── main.yml
└── templates
└── vhost.j2
Voici un aperçu des principaux fichiers de notre rôle Nginx, avec leur fonction dans l’organisation du code :
|
Fichier |
Fonction |
|---|---|
|
.ansible-lint.yml |
Configure les règles utilisées par ansible-lint |
|
defaults/main.yml |
Valeurs par défaut des variables du rôle |
|
handlers/main.yml |
Handlers déclenchés par notify (ex. reload nginx) |
|
meta/argument_specs.yml |
Déclaration et documentation des variables du rôle |
|
meta/main.yml |
Métadonnées du rôle (dépendances, auteur, licence) |
|
molecule/default/converge.yml |
Playbook pour exécuter le rôle Nginx |
|
molecule/default/create.yml |
Playbook pour créer l’environnement de test |
|
molecule/default/destroy.yml |
Playbook pour supprimer l’environnement de test |
|
molecule/default/group_vars/all.yml |
Variables globales pour le scénario Molecule |
|
molecule/default/inventory/inventory.yml |
Inventaire des hôtes pour le scénario Molecule |
|
molecule/default/molecule.yml |
Configuration principale du scénario Molecule |
|
molecule/default/templates/index.html.j2 |
Template utilisé dans l’environnement de test |
|
molecule/default/verify.yml |
Playbook pour vérifier l’état final du rôle |
|
tasks/main.yml |
Tâches principales du rôle (installation et configuration) |
|
templates/vhost.j2 |
Template Jinja2 pour la configuration des vhosts Nginx |
Vérifier le rôle avec ansible-lint
Avant de commencer, assurez-vous qu’ansible-lint est installé ; vous pouvez suivre la documentation officielle pour l’installation.
Dans ce rôle, un fichier .ansible-lint.yml est présent à la racine et contient uniquement :
---
profile: production
Ce profil active un ensemble de règles plus strictes, adaptées à un usage en environnement réel, notamment sur la qualité du code, la sécurité et la lisibilité.
Pour lancer l’analyse :
~$ ansible-lint
Si des erreurs ou mauvaises pratiques sont détectées, ansible-lint les remonte immédiatement. Voici un exemple typique de sortie :
role/tasks/main.yml:12:34: yaml[truthy]
Use 'true' or 'false' instead of 'yes' or 'no'
role/tasks/main.yml:7: fqcn-builtins
Use FQCN for builtin module actions (ex: ansible.builtin.apt)
role/handlers/main.yml:3: name[missing]
All handlers should have a name
Ce retour rapide permet de corriger les problèmes avant exécution ou intégration CI/CD, et garantit une meilleure qualité de code dès les premières étapes.
Tester des rôles avec Molecule
Pour s’assurer qu’un rôle fonctionne correctement avant de le déployer, Molecule permet de créer un environnement isolé, d’exécuter le rôle et de vérifier que tout fonctionne comme prévu.
Pour commencer, installez Molecule et ses dépendances si ce n’est pas déjà fait.
Dans notre exemple, nous allons illustrer son utilisation avec notre rôle Nginx.
Avant de lancer les tests, nous définissons la variable nginx_vhosts dans le fichier group_vars/all.yml, qui contient la configuration des différents sites à déployer :
---
nginx_vhosts:
- name: frontend
listen: 8080
server_name: frontend.exemple.com
root: /usr/share/nginx/html/frontend
- name: backend
listen: 8081
server_name: backend.exemple.com
root: /usr/share/nginx/html/backend
Le fichier molecule.yml définit le scénario global de test. Il indique à Molecule quel driver utiliser (Docker par défaut), quels playbooks exécuter pour créer, appliquer et vérifier le rôle, ainsi que la séquence des étapes :
---
ansible:
executor:
backend: ansible-playbook
args:
ansible_playbook:
- --inventory=inventory/
cfg:
defaults:
callback_result_format: yaml
deprecation_warnings: false
playbooks:
create: create.yml
destroy: destroy.yml
converge: converge.yml
verify: verify.yml
scenario:
test_sequence:
Explications :
- create : prépare l’environnement (réseau et conteneur).
- converge : applique le rôle Nginx.
- verify : effectue les tests pour vérifier que le rôle fonctionne correctement.
- destroy : nettoie l’environnement après le test.
Cette approche permet de garantir que le rôle est testé de manière complète et reproductible, étape par étape.
Avant d’appliquer le rôle, Molecule prépare un environnement de test dans un conteneur Docker. Le playbook create.yml démarre un conteneur Debian minimal et configure un réseau dédié :
- name: Start the webcontainer
community.docker.docker_container:
name: webcontainer
image: debian:trixie-slim
networks:
- name: molecule-nginx
published_ports: "{{ nginx_vhosts | map(attribute='listen') | map('string') | map('regex_replace', '^(.*)$', '\\1:\\1') | list }}"
command: sleep infinity
Les ports des vhosts sont automatiquement mappés du conteneur vers l’hôte grâce à published_ports, ce qui permet de tester l’accès HTTP à chaque site directement depuis la machine locale.
Le conteneur reste en veille (sleep infinity) jusqu’à l’exécution du rôle, prêt à recevoir toutes les tâches Ansible. On peut déclencher la création de l’environnement avec la commande suivante :
~$ molecule create
Le rôle Nginx est exécuté via converge.yml, qui configure les vhosts et déploie les pages index.html à partir du template fourni :
- name: Converge Molecule test environment
hosts: webcontainer
connection: docker
roles:
- bchauvelier.nginx
Pour appliquer le rôle dans le conteneur et déployer les vhosts, exécutez simplement :
~$ molecule converge
Le playbook verify.yml est chargé d’effectuer plusieurs contrôles :
---
- name: Verify Nginx service in container
hosts: webcontainer
connection: docker
gather_facts: false
tasks:
- name: Gather service facts from container
ansible.builtin.service_facts:
- name: Assert Nginx service is installed and running
ansible.builtin.assert:
that:
- "'nginx' in services"
- "services['nginx'].state == 'running'"
quiet: true
- name: Validate Nginx configuration syntax
ansible.builtin.command: nginx -t
changed_when: false
- name: Verify Nginx vhosts via HTTP
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Check that all vhosts respond with HTTP 200
ansible.builtin.uri:
url: "http://localhost:{{ item.listen }}"
loop: "{{ nginx_vhosts }}"
loop_control:
label: "{{ item.name }}"
La première partie s’exécute directement dans le conteneur Docker (webcontainer). Elle réalise trois contrôles essentiels :
- Récupération de l’état des services avec
service_facts. - Vérification que Nginx est installé et en cours d’exécution via une assertion.
- Validation de la configuration avec
nginx -tpour s’assurer qu’aucune erreur de syntaxe ne bloque le service.
Ces tests permettent de confirmer que le rôle a bien installé et configuré Nginx dans le conteneur cible.
La seconde partie s’exécute en local et vérifie que chaque vhost défini dans nginx_vhosts répond correctement en HTTP. Grâce à la boucle sur nginx_vhosts, chaque port est testé automatiquement (par exemple 8080 et 8081). Cela valide à la fois :
- l’accessibilité réseau,
- la publication des vhosts,
- et le bon rendu des pages index déployées.
Après avoir appliqué le rôle et vérifié son fonctionnement, il est important de supprimer l’environnement de test pour repartir sur une base propre et éviter d’accumuler des conteneurs ou des réseaux Docker inutiles.
Le playbook destroy.yml s’occupe de cette étape. Voici un exemple concret :
---
- name: Destroy Molecule test environment
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Remove test container
community.docker.docker_container:
name: webcontainer
state: absent
- name: Delete Molecule Docker network
community.docker.docker_network:
name: molecule-nginx
state: absent
Pour exécuter ce nettoyage de manière automatisée, Molecule fournit la commande :
~$ molecule destroy
Cette commande lance le playbook destroy.yml et garantit que tous les conteneurs et réseaux créés par Molecule sont supprimés, rendant vos tests reproductibles et propres pour les cycles suivants.
Pour simplifier le cycle complet de création, application, vérification et destruction de l’environnement de test, Molecule propose la commande unique :
~$ molecule test
Avec molecule test, vous pouvez lancer un test complet d’un rôle en une seule commande, garantissant que toutes les étapes sont reproductibles et que le rôle est prêt pour la production ou l’intégration dans un pipeline CI/CD.
Automatiser les tests avec GitLab CI/CD
Pour automatiser la vérification et les tests de vos rôles Ansible, vous pouvez définir un pipeline GitLab simple avec deux stages : lint et test :
---
stages:
- lint
- test
variables:
PIP_CACHE_DIR: "${CI_PROJECT_DIR}/.pip"
cache:
paths:
- .pip/
ansible-lint:
stage: lint
image:
registry.gitlab.com/pipeline-components/ansible-lint:latest
script:
- ansible-lint --show-relpath
molecule:
stage: test
image: docker:stable-dind
services:
- docker:dind
before_script:
- apk add --no-cache
python3 python3-dev py3-pip gcc git curl build-base
autoconf automake py3-cryptography linux-headers
musl-dev libffi-dev openssl-dev openssh
- python3 -m pip install ansible ansible-dev-tools docker
script:
- molecule test
Le job ansible-lint utilise une image prête à l’emploi pour analyser rapidement le rôle et remonter les éventuelles erreurs ou mauvaises pratiques. Le job molecule installe Ansible et Molecule, puis exécute l’ensemble des tests définis dans votre scénario Molecule via la commande molecule test.
Grâce à ce pipeline, chaque commit déclenche automatiquement le linting et les tests du rôle Nginx dans un environnement isolé, garantissant que votre code reste fiable, reproductible et prêt pour la production.
Cette approche complète la démonstration pratique : nous avons vu comment analyser un rôle avec ansible-lint, le tester localement avec Molecule, puis automatiser l’ensemble dans un pipeline CI/CD pour sécuriser et industrialiser vos déploiements Ansible.
En résumé : tester l’infrastructure comme du code
Les tests ne sont pas réservés aux applications : vos rôles et playbooks Ansible méritent eux aussi d’être validés systématiquement. Avec ansible-lint, vous détectez rapidement les erreurs de syntaxe et les mauvaises pratiques, tandis que Molecule permet de tester vos rôles dans des environnements isolés et reproductibles, de la création des conteneurs à la vérification des services déployés. L’intégration de ces étapes dans un pipeline CI/CD garantit que chaque modification est contrôlée avant d’atteindre la production, renforçant la fiabilité et la qualité de votre infrastructure comme du code.
Pour aller plus loin, Ansible propose ansible-test, un outil dédié aux tests des collections et des modules. Contrairement à Molecule, il ne s’adresse pas aux rôles individuels mais permet de vérifier la compatibilité, l’idempotence et le bon fonctionnement des modules et plugins inclus dans une collection. Cela offre une couverture de tests plus large et adaptée aux environnements Ansible complexes.En adoptant cette démarche, vos playbooks et rôles deviennent des composants fiables et maintenables, testés et prêts à être déployés en toute confiance.

