TL;DR

  • Molecule proporciona testing automatizado para roles de Ansible con contenedores Docker, escenarios multi-plataforma y verificaciones de idempotencia integradas
  • El ciclo de vida de testing (create → converge → idempotence → verify → destroy) detecta deriva de configuración y tareas no idempotentes antes de producción
  • Usa Docker para iteración rápida durante desarrollo; cambia a Vagrant solo cuando necesites probar parámetros del kernel o características específicas de systemd

Ideal para: Equipos con 5+ roles de Ansible que quieren infraestructura reproducible e integración CI/CD No recomendado si: Solo tienes playbooks simples (ansible-lint puede ser suficiente) Tiempo de lectura: 20 minutos

Cuando tus playbooks de Ansible se despliegan en producción, ¿qué tan seguro estás de que funcionarán correctamente? Aquí es donde entra Molecule—un framework de testing diseñado específicamente para roles de Ansible que transforma el desarrollo de infraestructura de “funcionó en mi máquina” a “está probado en Ubuntu 20.04, 22.04 y Debian 11.”

En este tutorial, aprenderás todo desde testing básico de roles hasta validaciones complejas de múltiples escenarios con integración CI/CD. Ya sea que estés gestionando un puñado de servidores u orquestando miles de nodos, Molecule transformará cómo desarrollas y mantienes tu infraestructura como código.

El testing de infraestructura como código es parte de un ecosistema más amplio de prácticas DevOps. Si estás trabajando con otras herramientas de IaC, te recomendamos explorar nuestras estrategias de testing y validación de Terraform. Para entender mejor los entornos contenedorizados donde Molecule ejecuta sus pruebas, consulta nuestra guía sobre contenedorización para testing. Además, integrar estas pruebas en tu flujo de trabajo automatizado es esencial—aprende más en nuestra guía de optimización de pipelines CI/CD para equipos QA.

Enfoques Asistidos por IA

Los asistentes de IA modernos pueden acelerar el desarrollo y depuración de flujos de trabajo de Molecule. Aquí hay prompts prácticos para tareas comunes:

Generar tests verify.yml desde tareas del role:

Analiza el tasks/main.yml de este role de Ansible y genera tests
comprehensivos para verify.yml de Molecule. Para cada tarea, crea
aserciones que verifiquen:

1. Estados de instalación de paquetes
2. Estado de servicios (running/enabled)
3. Existencia y permisos de archivos
4. Validación de contenido de configuración
5. Estados de puertos escuchando

Tareas del role:
[pega tu tasks/main.yml]

Depurar fallos de idempotencia:

Mi test de idempotencia de Molecule muestra estas tareas como "changed"
en la segunda ejecución:
[pega la salida de las tareas]

Explica por qué cada tarea no es idempotente y proporciona alternativas
idempotentes usando los módulos apropiados de Ansible (lineinfile,
template, blockinfile, etc.)

Crear escenarios multi-plataforma:

Genera una configuración molecule.yml que pruebe mi role en:

- Ubuntu 20.04, 22.04 y 24.04
- Debian 11 y 12
- Rocky Linux 8 y 9

Incluye:

- Imágenes Docker apropiadas con soporte systemd
- Variables específicas por plataforma para diferencias de gestor de paquetes
- Sugerencias de ejecución paralela para optimización en CI

Generar tests Testinfra desde verify.yml existente:

Convierte estas aserciones de verify.yml de Ansible a tests de Python
con Testinfra. Mantén la misma cobertura de tests pero usa la sintaxis
más Pythonica de Testinfra. Incluye fixtures apropiados y parametrización
donde corresponda.

verify.yml actual:
[pega tu verify.yml]

Integración de pipeline CI/CD:

Genera un workflow de GitHub Actions para mi role de Ansible probado
con Molecule que:

1. Ejecute ansible-lint y yamllint
2. Pruebe en matriz de Ubuntu y Debian
3. Pruebe múltiples escenarios de Molecule
4. Cachee dependencias de pip entre ejecuciones
5. Publique en Ansible Galaxy al hacer push de tags

Estructura actual del role: [describe tu role]

Cuándo Usar Molecule

Framework de Decisión de Migración

Tu SituaciónRecomendaciónPor qué
1-3 playbooks simples, sin rolesQuedarte con ansible-lintEl overhead no justifica el tiempo de configuración
5+ roles, desarrollador individualEmpezar con MoleculeROI en detectar errores antes de producción
Equipo de 3+, roles compartidosMolecule + CI obligatorioPreviene problemas de “funciona en mi máquina”
Roles de infraestructura críticaMolecule + multi-escenarioProbar upgrades, casos edge, rollbacks
Publicando en Ansible GalaxyMolecule obligatorioExpectativa de la comunidad, genera confianza

Considera Molecule Cuando

  • Tienes roles reutilizables: Molecule brilla al probar roles que se despliegan en múltiples proyectos o entornos
  • Necesitas soporte multi-OS: Probar en Ubuntu, Debian y RHEL simultáneamente detecta problemas específicos de OS temprano
  • Existe integración CI/CD: Testing automatizado en cada commit previene regresiones
  • Colaboración en equipo: Múltiples ingenieros modificando los mismos roles necesitan validación consistente
  • Requisitos de compliance: Resultados de tests auditables prueban que la infraestructura cumple estándares

Considera Alternativas Cuando

  • Playbooks únicos: Scripts simples que se ejecutan una vez no necesitan el overhead
  • Aprendiendo lo básico de Ansible: Enfócate en fundamentos de Ansible primero antes de agregar complejidad de testing
  • Roles extremadamente simples: Un role que instala un paquete podría estar sobre-probado con Molecule
  • Testing a nivel de kernel necesario: Vagrant o testing bare-metal puede ser más apropiado para módulos de kernel, namespaces de red o características específicas de systemd
  • CI con recursos limitados: Los contenedores de Molecule agregan overhead; ansible-lint solo puede ser suficiente para validación simple

Prerequisitos

Antes de sumergirte en Molecule, asegúrate de tener configurado lo siguiente:

Herramientas Requeridas:

  • Python 3.8 o superior
  • Ansible 2.10 o superior
  • Docker (para testing basado en contenedores)
  • pip (gestor de paquetes de Python)

Requisitos de Conocimiento:

  • Experiencia básica con Ansible (roles, tareas, handlers)
  • Familiaridad con sintaxis YAML
  • Comprensión de conceptos de Docker
  • Competencia en línea de comandos

Configuración del Entorno: Recomiendo crear un entorno virtual de Python dedicado para evitar conflictos de dependencias:

python3 -m venv molecule-env
source molecule-env/bin/activate  # En Windows: molecule-env\Scripts\activate

Paso 1: Instalar Molecule

La instalación de Molecule es directa con pip. Necesitarás instalar Molecule junto con el driver de Docker, que usaremos para nuestros escenarios de testing.

# Instalar Molecule con soporte para Docker
pip install "molecule[docker,lint]"

# Verificar instalación
molecule --version

Salida Esperada:

molecule 5.0.1 using python 3.11
    ansible:2.15.4
    default:5.0.1 from molecule
    docker:2.1.0 from molecule_plugins.docker

La instalación incluye varios componentes:

  • Core de Molecule: El framework de testing en sí
  • Driver de Docker: Habilita testing basado en contenedores
  • Herramientas de lint: Ansible-lint y yamllint para calidad de código

Punto de Verificación: Ejecuta molecule --version y confirma que todos los componentes estén instalados. Si falta el driver de Docker, reinstala con el extra [docker].

Paso 2: Inicializar un Nuevo Role

Vamos a crear un ejemplo práctico: un role de servidor web Nginx. Molecule se integra perfectamente con la estructura de roles de Ansible Galaxy.

# Crear un nuevo role con testing de Molecule incorporado
molecule init role nginx --driver-name docker

# Navegar al directorio del role
cd nginx

Este comando genera una estructura completa de role:

nginx/
├── defaults/
│   └── main.yml
├── files/
├── handlers/
│   └── main.yml
├── meta/
│   └── main.yml
├── molecule/
│   └── default/
│       ├── converge.yml
│       ├── molecule.yml
│       └── verify.yml
├── tasks/
│   └── main.yml
├── templates/
├── tests/
└── vars/
    └── main.yml

Directorios Clave:

  • molecule/default/: Contiene la configuración de tu escenario de testing
  • tasks/main.yml: Donde van tus tareas de Ansible
  • handlers/main.yml: Para reinicios de servicios y notificaciones

Paso 3: Entender la Estructura de Molecule

El directorio molecule/default/ contiene tres archivos críticos:

molecule.yml - El archivo de configuración principal:

---
dependency:
  name: galaxy
driver:
  name: docker
platforms:

  - name: instance
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible

Desglose de Configuración:

  • dependency: Gestiona dependencias de roles de Ansible Galaxy
  • driver: Especifica Docker para crear instancias de prueba
  • platforms: Define entornos de prueba (OS, imagen, recursos)
  • provisioner: Usa Ansible para aplicar tu role
  • verifier: Ejecuta tests de verificación después de la convergencia

converge.yml - Aplica tu role a las instancias de prueba:

---
- name: Converge
  hosts: all
  become: true
  tasks:

    - name: "Include nginx"
      include_role:
        name: "nginx"

verify.yml - Contiene aserciones para validar el comportamiento del role:

---
- name: Verify
  hosts: all
  gather_facts: false
  tasks:

    - name: Example assertion
      ansible.builtin.assert:
        that: true

Paso 4: Escribir tu Primera Prueba

Vamos a construir un role funcional de Nginx con pruebas apropiadas. Comienza definiendo las tareas del role.

tasks/main.yml:

---
# Instalar servidor web Nginx
- name: Install Nginx package
  ansible.builtin.apt:
    name: nginx
    state: present
    update_cache: yes
  notify: Start nginx

- name: Ensure Nginx is started and enabled
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: yes

- name: Deploy custom index.html
  ansible.builtin.copy:
    content: |
      <html>
      <head><title>Ansible Managed</title></head>
      <body><h1>Deployed with Ansible</h1></body>
      </html>
    dest: /var/www/html/index.html
    owner: www-data
    group: www-data
    mode: '0644'

handlers/main.yml:

---
- name: Start nginx
  ansible.builtin.service:
    name: nginx
    state: started

Ahora crea pruebas de verificación significativas en molecule/default/verify.yml:

---
- name: Verify
  hosts: all
  gather_facts: true
  tasks:

    - name: Check if Nginx is installed
      ansible.builtin.package_facts:
        manager: auto

    - name: Assert Nginx package is present
      ansible.builtin.assert:
        that:

          - "'nginx' in ansible_facts.packages"
        fail_msg: "Nginx package is not installed"
        success_msg: "Nginx package is correctly installed"

    - name: Check if Nginx service is running
      ansible.builtin.service_facts:

    - name: Assert Nginx service is active
      ansible.builtin.assert:
        that:

          - "ansible_facts.services['nginx.service'].state == 'running'"
          - "ansible_facts.services['nginx.service'].status == 'enabled'"
        fail_msg: "Nginx service is not running or not enabled"
        success_msg: "Nginx service is active and enabled"

    - name: Check if Nginx is listening on port 80
      ansible.builtin.wait_for:
        port: 80
        timeout: 5

    - name: Verify custom index.html content
      ansible.builtin.uri:
        url: http://localhost
        return_content: yes
      register: webpage

    - name: Assert webpage contains expected content
      ansible.builtin.assert:
        that:

          - "'Deployed with Ansible' in webpage.content"
        fail_msg: "Custom index.html was not deployed correctly"
        success_msg: "Custom index.html is correctly deployed"

Paso 5: Ejecutar las Pruebas

Molecule proporciona un ciclo de vida de testing completo. Aquí está cómo ejecutar las pruebas:

# Ejecutar la secuencia completa de testing
molecule test

# O ejecutar pasos individuales:
molecule create    # Crear instancias de prueba
molecule converge  # Aplicar tu role
molecule verify    # Ejecutar pruebas de verificación
molecule destroy   # Limpiar instancias

La Secuencia Completa de Testing:

Cuando ejecutas molecule test, Molecule ejecuta estas fases:

  1. Dependency: Instalar dependencias de roles desde Ansible Galaxy
  2. Lint: Verificar sintaxis y mejores prácticas
  3. Cleanup: Eliminar instancias de prueba anteriores
  4. Destroy: Asegurar estado limpio
  5. Create: Crear contenedores de prueba
  6. Prepare: Pasos opcionales de pre-configuración
  7. Converge: Aplicar tu role
  8. Idempotence: Re-ejecutar para asegurar que no ocurran cambios
  9. Verify: Ejecutar pruebas de aserción
  10. Destroy: Limpiar recursos

Salida Esperada (abreviada):

--> Test matrix

└── default
    ├── dependency
    ├── cleanup
    ├── destroy
    ├── create
    ├── prepare
    ├── converge
    ├── idempotence
    ├── verify
    └── destroy

--> Scenario: 'default'
--> Action: 'converge'

    PLAY [Converge] ********************************************************

    TASK [Include nginx] ***************************************************
    included: /Users/user/nginx/tasks/main.yml

    TASK [Install Nginx package] *******************************************
    changed: [instance]

    TASK [Ensure Nginx is started and enabled] *****************************
    changed: [instance]

    PLAY RECAP *************************************************************
    instance: ok=3 changed=2 unreachable=0 failed=0

--> Scenario: 'default'
--> Action: 'verify'

    TASK [Assert Nginx service is active] **********************************
    ok: [instance] => {
        "msg": "Nginx service is active and enabled"
    }

Consejo de Flujo de Desarrollo: Durante el desarrollo, usa molecule converge repetidamente para aplicar cambios sin destruir instancias. Solo ejecuta el molecule test completo cuando estés listo para validar todo.

Paso 6: Probar con Diferentes Escenarios

La infraestructura del mundo real rara vez se ejecuta en un solo OS. Los escenarios de Molecule te permiten probar en múltiples plataformas simultáneamente.

Crea un escenario multi-plataforma modificando molecule/default/molecule.yml:

---
dependency:
  name: galaxy
driver:
  name: docker
platforms:

  - name: ubuntu-20-04
    image: geerlingguy/docker-ubuntu2004-ansible:latest
    pre_build_image: true
  - name: ubuntu-22-04
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    pre_build_image: true
  - name: debian-11
    image: geerlingguy/docker-debian11-ansible:latest
    pre_build_image: true
provisioner:
  name: ansible
  playbooks:
    converge: converge.yml
    verify: verify.yml
verifier:
  name: ansible

Crear Escenarios Nombrados:

También puedes crear escenarios de prueba completamente separados para diferentes casos de uso:

# Crear un escenario tipo producción
molecule init scenario production

# Crear un escenario para probar actualizaciones
molecule init scenario upgrade

Esto crea:

molecule/
├── default/
│   ├── converge.yml
│   ├── molecule.yml
│   └── verify.yml
├── production/
│   ├── converge.yml
│   ├── molecule.yml
│   └── verify.yml
└── upgrade/
    ├── converge.yml
    ├── molecule.yml
    └── verify.yml

Ejecutar Escenarios Específicos:

# Probar solo el escenario de producción
molecule test -s production

# Converger múltiples escenarios
molecule converge --all

Paso 7: Integración CI/CD

Molecule se integra perfectamente con pipelines de integración continua. Aquí está cómo configurarlo con GitHub Actions.

.github/workflows/molecule.yml:

---
name: Molecule Tests

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        scenario:

          - default
          - production

    steps:

      - name: Check out code
        uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install "molecule[docker,lint]"
          pip install ansible

      - name: Run Molecule tests
        run: molecule test -s ${{ matrix.scenario }}

Configuración de GitLab CI (.gitlab-ci.yml):

---
stages:

  - test

molecule:
  stage: test
  image: geerlingguy/docker-ubuntu2204-ansible:latest
  services:

    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  before_script:

    - pip install "molecule[docker,lint]"
  script:

    - molecule test --all
  only:

    - merge_requests
    - main

Punto de Verificación: Empuja tu role a un repositorio Git y verifica que el pipeline de CI se ejecute exitosamente. Verifica que todos los escenarios pasen y que el pipeline falle en caso de errores de prueba.

Ejemplos del Mundo Real

Ejemplo 1: Probar un Role de Servidor Web

Vamos a extender nuestro role de Nginx con configuración SSL y virtual hosts.

tasks/main.yml (extendido):

---
- name: Install Nginx and SSL dependencies
  ansible.builtin.apt:
    name:

      - nginx
      - openssl
    state: present
    update_cache: yes

- name: Create SSL directory
  ansible.builtin.file:
    path: /etc/nginx/ssl
    state: directory
    mode: '0755'

- name: Generate self-signed SSL certificate
  ansible.builtin.command:
    cmd: >
      openssl req -x509 -nodes -days 365 -newkey rsa:2048
      -keyout /etc/nginx/ssl/nginx.key
      -out /etc/nginx/ssl/nginx.crt
      -subj "/C=US/ST=State/L=City/O=Org/CN=localhost"
    creates: /etc/nginx/ssl/nginx.crt

- name: Deploy SSL virtual host configuration
  ansible.builtin.template:
    src: vhost-ssl.conf.j2
    dest: /etc/nginx/sites-available/default
    mode: '0644'
  notify: Reload nginx

- name: Ensure Nginx is started
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: yes

templates/vhost-ssl.conf.j2:

server {
    listen 80;
    listen 443 ssl;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

molecule/default/verify.yml (extendido):

---
- name: Verify
  hosts: all
  gather_facts: true
  tasks:

    - name: Check SSL certificate exists
      ansible.builtin.stat:
        path: /etc/nginx/ssl/nginx.crt
      register: ssl_cert

    - name: Assert SSL certificate is present
      ansible.builtin.assert:
        that:

          - ssl_cert.stat.exists
          - ssl_cert.stat.mode == '0644'

    - name: Verify Nginx is listening on HTTPS
      ansible.builtin.wait_for:
        port: 443
        timeout: 5

    - name: Test HTTPS connection
      ansible.builtin.uri:
        url: https://localhost
        validate_certs: no
        return_content: yes
      register: https_response

    - name: Assert HTTPS is working
      ansible.builtin.assert:
        that:

          - https_response.status == 200

Ejemplo 2: Probar Configuración de Base de Datos

Aquí está cómo probar un role de PostgreSQL con Molecule.

molecule/default/molecule.yml:

---
platforms:

  - name: postgres-instance
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    pre_build_image: true
    volumes:

      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    privileged: true
    command: /lib/systemd/systemd

tasks/main.yml (role de PostgreSQL):

---
- name: Install PostgreSQL
  ansible.builtin.apt:
    name:

      - postgresql
      - postgresql-contrib
      - python3-psycopg2
    state: present
    update_cache: yes

- name: Ensure PostgreSQL is started
  ansible.builtin.service:
    name: postgresql
    state: started
    enabled: yes

- name: Create application database
  become_user: postgres
  community.postgresql.postgresql_db:
    name: appdb
    state: present

- name: Create database user
  become_user: postgres
  community.postgresql.postgresql_user:
    name: appuser
    password: "{{ db_password | default('changeme') }}"
    db: appdb
    priv: ALL
    state: present

molecule/default/verify.yml:

---
- name: Verify
  hosts: all
  become: true
  tasks:

    - name: Check PostgreSQL service status
      ansible.builtin.service_facts:

    - name: Assert PostgreSQL is running
      ansible.builtin.assert:
        that:

          - "ansible_facts.services['postgresql.service'].state == 'running'"

    - name: Verify database exists
      become_user: postgres
      community.postgresql.postgresql_query:
        db: appdb
        query: SELECT 1
      register: db_check

    - name: Assert database is accessible
      ansible.builtin.assert:
        that:

          - db_check is succeeded

    - name: Test database connection with user
      become_user: postgres
      community.postgresql.postgresql_query:
        db: appdb
        login_user: appuser
        query: CREATE TABLE test (id serial PRIMARY KEY, name varchar(50))
      register: table_creation

    - name: Assert user has correct privileges
      ansible.builtin.assert:
        that:

          - table_creation is succeeded

Ejemplo 3: Probar Hardening de Seguridad

Los roles de seguridad requieren pruebas exhaustivas para asegurar que no rompan funcionalidad.

molecule/default/verify.yml (hardening de seguridad):

---
- name: Verify Security Hardening
  hosts: all
  gather_facts: true
  tasks:

    - name: Check if SSH password authentication is disabled
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^PasswordAuthentication'
        line: 'PasswordAuthentication no'
        state: present
      check_mode: yes
      register: ssh_config

    - name: Assert SSH is properly configured
      ansible.builtin.assert:
        that:

          - not ssh_config.changed
        fail_msg: "SSH password authentication is not disabled"

    - name: Verify firewall is active
      ansible.builtin.command: ufw status
      register: ufw_status
      changed_when: false

    - name: Assert firewall is enabled
      ansible.builtin.assert:
        that:

          - "'Status: active' in ufw_status.stdout"

    - name: Check for unattended upgrades
      ansible.builtin.stat:
        path: /etc/apt/apt.conf.d/50unattended-upgrades
      register: unattended_upgrades

    - name: Assert automatic updates are configured
      ansible.builtin.assert:
        that:

          - unattended_upgrades.stat.exists

    - name: Verify root login is disabled
      ansible.builtin.command: passwd -S root
      register: root_status
      changed_when: false

    - name: Assert root account is locked
      ansible.builtin.assert:
        that:

          - "'L' in root_status.stdout"
        fail_msg: "Root account is not locked"

Mejores Prácticas

Organización de Pruebas

Mantén las pruebas enfocadas y modulares:

# Mal: Un archivo de verificación gigante
verify.yml  # 500 líneas de pruebas

# Bien: Tareas de verificación separadas
molecule/default/
├── molecule.yml
├── converge.yml
├── verify.yml
└── verify/
    ├── test_installation.yml
    ├── test_configuration.yml
    ├── test_security.yml
    └── test_networking.yml

El verify.yml principal incluye pruebas específicas:

---
- name: Verify
  hosts: all
  tasks:

    - name: Run installation tests
      include_tasks: verify/test_installation.yml

    - name: Run configuration tests
      include_tasks: verify/test_configuration.yml

    - name: Run security tests
      include_tasks: verify/test_security.yml

Gestión de Escenarios

Usa escenarios estratégicamente:

  • default: Pruebas básicas de funcionalidad
  • production: Entorno tipo producción con todas las características
  • upgrade: Probar rutas de actualización desde versiones anteriores
  • multi-node: Pruebas de sistemas distribuidos

No crees escenarios para variaciones menores. En su lugar, usa variables:

# molecule/default/converge.yml
- name: Converge
  hosts: all
  vars:
    # Sobrescribe estas en escenarios específicos
    enable_ssl: "{{ scenario_ssl | default(true) }}"
    enable_monitoring: "{{ scenario_monitoring | default(false) }}"
  roles:

    - nginx

Pruebas de Idempotencia

La idempotencia es crítica: ejecutar tu role múltiples veces no debería causar cambios después de la primera ejecución.

Molecule prueba esto automáticamente. Asegúrate de que tus tareas sean idempotentes:

# Mal: Siempre reporta cambios
- name: Configure application
  ansible.builtin.shell: echo "config=true" >> /etc/app.conf

# Bien: Configuración idempotente
- name: Configure application
  ansible.builtin.lineinfile:
    path: /etc/app.conf
    line: "config=true"
    create: yes

Monitorea la salida de la prueba de idempotencia:

PLAY RECAP *****************************************************************
instance: ok=10 changed=0 unreachable=0 failed=0

Si changed es mayor que 0 en la segunda ejecución, tienes problemas de idempotencia.

Docker vs Vagrant

Docker (Recomendado para la mayoría de casos):

  • Rápido: Los contenedores inician en segundos
  • Eficiente en recursos: Ejecuta muchas instancias simultáneamente
  • Amigable con CI: Funciona en la mayoría de entornos de CI
  • Limitaciones: No puede probar módulos del kernel, peculiaridades de systemd, o cualquier cosa que requiera VM completa

Vagrant (Para escenarios complejos):

  • VMs completas: Sistema operativo completo
  • Systemd: Soporte completo del sistema init
  • Testing de kernel: Puede probar parámetros y módulos del kernel
  • Compensaciones: Más lento (minutos para iniciar), pesado en recursos, más difícil en CI

Cuándo usar Vagrant:

# molecule/vagrant/molecule.yml
---
driver:
  name: vagrant
platforms:

  - name: ubuntu-vm
    box: ubuntu/jammy64
    memory: 2048
    cpus: 2
provisioner:
  name: ansible

Usa Vagrant cuando pruebes roles que:

  • Modifican parámetros del kernel (sysctl)
  • Requieren características específicas de systemd
  • Instalan módulos del kernel
  • Necesitan stack de red completo

Errores Comunes

Limitaciones de Contenedores

Problema: Systemd no funciona apropiadamente en contenedores estándar.

Solución: Usa imágenes pre-construidas con soporte para systemd:

platforms:

  - name: instance
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    volumes:

      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    privileged: true
    command: /lib/systemd/systemd

Las imágenes Docker de Jeff Geerling están construidas específicamente para testing de Ansible con systemd funcional.

Problemas de Privilegios

Problema: Las tareas fallan con errores de permisos.

Solución: Usa become apropiadamente en tu playbook de convergencia:

# molecule/default/converge.yml
---
- name: Converge
  hosts: all
  become: true  # Ejecutar tareas con sudo
  tasks:

    - name: Include role
      include_role:
        name: nginx

Evita requerir become: yes en el role mismo cuando sea posible. Deja que el usuario decida la escalada de privilegios.

Gestión de Dependencias

Problema: El role depende de otros roles, pero no están disponibles durante el testing.

Solución: Define dependencias en meta/main.yml:

# meta/main.yml
---
dependencies:

  - role: geerlingguy.security
  - role: geerlingguy.firewall

Molecule instala estas automáticamente antes de probar si tienes habilitado el gestor de dependencias de Galaxy:

# molecule/default/molecule.yml
dependency:
  name: galaxy
  options:
    role-file: requirements.yml

Crea requirements.yml para dependencias externas:

# requirements.yml
---
roles:

  - name: geerlingguy.security
    version: 2.3.0
  - name: geerlingguy.firewall
    version: 3.1.0

Inestabilidad de Pruebas

Problema: Las pruebas ocasionalmente fallan sin razón aparente.

Causas comunes:

  • Timeouts de red
  • Condiciones de carrera en el inicio de servicios
  • Tiempos de espera insuficientes

Solución: Agrega esperas y reintentos apropiados:

- name: Wait for service to be ready
  ansible.builtin.wait_for:
    port: 80
    delay: 2
    timeout: 30

- name: Check endpoint with retry
  ansible.builtin.uri:
    url: http://localhost/health
  register: health_check
  until: health_check.status == 200
  retries: 5
  delay: 3

Herramientas e Integración

Testinfra para Verificación

Aunque Molecule usa Ansible para verificación por defecto, también puedes usar Testinfra (testing basado en Python):

pip install testinfra

molecule/default/tests/test_default.py:

import os
import testinfra.utils.ansible_runner

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ['MOLECULE_INVENTORY_FILE']
).get_hosts('all')

def test_nginx_is_installed(host):
    nginx = host.package("nginx")
    assert nginx.is_installed

def test_nginx_running_and_enabled(host):
    nginx = host.service("nginx")
    assert nginx.is_running
    assert nginx.is_enabled

def test_nginx_listening(host):
    assert host.socket("tcp://0.0.0.0:80").is_listening

def test_index_html_content(host):
    content = host.file("/var/www/html/index.html").content_string
    assert "Deployed with Ansible" in content

Configurar Testinfra en molecule.yml:

verifier:
  name: testinfra
  options:
    v: 1

Integración GitLab/GitHub CI

GitHub Actions avanzado con testing de matriz:

---
name: Ansible Role Testing

on:
  push:
    branches: [main]
  pull_request:
  schedule:

    - cron: '0 0 * * 0'  # Semanal

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:

      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: pip install ansible-lint yamllint
      - name: Lint Ansible role
        run: ansible-lint .
      - name: Lint YAML files
        run: yamllint .

  test:
    needs: lint
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        distro:

          - ubuntu2004
          - ubuntu2204
          - debian11
        scenario:

          - default
          - production
    steps:

      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install Molecule
        run: pip install "molecule[docker,lint]" ansible
      - name: Run Molecule test
        run: molecule test -s ${{ matrix.scenario }}
        env:
          PY_COLORS: '1'
          ANSIBLE_FORCE_COLOR: '1'
          MOLECULE_DISTRO: ${{ matrix.distro }}

