Aller au contenu
Infrastructure as Code medium

Installer Molecule et prendre en main sa CLI

75 min de lecture

Logo Ansible

Molecule crée des machines de test, y joue votre rôle, vérifie le résultat, puis détruit tout. Cette page installe l'outil, produit un premier scénario, puis règle les quatre points qui séparent le scénario généré d'un scénario réellement fonctionnel. Elle se termine par les commandes de la CLI Molecule, qui sont votre interface quotidienne avec l'outil.

L'obstacle qui attend tout le monde est contre-intuitif : le scénario généré passe au vert sans avoir rien testé. Comprendre pourquoi, et le corriger, est le cœur de ce guide.

  • Installer Molecule et le plugin correspondant à votre moteur de conteneurs.
  • Créer un scénario, et identifier les cinq fichiers déposés.
  • Lire un molecule.yml moderne, qui n'a plus la structure décrite par la plupart des tutoriels.
  • Rendre ce scénario fonctionnel, jusqu'à un rôle réellement joué dans un conteneur.
  • Utiliser les commandes de la CLI, du cycle complet au diagnostic pas à pas.

Molecule est un outil Python indépendant d'ansible-core. L'installer avec pipx l'isole dans son propre environnement, ce qui évite de mélanger ses dépendances avec celles de votre système. Le plugin de driver s'ajoute ensuite dans ce même environnement, car Molecule seul ne sait pas fabriquer de conteneur.

Fenêtre de terminal
# Molecule, puis le plugin Podman dans le même environnement isolé
pipx install molecule==26.4.0
pipx inject molecule "molecule-plugins[podman]"

La vérification donne bien plus qu'un numéro de version : elle liste les plugins détectés et la version d'ansible-core que Molecule utilisera, qui n'est pas forcément celle de votre shell.

Fenêtre de terminal
$ molecule --version
molecule 26.4.0 using python 3.12
ansible:2.20.5
podman:25.8.12 from molecule_plugins
docker:25.8.12 from molecule_plugins

Si la ligne ansible: n'apparaît pas, Molecule ne trouve pas de moteur Ansible utilisable et rien ne fonctionnera ensuite. Si aucun plugin n'est listé, l'injection a échoué et la création de machines restera impossible.

La commande molecule drivers confirme ce que l'installation met à disposition. Elle liste les drivers connus, podman et docker en tête pour un usage local.

La commande s'exécute depuis la racine du rôle, et non depuis un répertoire quelconque. Un scénario est un dossier de configuration autonome : vous en aurez plusieurs le jour où vous testerez sur plusieurs distributions.

Fenêtre de terminal
cd monrole
molecule init scenario

Elle dépose exactement cinq fichiers dans molecule/default/ :

molecule/default/
├── molecule.yml # la configuration du scénario
├── create.yml # comment fabriquer les machines de test
├── destroy.yml # comment les détruire
├── converge.yml # le playbook qui appelle votre rôle
└── verify.yml # les vérifications après convergence

Le nom default est celui du scénario. Vous pouvez en créer d'autres en passant un nom en argument, sujet traité dans Scénarios multi-distributions.

Ce fichier surprend quiconque a lu un tutoriel écrit avant 2025. Il ne contient aucune section driver: ni platforms:, qui étaient pourtant le cœur de la configuration des versions précédentes. Voici ses blocs significatifs.

dependency:
name: galaxy
options:
role-file: requirements.yml
requirements-file: requirements.yml
ansible:
cfg:
defaults:
host_key_checking: false
verbosity: 1
executor:
backend: ansible-playbook
args:
ansible_playbook:
- --diff
- --force-handlers
- --inventory=/path/to/inventory.yml
playbooks:
converge: converge.yml
verify: verify.yml
scenario:
name: default
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- idempotence
- side_effect
- verify
- cleanup
- destroy

Quatre blocs le composent. dependency installe les rôles et collections déclarés dans un requirements.yml avant chaque test. ansible configure le moteur pour la durée du scénario, en écrivant un ansible.cfg temporaire. executor liste les arguments passés à ansible-playbook. scenario énumère les étapes que molecule test enchaînera dans l'ordre.

Deux détails de ce fichier généré méritent votre attention immédiate. La ligne --inventory=/path/to/inventory.yml est un exemple laissé en place, pas un chemin valide. Surtout, la création des machines n'est plus décrite ici, elle est déléguée à create.yml, et c'est ce déplacement qui explique la section suivante.

Ouvrez create.yml, et le diagnostic tient dans son commentaire d'ouverture :

