如何在Ubuntu18.04上使用Molecule和TravisCI实现Ansible角色的持续测试

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Mozilla 基金会 来接受捐赠。

介绍

Ansible 是一个无代理配置管理工具,它使用 YAML 模板定义要在主机上执行的任务列表。 在 Ansible 中,roles 是变量、任务、文件、模板和模块的集合,它们一起用于执行单一、复杂的功能。

Molecule 是一种用于对 Ansible 角色进行自动化测试的工具,专门设计用于支持开发始终如一地编写和维护良好的角色。 Molecule 的单元测试允许开发人员同时针对多个环境和不同参数测试角色。 开发人员不断地针对经常更改的代码运行测试,这一点很重要。 此工作流程可确保角色在您更新代码库时继续工作。 使用持续集成工具运行 Molecule,例如 Travis CI,允许测试持续运行,确保对代码的贡献不会引入重大更改。

在本教程中,您将使用预制的基本角色在 Ubuntu 和 CentOS 服务器上安装和配置 Apache Web 服务器和防火墙。 然后,您将在该角色中初始化一个 Molecule 场景以创建测试并确保该角色在您的目标环境中按预期执行。 配置 Molecule 后,您将使用 Travis CI 不断测试您新创建的角色。 每次对代码进行更改时,Travis CI 都会运行 molecule test 以确保角色仍然正确执行。

先决条件

在开始本教程之前,您需要:

第 1 步 - 分叉基本角色存储库

您将使用一个名为 ansible-apache 的预制角色,该角色安装 Apache 并在基于 Debian 和 Red Hat 的发行版上配置防火墙。 您将分叉并使用此角色作为基础,然后在其之上构建 Molecule 测试。 Forking 允许您创建存储库的副本,以便您可以对其进行更改而不会篡改原始项目。

首先创建一个 ansible-apache 角色的分支。 转到 ansible-apache 存储库并单击 Fork 按钮。

分叉存储库后,GitHub 将引导您进入分叉页面。 这将是基本存储库的副本,但在您自己的帐户上。

单击绿色的 Clone 或下载 按钮,您将看到一个带有 Clone with HTTPS 的框。

复制为您的存储库显示的 URL。 您将在下一步中使用它。 URL 将与此类似:

https://github.com/username/ansible-apache.git

您将 username 替换为您的 GitHub 用户名。

设置好 fork 后,您将在服务器上克隆它并开始准备下一部分中的角色。

第 2 步——准备你的角色

按照先决条件 如何在 Ubuntu 18.04 上使用 Molecule 测试 Ansible 角色的步骤 1,您将在虚拟环境中安装 Molecule 和 Ansible。 您将使用这个虚拟环境来发展您的新角色。

首先,在满足先决条件的同时通过运行以下命令激活您创建的虚拟环境:

source my_env/bin/activate

运行以下命令以使用您刚刚在步骤 1 中复制的 URL 克隆存储库:

git clone https://github.com/username/ansible-apache.git

您的输出将类似于以下内容:

OutputCloning into 'ansible-apache'...
remote: Enumerating objects: 16, done.
remote: Total 16 (delta 0), reused 0 (delta 0), pack-reused 16
Unpacking objects: 100% (16/16), done.

进入新创建的目录:

cd ansible-apache

您下载的基本角色执行以下任务:

  • 包含变量:角色首先根据主机的分布包含所有需要的变量。 Ansible 使用变量来处理不同系统之间的差异。 由于您使用 Ubuntu 18.04 和 CentOS 7 作为主机,因此该角色将识别出操作系统系列分别是 Debian 和 Red Hat,并包含来自 vars/Debian.ymlvars/RedHat.yml 的变量。
  • 包括与分布相关的任务:这些任务包括tasks/install-Debian.ymltasks/install-RedHat.yml。 根据指定的发行版,它会安装相关的软件包。 对于 Ubuntu,这些软件包是 apache2ufw。 对于 CentOS,这些软件包是 httpdfirewalld
  • 确保存在最新的 index.html:此任务复制 Apache 将用作 Web 服务器主页的模板 templates/index.html.j2
  • 启动相关服务并在启动时启用它们:启动并启用作为第一个任务的一部分安装的所需服务。 对于 CentOS,这些服务是 httpdfirewalld,对于 Ubuntu,它们是 apache2ufw
  • 配置防火墙以允许流量:这包括tasks/configure-Debian-firewall.ymltasks/configure-RedHat-firewall.yml。 Ansible 将 Firewalld 或 UFW 配置为防火墙并将 http 服务列入白名单。

现在您已经了解了这个角色的工作原理,您将配置 Molecule 来测试它。 您将为这些任务编写测试用例,涵盖他们所做的更改。

第 3 步 — 编写测试

要检查您的基本角色是否按预期执行其任务,您将启动一个 Molecule 场景,指定您的目标环境,并创建三个自定义测试文件。

首先使用以下命令为此角色初始化 Molecule 场景:

molecule init scenario -r ansible-apache

您将看到以下输出:

Output--> Initializing new scenario default...
Initialized scenario in /home/sammy/ansible-apache/molecule/default successfully.

通过将 CentOS 和 Ubuntu 作为平台包含在 Molecule 配置文件中,您将添加 CentOS 和 Ubuntu 作为目标环境。 为此,请使用文本编辑器编辑 molecule.yml 文件:

nano molecule/default/molecule.yml

将以下突出显示的内容添加到分子配置中:

~/ansible-apache/molecule/default/molecule.yml

---
dependency:
  name: galaxy
driver:
  name: docker
lint:
  name: yamllint
platforms:
  - name: centos7
    image: milcom/centos7-systemd
    privileged: true
  - name: ubuntu18
    image: solita/ubuntu-systemd
    command: /sbin/init
    privileged: true
    volumes:
      - /lib/modules:/lib/modules:ro
provisioner:
  name: ansible
  lint:
    name: ansible-lint
scenario:
  name: default
verifier:
  name: testinfra
  lint:
    name: flake8

在这里,您指定了两个以特权模式启动的目标平台,因为您正在使用 systemd 服务:

  • centos7是第一个平台,使用milcom/centos7-systemd镜像。
  • ubuntu18 是第二个平台,使用 solita/ubuntu-systemd 图像。 除了使用特权模式和挂载所需的内核模块之外,您还在启动时运行 /sbin/init 以确保 iptables 已启动并运行。

保存并退出文件。

有关运行特权容器的更多信息,请访问 官方分子文档

您将不使用默认的 Molecule 测试文件,而是创建三个自定义测试文件,一个用于每个目标平台,一个用于编写所有平台之间通用的测试。 首先使用以下命令删除场景的默认测试文件 test_default.py

rm molecule/default/tests/test_default.py

您现在可以继续为每个目标平台创建三个自定义测试文件 test_common.pytest_Debian.pytest_RedHat.py

第一个测试文件 test_common.py 将包含每个主机将执行的常见测试。 创建和编辑通用测试文件,test_common.py

nano molecule/default/tests/test_common.py

将以下代码添加到文件中:

~/ansible-apache/molecule/default/tests/test_common.py

import os
import pytest

import testinfra.utils.ansible_runner

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


@pytest.mark.parametrize('file, content', [
  ("/var/www/html/index.html", "Managed by Ansible")
])
def test_files(host, file, content):
    file = host.file(file)

    assert file.exists
    assert file.contains(content)

在您的 test_common.py 文件中,您已导入所需的库。 您还编写了一个名为 test_files() 的测试,它包含您的角色执行的发行版之间的唯一常见任务:将您的模板复制为 Web 服务器主页。

下一个测试文件 test_Debian.py 包含特定于 Debian 发行版的测试。 该测试文件将专门针对您的 Ubuntu 平台。

通过运行以下命令创建和编辑 Ubuntu 测试文件:

nano molecule/default/tests/test_Debian.py

您现在可以导入所需的库并将 ubuntu18 平台定义为目标主机。 将以下代码添加到此文件的开头:

~/ansible-apache/molecule/default/tests/test_Debian.py

import os
import pytest

import testinfra.utils.ansible_runner

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

然后,在同一个文件中,您将添加 test_pkg() 测试。

将以下代码添加到文件中,该文件定义了 test_pkg() 测试:

~/ansible-apache/molecule/default/tests/test_Debian.py

...
@pytest.mark.parametrize('pkg', [
    'apache2',
    'ufw'
])
def test_pkg(host, pkg):
    package = host.package(pkg)

    assert package.is_installed

该测试将检查主机上是否安装了 apache2ufw 软件包。

注意: 将多个测试添加到 Molecule 测试文件时,请确保每个测试之间有两个空白行,否则您将收到 Molecule 的语法错误。


