Tester vos rôles Ansible avec Molécule + GitHub Actions (CI Automatisée)

Introduction

 

Dans un environnement DevOps, chaque modification de code doit pouvoir être testée rapidement et de manière fiable. Avec Ansible, le risque est simple : un rôle mal testé peut faire tomber une partie ou la totalité d’une infrastructure.

Molecule permet déjà de tester vos rôles localement. Mais en l’associant à GitHub Actions, vous pouvez exécuter ces tests automatiquement à chaque commit ou pull request. Résultat : vous atteignez en moyenne 80 à 90 % de couverture de scénarios critiques et vous pouvez détecter plus de 85 % des erreurs potentielles avant même qu’elles n’arrivent en production. Plus de confiance, moins de mauvaises surprises.

Si vous débutez avec Ansible, notre cours Ansible vous aide à poser des bases solides. Pour aller plus loin (tests role avec molecule, CI/CD, retours d’expérience), découvrez Ansible Expert.

Durée de mise en place : 30 à 45 min

 

Rappel : Molecule en quelques mots

 

Molecule est un framework open-source qui aide à tester des rôles Ansible dans des environnements isolés, souvent via Docker. Il suit un scénario simple :

  • Créer l’environnement de test. ;
  • Appliquer le rôle Ansible. ;
  • Vérifier le résultat avec Testinfra ou Ansible.
  • Nettoyer l’environnement.

Résultat : des rôles plus fiables, moins de surprises, et une base saine pour l’intégration continue.

Pourquoi utiliser GitHub Actions avec Molecule ?

Dans de nombreuses équipes, les rôles Ansible évoluent vite… et les régressions se voient trop tard. Molecule apporte un filet de sécurité : un environnement éphémère (Docker), un playbook “converge”, des vérifications, et un nettoyage propre. Adossé à GitHub Actions, chaque modification est testée automatiquement, et sur plusieurs distributions Linux pour éviter les surprises.

    • Automatisation totale : plus besoin de lancer les tests à la main.
    • Détection rapide : si un rôle casse, vous le savez immédiatement.
    • Qualité constante : chaque commit est validé avant d’être fusionné.
    • Travail d’équipe facilité : tout le monde voit l’état des tests dans GitHub.

Mise en place locale (exemple avec le rôle ansible-role-traefik)

 

Qu’est-ce que Traefik ?

Traefik est un reverse-proxy et load balancer open source (écrit en Go) pensé pour les environnements cloud-native (Docker, Kubernetes, Consul, etc.). Il découvre automatiquement les services, expose des routes HTTP(S) dynamiques via des règles, gère TLS/Let’s Encrypt, HTTP/2/3, des middlewares (auth, redirections, rate-limit…), l’observabilité (logs, metrics), et propose un dashboard/API.

En résumé: C’est une façon simple et moderne de publier et router des applications conteneurisées.

Installation de packer

Molecule et GitHub Actions, un duo gagnant pour Ansible 

Vue d’ensemble (système & architecture) 

  • Local : hôte Ubuntu 22.04 LTS, Docker Engine, Python 3 (venv), outils Ansible/Molecule/Testinfra. 
  • CI : runner GitHub Actions ubuntu-latest, workflow avec matrix (Ubuntu, Debian) ; chaque job installe la toolchain et lance molecule test. 
  • Cycle Molecule : create → converge → verify → destroy 

 

Cas d’usage : installation de Traefik, démarrage du service systemd, vérification que l’API et le dashboard 

Prérequis système (Ubuntu 22.04) 

Ressources conseillées (dev local) : 2 vCPU, 4–8 Go RAM, 3–6 Go de disque libre, accès Internet. 

Paquets : 

sudo apt update 
sudo apt install -y python3 python3-pip python3-venv python3-dev build-essential libffi-dev libssl-dev 
sudo apt install -y python-is-python3   # optionnel (alias 'python' → python3) 
sudo apt install -y docker.io 
sudo usermod -aG docker $USER 
newgrp docker 

 

Installation de packer

Dépôt cible & structure Molecule 

Créez (ou utilisez) un dépôt de rôle Ansible — ici le rôle https://github.com/simoncaron/ansible-role-traefik  sert de support pour intégrer Molecule (l’objectif est de tester ce role). 

Forkez et cloner le repo: https://github.com/simoncaron/ansible-role-traefik 

cd ansible-role-traefik / 
 
python3 -m venv .venv 
source .venv/bin/activate 
python -m pip install --upgrade pip setuptools wheel 
 
# Pile outils (driver docker via plugins) 

 
pip install "molecule" "molecule-plugins[docker]" ansible ansible-lint testinfra docker 

 

Installation de packer

Ajouter un scénario Molecule 

Si le dépôt ne contient pas encore de scénario comme ici : 

Installation de packer

Tapez:

molecule init scenario default --driver-name docker 

 

Installation de packer

Après l’initialisation le dossier molécule va se creer dans le repos du rôle: 

 Toujours

Installation de packer

dans le repertoire molecule/default/ rajouter les fichiers requirements.yml et verify.yml pour avoir ceci: 

molecule/default/ 

├── converge.yml 

├── molecule.yml 

├── requirements.yml 

└── verify.yml 

 

Fichier : molecule/default/molecule.yml 

Remplace le contenu /default/molecule.yml par : 

--- 

driver: 

  name: docker 

 

platforms: 

  - name: instance 

    image: ${MOLECULE_IMAGE:-geerlingguy/docker-ubuntu2204-ansible} 

    pre_build_image: true 

    privileged: true 

    command: /sbin/init 

    cgroupns_mode: host 

    user: root 

    environment: 

      HOME: /root 

    volumes: 

      - /sys/fs/cgroup:/sys/fs/cgroup:rw 

    tmpfs: 

      - /run 

      - /tmp:rw,mode=1777   # <— essentiel : /tmp en écriture avec bons perms 

    # Optionnel: pour voir le dashboard depuis ton host pendant les tests locaux 

    published_ports: 

      - "8080:8080"   # http://localhost:8080/dashboard/ 

      - "80:80" 

provisioner: 

  name: ansible 

  config_options: 

    defaults: 

      host_key_checking: false 

      remote_tmp: /tmp/.ansible/tmp 

  inventory: 

    host_vars: 

      instance: 

        ansible_connection: docker 

        ansible_user: root 

        ansible_python_interpreter: /usr/bin/python3 

  playbooks: 

    converge: converge.yml 

    verify: verify.yml 

 

dependency: 

  name: galaxy 

  options: 

    role-file: requirements.yml 

    roles-path: "${MOLECULE_EPHEMERAL_DIRECTORY}/roles" 

    force: true 

 

scenario: 

  test_sequence: 

    - dependency 

    - cleanup 

    - destroy 

    - syntax 

    - create 

    - prepare 

    - converge 

    - verify 

    - cleanup 

    - destroy 

 

  

Ce fichier décrit l’environnement Docker, publie les ports 80/8080, et configure la provision via Ansible en pointant sur tes playbooks converge.yml et verify.yml. 

 

 

Fichier : molecule/default/converge.yml 

Ton playbook télécharge le binaire Traefik sur le contrôleur, l’extrait en local, applique le rôle local (chemin projet), puis démarre le service. Enfin, il vérifie l’API /api/rawdata et le dashboard /dashboard/. 

- name: Converge (Traefik dashboard insecure)
hosts: all
become: true

gather_facts: true

pre_tasks:
# 1) Télécharger l’archive sur le CONTROLEUR au chemin attendu par le rôle

- name: Pre-download Traefik archive on controller
ansible.builtin.get_url:
url: "https://github.com/traefik/traefik/releases/download/v{{ traefik_version }}/traefik_v{{ traefik_version }}_linux_amd64.tar.gz"
dest: "/tmp/traefik-{{ traefik_version }}.linux-amd64.tar.gz"
mode: "0644"

delegate_to: localhost

run_once: true

become: false

# 2) Décompresser en local vers /tmp pour obtenir /tmp/traefik

- name: Unarchive traefik locally to /tmp

ansible.builtin.unarchive:

src: "/tmp/traefik-{{ traefik_version }}.linux-amd64.tar.gz"

dest: "/tmp"

remote_src: false

creates: "/tmp/traefik"

delegate_to: localhost

run_once: true

become: false

# 3) S’assurer que le binaire est exécutable

- name: Ensure /tmp/traefik is executable (controller)

ansible.builtin.file:

path: "/tmp/traefik"

mode: "0755"

state: file

delegate_to: localhost

run_once: true

become: false

roles:

# Appel du rôle local par chemin absolu pour éviter tout souci de FQCN

- role: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}"

vars:

traefik_version: "2.6.1"

traefik_config:

api:

insecure: true

dashboard: true

entryPoints:

traefik:

address: ":8080"

http:

address: ":80"

handlers:

- name: bounce traefik

listen:

- restart traefik

- reload traefik

ansible.builtin.systemd:

name: traefik

state: restarted # 'restarted' marche même si le unit ne supporte pas 'reload'

daemon_reload: true

become: true

# Pas de handlers requis côté rôle -> on le (re)démarre explicitement ici

post_tasks:

- name: Reload systemd units

ansible.builtin.systemd:

daemon_reload: true

- name: Enable + start Traefik

ansible.builtin.systemd:

name: traefik

state: started

enabled: true

- name: Wait for Traefik API (8080)

ansible.builtin.wait_for:

host: 127.0.0.1

port: 8080

timeout: 60

- name: Check Traefik API returns JSON

ansible.builtin.uri:

url: http://127.0.0.1:8080/api/rawdata

method: GET

status_code: 200

return_content: true

register: traefik_api

retries: 5

delay: 2

until: traefik_api.status == 200

- name: Check dashboard HTML is served

ansible.builtin.uri:

url: http://127.0.0.1:8080/dashboard/

method: GET

status_code: 200

return_content: true
register: traefik_dash
- name: Assert dashboard content looks OK
ansible.builtin.assert:
that:

- "'Traefik' in traefik_dash.content"
fail_msg: "Le dashboard ne semble pas servi correctement."
Fichier : molecule/default/verify.yml 

Le playbook de vérification confirme que le service écoute sur :8080 puis exige un HTTP 200 sur /dashboard/. 

 

- name: Verify (Traefik dashboard) 

  hosts: all 

  become: true 

  gather_facts: false 

 

  tasks: 

    - name: Attend que Traefik écoute sur 8080 

      ansible.builtin.wait_for: 

        host: 127.0.0.1 

        port: 8080 

        timeout: 120 

        state: started 

 

    - name: Vérifie que /dashboard/ répond 200 

      ansible.builtin.uri: 

        url: http://127.0.0.1:8080/dashboard/ 

        follow_redirects: all 

        return_content: false 

        status_code: 200 

 

 

 

Fichier : molecule/default/requirements.yml 

--- 

roles: 

  - name: simoncaron.traefik 

    src: https://github.com/Aurelie-Kamgang/ansible-role-traefik.git 

  

Dans notre converge.yml, on appelle le rôle local avec {{ lookup(‘env’, ‘MOLECULE_PROJECT_DIRECTORY’) }}. Garde ce requirements.yml si tu veux tester une autre source en mode dependency. 

Exécution locale (Ubuntu 22.04) 

  • Lint et meta Galaxy propres  

Dans meta/main.yml (utile pour ansible-lint) : 

--- 

galaxy_info: 

  namespace: simoncaron 

  role_name: traefik 

  author: Simon Caron 

  description: Installing and configure Traefik Webserver 

  license: "MIT" 

  min_ansible_version: "2.5" 

  platforms: 

    - name: Ubuntu 

      versions: 

        - bionic 

        - focal 

        - groovy 

        - hirsute 

  galaxy_tags: 

  - system 

  - network 

  - linux 

  - monitoring 

  - traefik 

dependencies: [] 

  

    • Exécuter Molecule en local 

    # Création de l’environnement de test (Docker) 
    molecule create 

    Installation de packer
    Installation de packer
    • Après la création on a l’instance qui est disponible 
    Installation de packer

    # Application du rôle (convergence) 

    Molecule converge 

    Installation de packer
    Installation de packer
    • #Visualisation de l’application apres le converge 
    Installation de packer

    # Arrête et supprime le conteneur + ressources associées 

    molecule destroy

    Installation de packer
    Installation de packer

    # test complet (par défaut sur Ubuntu 22.04)
    molecule test orchestre automatiquement la séquence complète (dependency → cleanup/destroy → syntax → create → prepare → converge → verify → cleanup → destroy) telle que définie dans ton scenario.test_sequence. 

    • C’est la commande la plus utilisée en automatisation (GitHub Actions, GitLab CI, Jenkins…) car elle porte le pipeline de A à Z. 

     

    Intégration CI : GitHub Actions en matrix multi-OS 

    Créer .github/workflows/molecule-matrix.yml à la racine du repo : 

    name: Molecule Multi-OS Test 

    name: Molecule 
    
     
    
    on: 
    
      push: 
    
        branches: [ master, main ] 
    
      pull_request: 
    
     
    
    jobs: 
    
      molecule: 
    
        name: Molecule (${{ matrix.label }}) 
    
        runs-on: ubuntu-latest 
    
        strategy: 
    
          fail-fast: false 
    
          matrix: 
    
            include: 
    
              - label: ubuntu2204 
    
                image: geerlingguy/docker-ubuntu2204-ansible 
    
              - label: debian12 
    
                image: geerlingguy/docker-debian12-ansible 
    
     
    
        steps: 
    
          - name: Checkout 
    
            uses: actions/checkout@v4 
    
     
    
          - name: Set up Python 
    
            uses: actions/setup-python@v5 
    
            with: 
    
              python-version: "3.10"   # pas de cache pip pour éviter l’erreur de fichier manquant 
    
     
    
          - name: Install Molecule toolchain 
    
            run: | 
    
              python -m pip install --upgrade pip 
    
              pip install molecule "molecule-plugins[docker]" ansible docker 
    
     
    
          - name: Docker info (debug) 
    
            run: docker info 
    
     
    
          - name: Run Molecule tests 
    
            env: 
    
              MOLECULE_IMAGE: ${{ matrix.image }} 
    
            run: molecule test 
    
      

     

     

     

    Distribution  Image Docker (MOLECULE_IMAGE) 
    Ubuntu 22.04  geerlingguy/docker-ubuntu2204-ansible 
    Debian 12  geerlingguy/docker-debian12-ansible 

     

    Après push/PR : Deux jobs parallèles, un par distribution. 

    Installation de packer

    Sécurité : ne laissez pas le dashboard en « insecure » 

    Dans ce tuto, api.insecure: true simplifie les tests. N’exposez jamais cela en production.
    En prod, activez TLS (certresolver), auth, ou restreignez l’accès (middleware + IPAllowList, etc.). 

     

    FAQ 

    Pourquoi télécharger le binaire côté contrôleur ?
    Pour éviter des restrictions réseau dans le conteneur et fiabiliser la répétabilité du test. 

    Puis-je ajouter des tests Testinfra ?
    Oui — en complément de verify.yml : vérifiez le binaire, les sockets, l’unité systemd, la présence des fichiers de config/règles. 

     

    Conclusion 

    Ce tutoriel a montré, pas à pas, comment industrialiser la validation d’un rôle Ansible avec Molecule (Docker) et GitHub Actions, en utilisant Traefik comme exemple. 

    Ce qui est vérifié : 

    • Installation de Traefik, service systemd opérationnel et dashboard servi ; 
    • Fin voulue confirmée : binaire présent/exécutable, service enabled/running, :8080 à l’écoute, /dashboard/ → HTTP 200 (en local et en CI) ; 
    • Échecs explicites en cas de souci (timeout sur :8080, statut ≠ 200, service en échec) pour un diagnostic immédiat. 

    Avec Molecule + Docker, tu valides localement l’installation, le service et le serving du dashboard.
    Avec GitHub Actions, ces validations s’exécutent automatiquement à chaque commit/PR sur plusieurs distributions. 

    En pratique, molecule test orchestre toute la séquence
    (dependency → cleanup/destroy → syntax → create → prepare → converge → verify → cleanup → destroy)
    et c’est la commande de référencesurtout en automatisation (CI/CD). 

    Résultat : une chaîne de confiance de bout en bout, des revues plus rapides et des déploiements plus sûrs — un patron de test que tu peux appliquer à n’importe quel rôle Ansible, bien au-delà de Traefik. 

    👉 Dépôt associé : https://github.com/Aurelie-Kamgang/ansible-role-traefik.git

     

    Tags et Catégories

    Tags : #Ansible #Semaphore #Automatisation #DevOps
    Catégorie : Automatisation, Ansible

    Aurelie Blondel Nguedajang Kamgang

    Ingénieur DevOps
    blondelle aurelie nguedjang kamgang | LinkedIn