- name: Create
hosts: localhost
connection: local
gather_facts: false
tasks:
# TODO: Developer must implement and populate 'server' variable
- name: Create instance config
when: server.changed | default(false) | bool # noqa no-handler
block:
- name: Populate instance config dict # noqa jinja
ansible.builtin.set_fact:
instance_conf_dict: {}

Le fichier est un squelette à compléter. La variable server n'est jamais définie, donc la condition vaut faux, donc toutes les tâches de création sont ignorées. Aucune machine n'est fabriquée. Le # noqa no-handler en fin de ligne fait taire une règle d'ansible-lint : Molecule annote son propre squelette pour qu'il passe le linter, ce qui confirme qu'il est destiné à être remplacé.

La conséquence à l'exécution est déroutante :

INFO [default > create] Executing
skipping: [localhost] => {"false_condition": "server.changed | default(false) | bool"}
localhost : ok=0 changed=0 unreachable=0 failed=0 skipped=3
INFO [default > create] Executed: Successful

Le PLAY RECAP affiche ok=0, et Molecule annonce pourtant Successful. Le cycle complet se termine avec un code de retour nul alors qu'aucune instance n'existe et que votre rôle n'a jamais été joué.

Le plugin installé plus haut fournit ses propres playbooks de création et de destruction, éprouvés et maintenus. Le travail consiste donc à lui laisser la place, en quatre gestes qui se tiennent.

Le premier est le moins intuitif : supprimez les squelettes locaux. Tant que create.yml et destroy.yml existent dans le dossier du scénario, Molecule les utilise et ignore ceux du driver. Leur simple présence suffit à les faire gagner.

Fenêtre de terminal
rm molecule/default/create.yml molecule/default/destroy.yml

Le deuxième déclare le driver et les machines voulues. Les sections driver: et platforms: sont absentes du fichier généré, mais le driver Podman les attend, et c'est là que vous choisissez votre image de test.

---
driver:
name: podman
platforms:
- name: instance
image: quay.io/centos/centos:stream9@sha256:3714c89f1903dac5a5e1eb6c02d84189ff6d962a0c18df01feba0a5406856926

Le troisième rend votre rôle visible. Molecule n'ajoute pas le répertoire parent du rôle au chemin de recherche, ce qui provoque un échec sec au converge. La variable MOLECULE_PROJECT_DIRECTORY pointe sur la racine du rôle, donc son parent est le répertoire qui contient vos rôles.

ansible:
cfg:
defaults:
roles_path: ${MOLECULE_PROJECT_DIRECTORY}/..
host_key_checking: false

Profitez-en pour retirer la ligne --inventory=/path/to/inventory.yml du bloc executor, qui pointe vers un fichier inexistant.

Le quatrième corrige le nom du rôle. Le converge.yml généré référence un rôle fictif, et l'oublier donne l'erreur the role 'yournamespace.yourcollection.yourrole' was not found.

---
- name: Converge
hosts: all
gather_facts: true
tasks:
- name: Apply role under test
ansible.builtin.include_role:
name: monrole

Le hosts: all désigne l'inventaire produit par le driver, pas votre inventaire de production. Molecule le construit à la volée et l'oublie à la destruction.

Le résultat se vérifie en une commande, et cette fois le recap est parlant :

TASK [monrole : Deposer un fichier temoin] *************************************
instance : ok=3 changed=1 unreachable=0 failed=0 skipped=0

Un conteneur instance existe, votre rôle y a exécuté ses tâches, et molecule list le confirme en affichant Created: true et Converged: true.

Le cycle complet s'obtient avec molecule test, qui enchaîne toute la test_sequence puis détruit l'instance, y compris en cas de succès. C'est la commande de l'intégration continue, et la plus mauvaise compagne du développement : elle repart de zéro à chaque appel et ne laisse rien à inspecter.

Fenêtre de terminal
molecule test

Au quotidien, vous utiliserez plutôt les étapes séparément. Elles conservent l'instance entre deux appels, ce qui rend la boucle de correction rapide.

Fenêtre de terminal
molecule create # fabriquer l'instance et s'arrêter là
molecule converge # jouer le rôle sur l'instance existante
molecule idempotence # rejouer le converge, échoue si quelque chose change
molecule verify # exécuter les vérifications de verify.yml
molecule destroy # détruire l'instance

L'étape idempotence mérite d'être connue pour elle-même : elle rejoue le converge et échoue si une tâche se déclare modifiée au second passage. Molecule vérifie donc gratuitement une propriété fondamentale de vos rôles, sans que vous ayez une seule assertion à écrire.