要定义下一个测试 test_svc(),请在文件中的 test_pkg() 测试下添加以下代码:

~/ansible-apache/molecule/default/tests/test_Debian.py

...
@pytest.mark.parametrize('svc', [
    'apache2',
    'ufw'
])
def test_svc(host, svc):
    service = host.service(svc)

    assert service.is_running
    assert service.is_enabled

test_svc() 将检查 apache2ufw 服务是否正在运行和启用。

最后,您将把最后一个测试 test_ufw_rules() 添加到 test_Debian.py 文件中。

在文件中的 test_svc() 测试下添加此代码以定义 test_ufw_rules()

~/ansible-apache/molecule/default/tests/test_Debian.py

...
@pytest.mark.parametrize('rule', [
    '-A ufw-user-input -p tcp -m tcp --dport 80 -j ACCEPT'
])
def test_ufw_rules(host, rule):
    cmd = host.run('iptables -t filter -S')

    assert rule in cmd.stdout

test_ufw_rules() 将检查您的防火墙配置是否允许 Apache 服务使用的端口上的流量。

添加这些测试后,您的 test_Debian.py 文件将如下所示:

~/ansible-apache/molecule/default/tests/test_Debian.py

import os
import pytest

import testinfra.utils.ansible_runner

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


@pytest.mark.parametrize('pkg', [
    'apache2',
    'ufw'
])
def test_pkg(host, pkg):
    package = host.package(pkg)

    assert package.is_installed


@pytest.mark.parametrize('svc', [
    'apache2',
    'ufw'
])
def test_svc(host, svc):
    service = host.service(svc)

    assert service.is_running
    assert service.is_enabled


@pytest.mark.parametrize('rule', [
    '-A ufw-user-input -p tcp -m tcp --dport 80 -j ACCEPT'
])
def test_ufw_rules(host, rule):
    cmd = host.run('iptables -t filter -S')

    assert rule in cmd.stdout

test_Debian.py 文件现在包括三个测试:test_pkg()test_svc()test_ufw_rules()

保存并退出test_Debian.py

接下来,您将创建 test_RedHat.py 测试文件,其中将包含特定于 Red Hat 发行版的测试,以针对您的 CentOS 平台。

通过运行以下命令创建和编辑 CentOS 测试文件 test_RedHat.py

nano molecule/default/tests/test_RedHat.py

与 Ubuntu 测试文件类似,您现在将编写三个测试以包含在 test_RedHat.py 文件中。 在添加测试代码之前,您可以导入所需的库并将 centos7 平台定义为目标主机,方法是在文件开头添加以下代码:

~/ansible-apache/molecule/default/tests/test_RedHat.py

import os
import pytest

import testinfra.utils.ansible_runner

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

然后,添加 test_pkg() 测试,它将检查 httpdfirewalld 包是否安装在主机上。

在您的库导入代码之后,将 test_pkg() 测试添加到您的文件中。 (同样,请记住在每个新测试之前包含两个空白行。)

~/ansible-apache/molecule/default/tests/test_RedHat.py

...
@pytest.mark.parametrize('pkg', [
    'httpd',
    'firewalld'
])
def test_pkg(host, pkg):
    package = host.package(pkg)

      assert package.is_installed

现在,您可以添加 test_svc() 测试以确保 httpdfirewalld 服务正在运行和启用。

test_pkg() 测试之后将 test_svc() 代码添加到您的文件中:

~/ansible-apache/molecule/default/tests/test_RedHat.py

...
@pytest.mark.parametrize('svc', [
    'httpd',
    'firewalld'
])
  def test_svc(host, svc):
    service = host.service(svc)

    assert service.is_running
    assert service.is_enabled

test_RedHat.py 文件中的最终测试将是 test_firewalld(),它将检查 Firewalld 是否将 http 服务列入白名单。

test_svc() 代码之后将 test_firewalld() 测试添加到您的文件中:

~/ansible-apache/molecule/default/tests/test_RedHat.py

...
@pytest.mark.parametrize('file, content', [
    ("/etc/firewalld/zones/public.xml", "<service name=\"http\"/>")
])
def test_firewalld(host, file, content):
    file = host.file(file)

    assert file.exists
    assert file.contains(content)

导入库并添加三个测试后,您的 test_RedHat.py 文件将如下所示:

~/ansible-apache/molecule/default/tests/test_RedHat.py

import os
import pytest

import testinfra.utils.ansible_runner

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


@pytest.mark.parametrize('pkg', [
    'httpd',
    'firewalld'
])
def test_pkg(host, pkg):
    package = host.package(pkg)

    assert package.is_installed


@pytest.mark.parametrize('svc', [
    'httpd',
    'firewalld'
])
def test_svc(host, svc):
    service = host.service(svc)

    assert service.is_running
    assert service.is_enabled


@pytest.mark.parametrize('file, content', [
    ("/etc/firewalld/zones/public.xml", "<service name=\"http\"/>")
])
def test_firewalld(host, file, content):
    file = host.file(file)

    assert file.exists
    assert file.contains(content)

现在您已经在 test_common.pytest_Debian.pytest_RedHat.py 这三个文件中完成了编写测试,您的角色已准备好进行测试。 在下一步中,您将使用 Molecule 针对您新配置的角色运行这些测试。

第 4 步——针对你的角色进行测试

您现在将使用 Molecule 针对基本角色 ansible-apache 执行新创建的测试。 要运行测试,请使用以下命令:

molecule test

一旦 Molecule 完成运行所有测试,您将看到以下输出:

Output...
--> Scenario: 'default'
--> Action: 'verify'
--> Executing Testinfra tests found in /home/sammy/ansible-apache/molecule/default/tests/...
    ============================= test session starts ==============================
    platform linux -- Python 3.6.7, pytest-4.1.1, py-1.7.0, pluggy-0.8.1
    rootdir: /home/sammy/ansible-apache/molecule/default, inifile:
    plugins: testinfra-1.16.0
collected 12 items

    tests/test_common.py ..                                                  [ 16%]
    tests/test_RedHat.py .....                                               [ 58%]
    tests/test_Debian.py .....                                               [100%]

    ========================== 12 passed in 80.70 seconds ==========================
Verifier completed successfully.

您会在输出中看到 Verifier completed successfully ; 这意味着验证者执行了您的所有测试并成功返回。

现在您已成功完成角色的开发,您可以将更改提交到 Git 并设置 Travis CI 以进行持续测试。

第 5 步 — 使用 Git 分享您更新后的角色

在本教程中,到目前为止,您已经克隆了一个名为 ansible-apache 的角色并向其添加了测试,以确保它适用于 Ubuntu 和 CentOS 主机。 要与公众分享您更新的角色,您必须提交这些更改并将它们推送到您的 fork。

运行以下命令以添加文件并提交您所做的更改:

git add .

此命令会将您在当前目录中修改的所有文件添加到暂存区。

您还需要在 git config 中设置您的姓名和电子邮件地址才能成功提交。 您可以使用以下命令执行此操作:

git config user.email "sammy@digitalocean.com"
git config user.name "John Doe"

将更改的文件提交到您的存储库:

git commit -m "Configured Molecule"

您将看到以下输出:

Output[master b2d5a5c] Configured Molecule
 8 files changed, 155 insertions(+), 1 deletion(-)
 create mode 100644 molecule/default/Dockerfile.j2
 create mode 100644 molecule/default/INSTALL.rst
 create mode 100644 molecule/default/molecule.yml
 create mode 100644 molecule/default/playbook.yml
 create mode 100644 molecule/default/tests/test_Debian.py
 create mode 100644 molecule/default/tests/test_RedHat.py
 create mode 100644 molecule/default/tests/test_common.py

这表示您已成功提交更改。 现在,使用以下命令将这些更改推送到您的 fork:

git push -u origin master

您将看到输入 GitHub 凭据的提示。 输入这些凭据后,您的代码将被推送到您的存储库,您将看到以下输出:

OutputCounting objects: 13, done.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (13/13), 2.32 KiB | 2.32 MiB/s, done.
Total 13 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 2 local objects.
To https://github.com/username/ansible-apache.git
   009d5d6..e4e6959  master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

如果您访问位于 github.com/username/ansible-apache 的 fork 存储库,您将看到一个名为 Configured Molecule 的新提交,反映了您在文件中所做的更改。

现在,您可以将 Travis CI 与您的新存储库集成,以便对您的角色所做的任何更改都会自动触发 Molecule 测试。 这将确保您的角色始终适用于 Ubuntu 和 CentOS 主机。