Integración con Ansible Galaxy

Al publicar roles en Ansible Galaxy, incluye pruebas de Molecule para aumentar credibilidad:

# .github/workflows/release.yml
---
name: Release to Galaxy

on:
  push:
    tags:

      - 'v*'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:

      - uses: actions/checkout@v3
      - name: Test with Molecule
        run: |
          pip install "molecule[docker,lint]"
          molecule test

  release:
    needs: test
    runs-on: ubuntu-latest
    steps:

      - uses: actions/checkout@v3
      - name: Release to Galaxy
        uses: robertdebock/galaxy-action@1.2.0
        with:
          galaxy_api_key: ${{ secrets.GALAXY_API_KEY }}

Enlaza a tu badge de CI en README.md:

# Ansible Role: Nginx

[![CI](https://github.com/username/ansible-role-nginx/workflows/CI/badge.svg)](https://github.com/username/ansible-role-nginx/actions)
[![Ansible Galaxy](https://img.shields.io/badge/galaxy-username.nginx-blue.svg)](https://galaxy.ansible.com/username/nginx)

Probado con Molecule en:

- Ubuntu 20.04
- Ubuntu 22.04
- Debian 11

Conclusión

Molecule transforma el desarrollo de roles de Ansible de un proceso manual y propenso a errores en un flujo de trabajo robusto y automatizado. Al implementar estrategias de testing comprehensivas—desde verificaciones básicas de funcionalidad hasta escenarios multi-plataforma—aseguras que tu código de infraestructura sea confiable, mantenible y listo para producción.

Puntos Clave:

  • Siempre prueba tus roles en múltiples sistemas operativos y escenarios
  • Aprovecha el testing de idempotencia para prevenir deriva de configuración
  • Integra Molecule en tu pipeline de CI/CD para validación continua
  • Usa Docker para velocidad durante desarrollo, Vagrant para testing complejo a nivel de sistema
  • Escribe pruebas de verificación claras y enfocadas que actúen como documentación viva

Próximos Pasos:

  1. Explora escenarios avanzados: Implementa testing multi-nodo para sistemas distribuidos (aprende más en nuestra guía de Mejores Prácticas de Gestión de Contenedores Docker)
  2. Integra con tu pipeline de CI/CD: Agrega pruebas de Molecule a tus pipelines existentes (revisa Estrategias de Optimización de Pipeline CI/CD)
  3. Contribuye a la comunidad: Comparte tus roles probados en Ansible Galaxy
  4. Aprende herramientas complementarias de testing: Explora Testinfra, InSpec y ServerSpec para validación más profunda de infraestructura

Para más sobre automatización de infraestructura y mejores prácticas de DevOps, explora nuestra guía completa sobre Infraestructura como Código con Terraform o sumérgete en Estrategias de Despliegue en Kubernetes para testing de infraestructura cloud-native.

Recursos Adicionales:

Comienza a probar tu código de infraestructura hoy—tu yo futuro (y tu equipo) te lo agradecerán cuando los despliegues se vuelvan predecibles, confiables y libres de estrés.

Ver También

Recursos Oficiales