Trois commandes servent au diagnostic quand quelque chose résiste. molecule list affiche l'état des instances, molecule login ouvre un shell dans l'instance pour constater l'état réel du système, et molecule reset efface les fichiers temporaires de Molecule quand son état interne ne correspond plus à la réalité.

Fenêtre de terminal
molecule list # instances, driver, créée et convergée ou non
molecule login # shell interactif dans l'instance
molecule reset # purger l'état temporaire de Molecule

Deux dernières commandes s'exécutent sans rien créer, donc instantanément. molecule syntax contrôle la syntaxe des playbooks et molecule matrix affiche la liste des étapes qu'une commande donnée déclencherait, ce qui répond une bonne fois à la question de savoir ce que molecule test fait exactement.

Fenêtre de terminal
molecule syntax
molecule matrix test

Vous avez maintenant un scénario qui fabrique une instance, y joue un rôle et vérifie l'idempotence. La suite consiste à écrire les tests avant le code du rôle, méthode détaillée dans Le cycle TDD complet, qui construit un rôle users en trois cycles successifs sur cette base.

Ces messages arrivent presque toujours, dans cet ordre, et aucun n'est un défaut de votre travail. Les reconnaître fait gagner beaucoup de temps.

Le premier survient avant même que Molecule ne démarre, si votre rôle vient d'être créé par ansible-galaxy role init :

InvalidPrerequisiteError: Computed fully qualified role name of monrole does not
follow current galaxy requirements.

Molecule exige un nom pleinement qualifié, que le squelette généré ne fournit pas. Deux lignes dans meta/main.yml règlent la question :

galaxy_info:
role_name: monrole
namespace: demo

Le deuxième frappe au converge, et c'est celui que le roles_path de la section précédente corrige :

[ERROR]: the role 'monrole' was not found in .../molecule/default/roles:
/home/bob/.ansible/roles:/usr/share/ansible/roles

Le chemin de recherche affiché ne contient pas le répertoire de votre rôle. Ansible ne cherche jamais ailleurs, d'où l'échec immédiat.

Le troisième est un simple avertissement de fin d'exécution, et beaucoup le prennent à tort pour une erreur :

WARNING Molecule executed 1 scenario (1 missing files)

Le molecule.yml référence des playbooks facultatifs comme prepare.yml, cleanup.yml ou side_effect.yml que init ne génère pas. Leur absence n'empêche rien, les étapes correspondantes sont sautées. Créez-les si vous en avez besoin, ignorez l'avertissement sinon.

Un scénario généré passe au vert sans avoir rien testé : ce lab part de ce constat pour le combler. Vous y ajoutez un prepare.yml et un requirements.yml, personnalisez les instances par host_vars, déclarez une test_sequence qui inclut l'étape d'idempotence, et activez profile_tasks pour voir où part le temps. La correction relit le scénario produit et refuse un molecule.yml resté au squelette d'origine.

SymptômeCauseSolution
molecule test réussit mais rien n'a tournéLes squelettes create.yml et destroy.yml sont toujours làLes supprimer et déclarer driver: plus platforms:
the role 'monrole' was not foundLe rôle parent n'est pas dans le chemin de rechercheAjouter roles_path: ${MOLECULE_PROJECT_DIRECTORY}/..
yournamespace.yourcollection.yourrole was not foundLe converge.yml généré cite un rôle fictifY mettre le nom réel de votre rôle
Computed fully qualified role name au démarragemeta/main.yml sans namespace ni role_nameAjouter les deux clés
1 missing files en fin d'exécutionPlaybooks facultatifs non générésSans conséquence, ou créer les fichiers concernés
Aucun plugin listé par molecule --versionL'injection dans l'environnement pipx a échouéRejouer pipx inject molecule "molecule-plugins[podman]"
  • molecule init scenario dépose cinq fichiers, dont create.yml et destroy.yml qui sont des squelettes non fonctionnels.
  • Un scénario neuf réussit sans rien tester, avec un code de retour nul et un PLAY RECAP à ok=0.
  • Supprimer les squelettes locaux est ce qui laisse le driver Podman fournir ses propres playbooks de création.
  • roles_path: ${MOLECULE_PROJECT_DIRECTORY}/.. rend votre rôle visible depuis le scénario.
  • molecule test détruit tout à la fin : préférez create, converge et verify séparément pendant le développement.
  • L'étape idempotence rejoue le converge et échoue si quelque chose change au second passage.

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn