我们希望听到您的声音!帮助我们深入了解 Ansible 生态系统现状。
参与 2024 年 Ansible 项目调查

使用 Molecule 和 Podman 开发和测试 Ansible 角色 - 第 1 部分

使用 Molecule 和 Podman 开发和测试 Ansible 角色 - 第 1 部分

Red Hat Ansible Automation Platform 的一大优势在于,其自动化描述语言不仅易于少数专门专家理解,而且几乎所有 IT 生态系统中的专业人员都能轻松掌握。这意味着所有 IT 专业人员都可以参与自动化,实现跨团队协作,并在组织内部真正推动自动化成为一种文化。由于有如此多的人参与自动化,因此深入测试自动化内容至关重要。因此,在开发新的 Ansible 内容(如 playbook、角色和集合)时,最好在测试环境中对其进行测试,然后再将其用于自动化生产基础设施。测试可确保自动化按设计运行,并避免日后出现意外情况。

测试自动化内容通常是一项挑战,因为它需要部署特定的测试基础设施,并设置测试条件以确保测试的相关性。Molecule 是一个完整的测试框架,可帮助您开发和测试 Ansible 角色,让您专注于内容本身,而不是管理测试基础设施。

根据其官方文档,Molecule 是一个

"旨在帮助开发和测试 Ansible 角色的项目。它提倡一种方法,这种方法可以带来一致地开发的角色,这些角色编写良好、易于理解和维护。"

Molecule 允许您使用多个实例测试您的角色,确保它在不同操作系统和虚拟化环境的组合中都能正常工作。如果没有它,您将不得不单独配置和维护一个测试环境。您还需要配置到这些实例的连接,并确保它们在每次测试之前都是干净且准备好的。Molecule 以自动化和可重复的方式为您管理这些方面。

在本系列的两篇文章中,我们将使用 Molecule 开发和测试一个新的 Ansible 角色。第一篇文章将指导您完成 Molecule 的安装和配置。在第 2 部分中,我们将使用 Molecule 来辅助角色开发。

如果此角色是集合的一部分,请使用此方法来开发和“单元”测试该角色。在以后的文章中,我们将了解如何使用 Molecule 在集合中运行集成测试。

Molecule 使用驱动程序来使用不同的技术(包括 Linux 容器、虚拟机和云提供商)配置测试实例。默认情况下,它预装了三个驱动程序:Docker 和 Podman 驱动程序用于管理容器,以及 Delegated 驱动程序,允许您自定义集成。其他提供商的驱动程序可以通过开源社区获得。

在本文中,我们将使用Podman驱动程序来使用 Linux 容器开发和测试一个新的角色。Podman 是一个轻量级的 Linux 容器引擎,它不需要运行守护进程,并且允许在“无根”模式下执行容器,以提高安全性。

通过将 Molecule 与 Podman 驱动程序结合使用,我们将从头开始开发和测试一个新的 Ansible 角色。此基本角色部署一个由 Apache Web 服务器支持的 Web 应用程序。它必须在 Red Hat Enterprise Linux (RHEL) 8 或 Ubuntu 20.04 操作系统上运行。

此示例显示了一个常见场景,其中角色需要在不同版本的操作系统上工作。使用 Podman 和 Linux 容器允许我们创建多个实例来测试具有特定所需版本的角色。由于容器是轻量级的,因此它们还允许我们在开发角色时快速迭代其功能。在这种情况下,使用容器测试角色是适用的,因为角色仅配置正在运行的 Linux 实例。要测试其他配置场景或云基础设施,我们可以使用委托驱动程序或社区提供的其他适当驱动程序。

您需要什么?

要学习本教程,请使用运行 Linux 的物理机或虚拟机,并安装 Python 3 和 Podman。在本示例中,我们运行的是 RHEL 8.2。您还需要配置 Podman 以运行无根容器。Podman 的安装不在本博客的范围内,因此请参阅官方文档了解更多信息。要安装 RHEL 8 上的 Podman,您还可以查看 RHEL 8 的容器文档

入门

Molecule 可作为 Python 包使用,因此可以通过 pip 安装。第一步,我们为 Molecule 安装创建一个专用的 Python 环境,并在其中安装它

$ mkdir molecule-blog
$ cd molecule-blog
$ python3 -m venv molecule-venv
$ source molecule-venv/bin/activate
(molecule-venv) $ pip install "molecule[lint]"

请注意,我们使用“lint”选项安装了 Molecule。通过使用此选项,pip 还安装了“yamllint”和“ansible-lint”工具,这些工具允许您使用 Molecule 对您的角色执行静态代码分析,确保其符合 Ansible 代码标准。

安装会从互联网下载所有依赖项,包括 Ansible。验证安装的版本

$ molecule --version
molecule 3.0.4
   ansible==2.9.10 python==3.6

接下来,让我们使用“molecule”命令初始化一个新的 Ansible 角色。

初始化新的 Ansible 角色

一般来说,在开发新的 Ansible 角色时,您可以通过运行“ansible-galaxy role init”命令来初始化它。在这种情况下,请改用“molecule”初始化新角色。通过这样做,您将拥有“ansible-galaxy”命令提供的相同角色结构以及运行 Molecule 测试所需的基本样板代码。

默认情况下,Molecule 使用 Docker 驱动程序执行测试。由于我们希望使用“podman”执行测试,因此在使用“molecule”初始化角色时,需要使用选项--driver-name=podman指定驱动程序名称。

切换回“molecule-blog”目录,并使用以下命令初始化新角色“mywebapp”:

$ molecule init role mywebapp --driver-name=podman
--> Initializing new role mywebapp...
Initialized role in /home/ricardo/molecule-blog/mywebapp successfully.

Molecule 在名为“mywebapp”的目录中为您的新角色创建了结构。切换到此目录并检查 Molecule 创建的内容

$ cd mywebapp
$ tree
.
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── molecule
│   └── default
│       ├── converge.yml
│       ├── INSTALL.rst
│       ├── molecule.yml
│       └── verify.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

10 directories, 12 files

Molecule 将其配置文件包含在“molecule”子目录下。在初始化新角色时,Molecule 会添加一个名为“default”的单个场景。稍后,您可以添加更多场景以测试不同的条件。在本教程中,我们将使用“default”场景。

验证文件molecule/default/molecule.yml中的基本配置

$ cat molecule/default/molecule.yml
---
dependency:
  name: galaxy
driver:
  name: podman
platforms:
  - name: instance
    image: docker.io/pycontribs/centos:7
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible

根据我们的要求,此文件指定了用于测试的 Podman 驱动程序。它还使用容器镜像docker.io/pycontribs/centos:7定义了一个默认平台“instance”,您稍后将对其进行更改。

与 Molecule v2 不同,Molecule v3 默认不指定 linter。使用您喜欢的编辑器打开配置文件molecule/default/molecule.yml,在末尾包含 lint 配置

$ vi molecule/default/molecule.yml
...
verifier:
  name: ansible
lint: |
  set -e
  yamllint .
  ansible-lint .

保存并关闭配置文件。从项目根目录运行“molecule lint”以对整个项目进行 lint 检查

$ molecule lint

此命令返回了一些错误,因为文件“meta/main.yml”缺少一些必需的值。通过编辑文件“meta/main.yml”并添加“author”、“company”、“license”、“platforms”,以及删除末尾的空行来解决这些问题。为简洁起见,不添加注释,“meta/main.yaml”如下所示

$ vi meta/main.yml
galaxy_info:
  author: Ricardo Gerardi
  description: Mywebapp role deploys a sample web app
  company: Red Hat

  license: MIT

  min_ansible_version: 2.9

  platforms:
  - name: rhel
    versions:
    - 8
  - name: ubuntu
    versions:
    - 20.04

  galaxy_tags: []

dependencies: []

现在重新对项目进行 lint 检查,并验证这次没有错误。

$ molecule lint
--> Test matrix

└── default
    ├── dependency
    └── lint

--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'lint'
--> Executing: set -e
yamllint .
ansible-lint .

角色已初始化,基本 molecule 配置已就绪。接下来,让我们设置测试实例。

设置实例

