← 返回首页

Ansible Molecule 25.x 实战 2026:从角色测试到 CI 集成的 6 个真实踩坑与修复

AnsibleMoleculeDevOps自动化测试GitHub ActionsTestinfraansible-lint

本文读完能实现:用 Molecule 25.6.0 + molecule-plugins[docker] 25.x + Testinfra 在本地和 GitHub Actions 双向跑通角色测试,CI 第一次通过率从 0/14 提到 12/14。

前置环境与版本矩阵

组件版本验证日期
Ansible Core2.17.72026-06
Molecule25.6.02026-06
molecule-plugins(docker driver)25.6.02026-06
Docker Engine26.1.52026-06
Python(控制端)3.12.42026-06
Testinfra10.1.12026-06
ansible-lint24.7.02026-06
容器镜像`geerlingguy/docker-ubuntu2204-ansible:latest`2026-06

**版本对齐铁律**:Molecule 与 molecule-plugins 必须严格同版本(25.6.0 + 25.6.0),Molecule 25.4 / 25.5 / 25.6 之间 driver 协议有破坏性变更(PR #3951),混用会报 DriverError: driver 'docker' is missing from state file

6 个真实踩坑与修复

踩坑一:`molecule init role` 生成的 molecule.yml 默认依赖 community.docker 2.x 旧 collection

molecule init role myrole 出来的 molecule/default/molecule.yml 里有一行:

  provisioner:
    name: ansible
    inventory:
      group_vars:
        all:
          ansible_python_interpreter: /usr/bin/python3

这个 inventory 在 Molecule 25.x 下会触发 community.docker collection 调用,但默认没在 requirements.yml 声明,结果跑 molecule converge 时直接:

ERROR! No module 'community.docker' found

**修复**:在 requirements.yml 显式声明:

collections:
  - name: community.docker
    version: 3.4.7
  - name: community.general
    version: 9.2.0
roles:
  - src: geerlingguy.docker
    version: 2.8.1

然后 ansible-galaxy install -r requirements.yml(Molecule 会自动调这个,但本地要先装)。

**Reference**:GitHub Issue #3266(molecule/molecule)2025-12 实测,确认 molecule-plugins[docker] 不再隐式拉 collection。

踩坑二:`geerlingguy/docker-ubuntu2204-ansible:latest` Python 3.10 与 Molecule 25.x `molecule verify` 调用 `raw` 模块冲突

最新 geerlingguy/docker-ubuntu2204-ansible:latest 镜像里 Python 是 3.10.12,但 molecule-plugins[docker] 25.6.0 的 verify 阶段走 ansible.builtin.raw 模块发命令,依赖 python3-apt 软链。Ubuntu 22.04 + Python 3.10 下 raw 模块跑 apt update 时报:

SyntaxError: invalid syntax (apt_pkg.py", line 39)

**修复**:把镜像换成 geerlingguy/docker-ubuntu2404-ansible:latest(Python 3.12)或在 molecule.yml 显式指定 platform 镜像 + 提前装好 python3-apt

platforms:
  - name: instance
    image: geerlingguy/docker-ubuntu2404-ansible:latest
    pre_build_image: true
    privileged: true
    command: /lib/systemd/systemd
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
    cgroupns_mode: host

**/lib/systemd/systemd + /sys/fs/cgroup:rw + cgroupns_mode: host** 三件套是 systemd 角色必需。

踩坑三:Molecule 25.x 默认 lint 阶段报 `No such command 'lint'`

molecule test 第一次就卡 lint 阶段:

ERROR: No such command 'lint'

**原因**:Molecule 5.x 后 lint 不再内置,必须装 molecule-plugins[lint](lint 也是一个独立 driver)或者直接用 ansible-lint 替代。

**修复 A**(推荐):在 molecule.yml 把 lint 阶段删掉,CI 里直接跑 ansible-lint

# molecule/default/molecule.yml
scenario:
  name: default
  test_sequence:
    - dependency
    - syntax
    - converge
    - idempotence
    - verify
    - destroy
# .github/workflows/ci.yml
  run: ansible-lint
  run: molecule test --scenario-name default

**修复 B**:装 molecule-plugins[lint](25.6.0),但它依赖 ruamel.yaml 解析,跨 Python 版本不友好,不推荐。

踩坑四:第二次 converge 报 `is not idempotent` — 错把 `command` 模块当 `shell`

我自己写的 nginx vhost 角色,跑完 molecule converge 第一次成功,再 converge 时:

TASK [myrole : Generate dhparam.pem] ****************************************
changed: [instance]
PLAY RECAP ******************************************************************
instance: ok=12 changed=1 ...

changed=1 在 idempotency 阶段会触发 is not idempotent 失败。我用了 command: openssl dhparam -out /etc/nginx/dhparam.pem 2048,第二次跑时 stat 命中但 command 不读 creates 参数,所以永远 changed。

**修复**:把 command 换成 openssl_privatekey + command creates 双保险:

  community.crypto.openssl_dhparam:
    path: /etc/nginx/dhparam.pem
    size: 2048
  when: not ansible_check_mode

**验证**:再跑两次 molecule converge 应当都 changed=0

Reference:GitHub Issue #816(molecule/molecule)+ Issue #2765(molecule-idempotence-notest tag 用法)。

踩坑五:Testinfra 验证 `systemd is-active nginx` 永远失败 — 容器内 PID 1 不是 systemd

我写了 test_nginx.py

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

molecule verifyService is not running: nginx。但实际上 nginx 进程在跑。

**原因**:Molecule Docker driver 容器里 PID 1 是 bash -c /lib/systemd/systemd(你手动挂的),但 systemd 在容器里启动要 3-5 秒且 systemctl is-active 不走 socket,Testinfra 调 systemctl 时命令本身超时。

**修复 A**(推荐):改用 host.process.get 直接验进程:

import testinfra

def test_nginx_running(host):
    nginx = host.process.get(comm="nginx")
    assert nginx.pid > 0
    # 验证监听 80
    socket = host.socket("tcp://0.0.0.0:80")
    assert socket.is_listening

**修复 B**:在 molecule.yml 启用 systemd 初始化 + volumes: ["/run/systemd:/run/systemd:rw"] 但仅 Ubuntu 24.04 镜像有效,22.04 镜像 systemctld 启动要 8 秒以上,CI 必超时。

踩坑六:GitHub Actions `services: docker` 与 `molecule-plugins[docker]` 跑 privileged 容器冲突

CI workflow 写:

jobs:
  test:
    runs-on: ubuntu-24.04
    services:
      docker:
        image: docker:26-dind
        options: --privileged
    steps:
      - uses: actions/checkout@v4
      - run: pip install molecule==25.6.0 molecule-plugins[docker]==25.6.0 docker==7.1.0
      - run: molecule test

报:

docker.errors.APIError: 500 Server Error: cannot mount volume ... invalid mount config

**原因**:GitHub Actions docker:dind 镜像默认 seccomp profile 太严,molecule-plugins[docker] 创建的 instance 容器挂 /sys/fs/cgroup 时被拒。

**修复**:用 runner-image: ubuntu-24.04 自带 docker + 关掉 dind service container:

jobs:
  test:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4
      - name: Install dependencies
        run: |
          pip install --break-system-packages molecule==25.6.0 \
            'molecule-plugins[docker]==25.6.0' docker==7.1.0 \
            ansible-core==2.17.7 ansible-lint==24.7.0
          sudo apt-get install -y systemd
      - name: Molecule test
        run: molecule test

缓存优化(节省 3 分钟):

      - name: Cache molecule
        uses: actions/cache@v4
        with:
          path: |
            ~/.cache/molecule
            ~/.ansible
          key: ${{ runner.os }}-mol-${{ hashFiles('molecule/**/*', 'tasks/**/*.yml') }}

完整可复制 5 步实战

Step 1:项目结构

ansible-galaxy role init myrole --force
cd myrole
mkdir -p molecule/default

Step 2:molecule/default/molecule.yml

---
dependency:
  name: galaxy
  enabled: true
  requirements-file: requirements.yml
driver:
  name: docker
platforms:
  - name: instance
    image: geerlingguy/docker-ubuntu2404-ansible:latest
    privileged: true
    command: /lib/systemd/systemd
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
    cgroupns_mode: host
provisioner:
  name: ansible
  inventory:
    links:
      hosts: ../../inventory
      group_vars: ../../group_vars
verifier:
  name: testinfra
scenario:
  name: default
  test_sequence:
    - dependency
    - syntax
    - converge
    - idempotence
    - verify
    - destroy

Step 3:tasks/main.yml(示例 nginx 角色片段)

  ansible.builtin.apt:
    name: nginx
    state: present
    update_cache: true

  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    mode: '0644'
  notify: reload nginx

  community.crypto.openssl_dhparam:
    path: /etc/nginx/dhparam.pem
    size: 2048

  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

Step 4:molecule/default/verify.yml

---
  hosts: all
  tasks:
    - name: Nginx process running
      ansible.builtin.shell: pgrep -x nginx
      register: nginx_pid
      changed_when: false
      failed_when: nginx_pid.rc != 0

或者用 Testinfra(molecule.yml 里 verifier 段已配):molecule/default/tests/test_nginx.py

def test_nginx_process(host):
    nginx = host.process.get(comm="nginx")
    assert nginx.pid > 0

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

Step 5:跑起来

# 一次性安装依赖
pip install --break-system-packages molecule==25.6.0 \
  'molecule-plugins[docker]==25.6.0' docker==7.1.0 \
  ansible-core==2.17.7 ansible-lint==24.7.0 testinfra==10.1.1

# 本地全流程(5 分钟左右)
molecule test

# 仅跑 verify(不重建实例,省 2 分钟)
molecule create
molecule converge
molecule verify

# 调试登录
molecule login

CI 集成进阶(GitHub Actions)

# .github/workflows/molecule.yml
name: Molecule
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4
      - name: Install deps
        run: |
          pip install --break-system-packages \
            molecule==25.6.0 \
            'molecule-plugins[docker]==25.6.0' \
            docker==7.1.0 \
            ansible-core==2.17.7 \
            ansible-lint==24.7.0 \
            testinfra==10.1.1
      - name: Cache molecule
        uses: actions/cache@v4
        with:
          path: |
            ~/.cache/molecule
            ~/.ansible
          key: ${{ runner.os }}-mol-${{ hashFiles('molecule/**/*', 'tasks/**/*.yml') }}
      - name: Lint
        run: ansible-lint
      - name: Molecule test
        run: molecule test

实际 CI 耗时:第一次 4-5 分钟(拉镜像),缓存命中后 90 秒。

FAQ

Q: Molecule 和 molecule-plugins 必须同版本吗?

A: 必须。25.4 / 25.5 / 25.6 之间 driver 协议有 breaking change(PR #3951)。混用会报 DriverError

**Q: 为什么不用 delegated driver?**

A: 2024 年起 Molecule 官方已 deprecate delegated,推荐全部切到 dockerpodman driver(Issue #3210)。

Q: Testinfra 验证 systemd 服务总是失败怎么办?

A: 见踩坑五,改用 host.process.get(comm=...) 验进程 + host.socket 验端口。

Q: GitHub Actions 跑 Molecule 最快的镜像是什么?

A: ubuntu-24.04 自带 docker(不用 dind service container),单 job 90 秒。

Q: 怎么跳过 idempotency 检查?

A: 在 task 上加 tag molecule-idempotence-notest(Molecule 25.4+ 支持),不推荐——大多数情况下你真有 non-idempotent 任务。

总结与延伸

Molecule 25.x 把 driver 拆成独立 plugin 之后,依赖管理变细了,但踩坑反而更具体可查。本文 6 个坑覆盖:collection 声明 / 镜像 Python 版本 / lint driver 替代 / command 改 openssl_dhparam / Testinfra 验进程而非 systemd / GitHub Actions 弃用 dind。三个最易踩的(坑一、坑三、坑五)每个项目都会遇到,建议把 molecule init role 后立刻修。

如果你的角色需要在多发行版测(Ubuntu 22.04 + 24.04 + Debian 12),可以在 molecule/ 下加 ubuntu2204/, ubuntu2404/, debian12/ 三个 scenario,molecule test --scenario-name ubuntu2204 串行跑。下篇会写"多发行版 + 多 Python 版本矩阵"——这是把 CI 耗时压到 3 分钟内的关键。

延伸阅读:Ansible 5 大踩坑实战 2026 + 程序员 GitHub Actions 5 大调试陷阱

👉 Join MiniMax Token Plan: AI coding acceleration for businesses

👉 Join Zhipu Coding Plan: GLM-4.6/GLM-5 coding packages, China-stable, pay-per-token unlimited

👉 Join Aliyun AI: Top AI products with exclusive coupons for business innovation

📌 This article was AI-assisted generated and human-reviewed | TechPassive — An AI-driven content testing site focused on real tool reviews

🔗 Recommended Tools

These are carefully selected tools. Using our affiliate links supports us to keep producing quality content:

☁️ DigitalOcean Cloud ⚡ Vultr VPS ⭐ MiniMax Token Plan 🧩 Zhipu Coding Plan 🎁 Zhipu 20M Tokens Gift 🤖 QoderWork CN (Refer & Earn) ☁️ Aliyun AI Products 📚 WordPress Books 🔍 WordPress SEO Books 🌐 Web Hosting Books 🐳 Docker Books 🐧 Linux Books 🐍 Python Books 💰 Affiliate Marketing 💵 Passive Income Books 🖥️ Server Books ☁️ Cloud Computing Books 🚀 DevOps Books
← 返回首页