第 6 步 - 集成 Travis CI

在这一步中,您要将 Travis CI 集成到您的工作流程中。 启用后,您推送到 fork 的任何更改都将触发 Travis CI 构建。 这样做的目的是确保 Travis CI 在贡献者进行更改时始终运行 molecule test。 如果进行了任何重大更改,Travis 将声明构建状态。

继续 Travis CI 以启用您的存储库。 导航到您的个人资料页面,您可以在其中单击 GitHub 的 Activate 按钮。

您可以在 此处 找到有关在 Travis CI 中激活存储库的更多指导。

要使 Travis CI 正常工作,您必须创建一个包含相关说明的配置文件。 要创建 Travis 配置文件,请返回您的服务器并运行以下命令:

nano .travis.yml

要复制您在本教程中创建的环境,您将在 Travis 配置文件中指定参数。 将以下内容添加到您的文件中:

~/ansible-apache/.travis.yml

---
language: python
python:
  - "2.7"
  - "3.6"
services:
  - docker
install:
  - pip install molecule docker
script:
  - molecule --version
  - ansible --version
  - molecule test

您在此文件中指定的参数是:

  • language:当您指定 Python 作为语言时,CI 环境为您在 python 键下指定的每个 Python 版本使用单独的 virtualenv 实例。
  • python:在这里,您指定 Travis 将使用 Python 2.7 和 Python 3.6 来运行您的测试。
  • services:你需要 Docker 在 Molecule 中运行测试。 您指定 Travis 应确保 Docker 存在于您的 CI 环境中。
  • install:在这里,您指定 Travis CI 将在您的 virtualenv 中执行的初步安装步骤。 pip install molecular docker 检查 Ansible 和 Molecule 是否与 Docker 远程 API 的 Python 库一起存在。
  • script:这是指定 Travis CI 需要执行的步骤。 在您的文件中,您指定了三个步骤: 如果 Molecule 已成功安装,则分子 --version 打印分子版本。 ansible --version 如果 Ansible 已成功安装,则打印 Ansible 版本。 分子测试最终运行您的分子测试。

您指定 molecule --versionansible --version 的原因是为了在由于版本控制导致 ansiblemolecule 配置错误而导致构建失败的情况下捕获错误。

将内容添加到 Travis CI 配置文件后,保存并退出 .travis.yml

现在,每次您将任何更改推送到存储库时,Travis CI 都会自动运行基于上述配置文件的构建。 如果 script 块中的任何命令失败,Travis CI 将报告构建状态。

为了更容易查看构建状态,您可以在角色的 README 中添加一个指示构建状态的徽章。 使用文本编辑器打开 README.md 文件:

nano README.md

将以下行添加到 README.md 以显示构建状态:

~/ansible-apache/README.md

[![Build Status](https://travis-ci.org/username/ansible-apache.svg?branch=master)](https://travis-ci.org/username/ansible-apache)

username 替换为您的 GitHub 用户名。 像之前所做的那样提交并将更改推送到您的存储库。

首先,运行以下命令将.travis.ymlREADME.md添加到暂存区:

git add .travis.yml README.md

现在通过执行以下命令将更改提交到您的存储库:

git commit -m "Configured Travis"

最后,使用以下命令将这些更改推送到您的 fork:

git push -u origin master

如果您导航到您的 GitHub 存储库,您将看到它最初报告 build: unknown

在几分钟内,Travis 将启动一个构建,您可以在 Travis CI 网站上对其进行监控。 一旦构建成功,GitHub 也会在您的存储库中报告状态 - 使用您放置在 README 文件中的标记:

您可以访问 Travis CI 网站访问构建的完整详细信息:

现在您已经成功地为您的新角色设置了 Travis CI,您可以持续测试并将更改集成到您的 Ansible 角色。

结论

在本教程中,您派生了一个从 GitHub 安装和配置 Apache Web 服务器的角色,并通过编写测试并将这些测试配置为在运行 Ubuntu 和 CentOS 的 Docker 容器上工作,为 Molecule 添加了集成。 通过将新创建的角色推送到 GitHub,您已允许其他用户访问您的角色。 当贡献者更改您的角色时,Travis CI 将自动运行 Molecule 来测试您的角色。

一旦您熟悉角色的创建并使用 Molecule 进行测试,您可以将其与 Ansible Galaxy 集成,以便在构建成功后自动推送角色。