默认情况下,Molecule 使用“Centos:7”镜像定义了一个名为“instance”的单个实例。根据我们的要求,我们希望确保我们的角色与 RHEL 8 和 Ubuntu 20.04 兼容。此外,由于此角色将 Apache Web 服务器作为系统服务启动,因此我们需要使用启用“systemd”的容器镜像。

Red Hat 为 RHEL 8 提供了官方的通用基础镜像,该镜像启用了“systemd”:

  • registry.access.redhat.com/ubi8/ubi-init

对于 Ubuntu,没有官方的启用“systemd”的镜像,因此我们将使用 Ansible 开源社区的 Jeff Geerling 维护的镜像

  • geerlingguy/docker-ubuntu2004-ansible

要启用“systemd”实例,请修改“molecule/default/molecule.yml”配置文件,删除“centos:7”实例并添加两个新实例。

$ vi molecule/default/molecule.yml
---
dependency:
  name: galaxy
driver:
  name: podman
platforms:
  - name: rhel8
    image: registry.access.redhat.com/ubi8/ubi-init
    tmpfs:
      - /run
      - /tmp
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    capabilities:
      - SYS_ADMIN
    command: "/usr/sbin/init"
    pre_build_image: true
  - name: ubuntu
    image: geerlingguy/docker-ubuntu2004-ansible
    tmpfs:
      - /run
      - /tmp
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    capabilities:
      - SYS_ADMIN
    command: "/lib/systemd/systemd"
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible
lint: |
  set -e
  yamllint .
  ansible-lint .

使用这些参数,我们将挂载临时文件系统“/run”和“/tmp”,以及每个实例的“cgroup”卷。我们还启用了“SYS_ADMIN”功能,因为它们是使用 Systemd 运行容器所必需的。

此外,如果您在启用了 SELinux 的 RHEL 8 机器上学习本教程(应该如此),则需要将“container_manage_cgroup”布尔值设置为 true 以允许容器运行 Systemd。有关更多详细信息,请参阅 RHEL 8 的文档

sudo setsebool -P container_manage_cgroup 1

Molecule 使用 Ansible Playbook 来配置这些实例。通过修改“molecule/default/molecule.yml”配置文件中的“provisioner”字典来修改和添加配置参数。它接受 Ansible 配置文件“ansible.cfg”中提供的相同配置选项。例如,通过添加“defaults”部分来更新配置程序配置。将 Python 解释器设置为“auto_silent”以防止警告。启用“profile_tasks”、“timer”和“yaml”回调插件以使用 playbook 输出输出性能分析信息。然后,添加“ssh_connection”部分并禁用 SSH 管道,因为它不适用于 Podman

provisioner:
  name: ansible
  config_options:
    defaults:
      interpreter_python: auto_silent
      callback_whitelist: profile_tasks, timer, yaml
    ssh_connection:
      pipelining: false

保存配置文件,并通过从角色根目录运行“molecule create”来创建实例

$ molecule create

Molecule 运行配置 playbook 并创建两个实例。您可以通过运行“molecule list”来检查实例。

$ molecule list
Instance Name    Driver Name    Provisioner Name    Scenario Name    Created    Converged
---------------  -------------  ------------------  ---------------  ---------  -----------
rhel8            podman         ansible             default          true       false
ubuntu           podman         ansible             default          true       false

您还可以验证 Podman 中是否正在运行这两个容器

$ podman ps
CONTAINER ID  IMAGE                                                   COMMAND               CREATED             STATUS                 PORTS  NAMES
2e2f14eaa37b  docker.io/geerlingguy/docker-ubuntu2004-ansible:latest  /lib/systemd/syst...  About a minute ago  Up About a minute ago         ubuntu
2ce0a0ea8692  registry.access.redhat.com/ubi8/ubi-init:latest         /usr/sbin/init        About a minute ago  Up About a minute ago         rhel8

在开发角色时,Molecule 使用正在运行的实例对其进行测试。如果测试失败,或错误导致不可逆转的更改,需要您重新开始,您可以随时运行“molecule destroy”删除这些实例,并使用“molecule create”重新创建它们。