作者选择了Mozilla基金会作为Write for DOnations计划的一部分进行捐赠。
介绍
Ansible是一种无代理配置管理工具,它使用YAML模板定义要在主机上执行的任务列表。 在Ansible中, 角色是变量,任务,文件,模板和模块的集合,它们一起用于执行单一的复杂功能。
Molecule是一种用于执行Ansible角色自动化测试的工具,专门用于支持开发始终如一的良好编写和维护的角色。 Molecule的单元测试允许开发人员在多个环境和不同参数下同时测试角色。 开发人员必须不断地针对经常变化的代码运行测试; 此工作流程可确保角色在更新代码库时继续有效。 使用Travis CI等持续集成工具运行Molecule可以让测试持续运行,确保对代码的贡献不会引入重大变化。
在本教程中,您将使用预先制作的基本角色,在Ubuntu和CentOS服务器上安装和配置Apache Web服务器和防火墙。 然后,您将初始化该角色中的Molecule场景,以创建测试并确保角色在目标环境中按预期执行。 配置Molecule后,您将使用Travis CI连续测试新创建的角色。 每次对代码进行更改时,Travis CI都会运行molecule test
以确保角色仍能正确执行。
先决条件
在开始本教程之前,您需要:
- 一个Ubuntu 18.04服务器按照Ubuntu 18.04初始服务器设置指南设置 ,包括一个sudo非root用户和防火墙。
- 配置Ansible和Molecule,您可以按照如何在Ubuntu 18.04上测试Anslec Roles with Molecule的第1步来完成。
- 通过以下如何为开源提供安装Git :Git入门 。
- 熟悉持续集成及其用例。 要了解更多信息,请查看“持续集成,交付和部署简介” 。
- GitHub上的一个帐户。
- 特拉维斯CI的帐户。
第1步 – 分叉基本角色存储库
您将使用一个名为ansible-apache的预制角色来安装Apache并在基于Debian和Red Hat的发行版上配置防火墙。 您将分叉并使用此角色作为基础,然后在其上构建分子测试。 Forking允许您创建存储库的副本,以便您可以对其进行更改而不会篡改原始项目。
首先创建一个ansible-apache角色的分支。 转到ansible-apache存储库,然后单击Fork按钮。
一旦你分叉了存储库,GitHub将引导你进入你的fork页面。 这将是基本存储库的副本,但是您自己的帐户。
单击绿色克隆或下载按钮,您将看到一个包含使用HTTPS克隆的框。
复制为存储库显示的URL。 您将在下一步中使用它。 URL将类似于:
https://github.com/username/ansible-apache.git
您将使用您的GitHub用户名替换username。
设置fork后,您将在服务器上克隆它并在下一部分开始准备您的角色。
第2步 – 准备你的角色
按照Ubuntu 18.04上的如何使用Molecule测试Ansible Roles的先决条件的第1步,您将在虚拟环境中安装Molecule和Ansible。 您将使用此虚拟环境来开发新角色。
首先,通过运行以下命令来激活您在创建先前条件时创建的虚拟环境:
source my_env/bin/activate
运行以下命令以使用您在第1步中复制的URL克隆存储库:
git clone https://github.com/username/ansible-apache.git
您的输出将类似于以下内容:
Cloning into 'ansible-apache'...remote: Enumerating objects: 16, done.remote: Total 16 (delta 0), reused 0 (delta 0), pack-reused 16Unpacking objects: 100% (16/16), done.
进入新创建的目录:
cd ansible-apache
您下载的基本角色执行以下任务:
包含变量 :角色首先根据主机的分布包含所有必需的变量 。 Ansible使用变量来处理不同系统之间的差异。 由于您使用Ubuntu 18.04和CentOS 7作为主机,该角色将分别识别OS系列是Debian和Red Hat,并包含来自
vars/Debian.yml
和vars/RedHat.yml
。包括与分发相关的任务 :这些任务包括
tasks/install-Debian.yml
和tasks/install-RedHat.yml
。 根据指定的分发,它会安装相关的包。 对于Ubuntu,这些包是apache2
和ufw
。 对于CentOS,这些软件包是httpd
和firewalld
。确保存在最新的index.html :此任务复制Apache将用作Web服务器主页的模板
templates/index.html.j2
。启动相关服务并在启动时启用它们 :启动并启用作为第一个任务的一部分安装的所需服务。 对于CentOS,这些服务是
httpd
和firewalld
,对于Ubuntu,它们是apache2
和ufw
。配置防火墙以允许流量 :这包括
tasks/configure-Debian-firewall.yml
或tasks/configure-RedHat-firewall.yml
。 Ansible将Firewalld或UFW配置为防火墙并将http
服务列入白名单。
现在您已了解此角色的工作原理,您将配置Molecule进行测试。 您将为这些任务编写测试用例,以涵盖他们所做的更改。
第3步 – 编写测试
要检查基本角色是否按预期执行任务,您将启动Molecule方案,指定目标环境并创建三个自定义测试文件。
首先使用以下命令初始化此角色的Molecule场景:
molecule init scenario -r ansible-apache
您将看到以下输出:
--> Initializing new scenario default...Initialized scenario in /home/sammy/ansible-apache/molecule/default successfully.
您将CentOS和Ubuntu作为目标环境添加为Molecule配置文件中的平台。 为此,请使用文本编辑器编辑molecule.yml
文件:
nano molecule/default/molecule.yml
将以下突出显示的内容添加到Molecule配置中:
---dependency: name: galaxydriver: name: dockerlint: name: yamllintplatforms: - name: centos7 image: milcom/centos7-systemd privileged: true - name: ubuntu18 image: solita/ubuntu-systemd command: /sbin/init privileged: true volumes: - /lib/modules:/lib/modules:roprovisioner: name: ansible lint: name: ansible-lintscenario: name: defaultverifier: name: testinfra lint: name: flake8
在这里,您将指定在使用systemd服务时以特权模式启动的两个目标平台:
-
centos7
是第一个使用milcom/centos7-systemd
映像的平台。 -
ubuntu18
是第二个平台,使用solita/ubuntu-systemd
映像。 除了使用特权模式并安装所需的内核模块之外,您还在启动时运行/sbin/init
以确保iptables启动并运行。
保存并退出该文件。
有关运行特权容器的更多信息,请访问官方Molecule文档 。
您将创建三个自定义测试文件,一个用于每个目标平台,一个文件用于编写所有平台之间通用的测试,而不是使用默认的Molecule测试文件。 首先使用以下命令删除方案的默认测试文件test_default.py
:
rm molecule/default/tests/test_default.py
您现在可以继续为每个目标平台创建三个自定义测试文件test_common.py
, test_Debian.py
和test_RedHat.py
。
第一个测试文件test_common.py
将包含每个主机将执行的常见测试。 创建和编辑公共测试文件test_common.py
:
nano molecule/default/tests/test_common.py
将以下代码添加到文件中:
import osimport pytestimport testinfra.utils.ansible_runnertestinfra_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
平台定义为目标主机。 将以下代码添加到此文件的开头:
import osimport pytestimport testinfra.utils.ansible_runnertestinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('ubuntu18')
然后,在同一个文件中,您将添加test_pkg()
测试。
将以下代码添加到文件中,该文件定义了test_pkg()
测试:
...@pytest.mark.parametrize('pkg', [ 'apache2', 'ufw'])def test_pkg(host, pkg): package = host.package(pkg) assert package.is_installed
此测试将检查主机上是否安装了apache2
和ufw
软件包。
注意:将多个测试添加到Molecule测试文件时,请确保每个测试之间有两个空行,否则您将从Molecule获得语法错误。
要定义下一个测试test_svc()
,请在文件中的test_pkg()
测试下添加以下代码:
...@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()
将检查apache2
和ufw
服务是否正在运行并启用。
最后,您将最后一个测试test_ufw_rules()
添加到test_Debian.py
文件中。
在您的文件中的test_svc()
测试下添加此代码以定义test_ufw_rules()
:
...@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
文件将如下所示:
import osimport pytestimport testinfra.utils.ansible_runnertestinfra_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
测试文件,该文件将包含针对您的CentOS平台的特定于Red Hat发行版的测试。
通过运行以下命令创建和编辑CentOS测试文件test_RedHat.py
:
nano molecule/default/tests/test_RedHat.py
与Ubuntu测试文件类似,您现在将编写三个测试以包含在test_RedHat.py
文件中。 在添加测试代码之前,您可以导入所需的库并将centos7
平台定义为目标主机,方法是将以下代码添加到文件的开头:
import osimport pytestimport testinfra.utils.ansible_runnertestinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('centos7')
然后,添加test_pkg()
测试,该测试将检查主机上是否安装了httpd
和firewalld
软件包。
按照库导入的代码,将test_pkg()
测试添加到您的文件中。 (再次,记住在每次新测试之前包括两个空行。)
...@pytest.mark.parametrize('pkg', [ 'httpd', 'firewalld'])def test_pkg(host, pkg): package = host.package(pkg) assert package.is_installed
现在,您可以添加test_svc()
测试以确保httpd
和firewalld
服务正在运行和启用。
在test_pkg()
测试之后将test_pkg()
代码添加到您的文件中:
...@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_svc()
测试添加到您的文件中:
...@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
文件将如下所示:
import osimport pytestimport testinfra.utils.ansible_runnertestinfra_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.py
, test_Debian.py
和test_RedHat.py
编写测试,您的角色已准备好进行测试。 在下一步中,您将使用Molecule针对新配置的角色运行这些测试。
第4步 – 针对您的角色进行测试
现在,您将使用Molecule对基础角色ansible-apache
执行新创建的测试。 要运行测试,请使用以下命令:
molecule test
一旦Molecule完成所有测试,您将看到以下输出:
...--> 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.0collected 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
在您的输出中Verifier completed successfully
; 这意味着验证程序执行了所有测试并成功返回。
既然您已成功完成角色的开发,您可以将更改提交给Git并设置Travis CI以进行持续测试。
第5步 – 使用Git共享更新的角色
在本教程中,到目前为止,您已经克隆了一个名为ansible-apache
的角色并为其添加了测试,以确保它可以对抗Ubuntu和CentOS主机。 要与公众共享更新的角色,您必须提交这些更改并将其推送到您的分支。
运行以下命令以添加文件并提交您所做的更改:
git add .
此命令将您在当前目录中修改的所有文件添加到暂存区域。
您还需要在git config
中设置您的姓名和电子邮件地址才能成功提交。 您可以使用以下命令执行此操作:
git config user.email "[email protected]"git config user.name "John Doe"
将更改的文件提交到存储库:
git commit -m "Configured Molecule"
您将看到以下输出:
[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凭据的提示。 输入这些凭据后,您的代码将被推送到您的存储库,您将看到此输出:
Counting 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 -> masterBranch '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的“ 激活”按钮。
您可以在此处找到有关在Travis CI中激活存储库的更多指导。
要使Travis CI正常工作,您必须创建包含相关说明的配置文件。 要创建Travis配置文件,请返回到您的服务器并运行以下命令:
nano .travis.yml
要复制您在本教程中创建的环境,您将在Travis配置文件中指定参数。 将以下内容添加到您的文件中:
---language: pythonpython: - "2.7" - "3.6"services: - dockerinstall: - pip install molecule dockerscript: - molecule --version - ansible --version - molecule test
您在此文件中指定的参数是:
-
language
:当您指定Python作为语言时,CI环境对您在python
密钥下指定的每个Python版本使用单独的virtualenv
实例。 -
python
:在这里,您指定Travis将同时使用Python 2.7和Python 3.6来运行测试。 -
services
:您需要Docker在Molecule中运行测试。 您指定Travis应确保您的CI环境中存在Docker。 -
install
:在这里,您将指定Travis CI将在您的virtualenv
执行的初步安装步骤。-
pip install molecule docker
docker检查Ansible和Molecule是否与Docker远程API的Python库一起出现。
-
-
script
:这是指定Travis CI需要执行的步骤。 在您的文件中,您指定了三个步骤:- 如果已成功安装Molecule,则
molecule --version
打印Molecule版本。 - 如果已成功安装Ansible,则ansible
ansible --version
打印Ansible版本。 -
molecule test
终于进行了你的分子测试。
- 如果已成功安装Molecule,则
你指定molecule --version
和ansible --version
的原因是为了在构建因版本控制导致的安全性或molecule
错误配置失败的情况下捕获错误。
将内容添加到Travis CI配置文件后,保存并退出.travis.yml
。
现在,每次将任何更改推送到存储库时,Travis CI将根据上述配置文件自动运行构建。 如果script
块中的任何命令失败,Travis CI将报告构建状态。
为了更容易查看构建状态,您可以将指示构建状态的徽章添加到角色的README
中。 使用文本编辑器打开README.md
文件:
nano README.md
README.md
添加到README.md
以显示构建状态:
[](https://travis-ci.org/username/ansible-apache)
用您的GitHub用户名替换username
名。 像之前一样提交并将更改推送到存储库。
首先,运行以下命令将.travis.yml
和README.md
添加到暂存区域:
git add .travis.yml README.md
现在通过执行以下命令将更改提交到存储库:
git commit -m "Configured Travis"
最后,使用以下命令将这些更改推送到fork:
git push -u origin master
如果您导航到GitHub存储库,您将看到它最初报告构建:未知 。
在几分钟内,Travis将启动您可以在Travis CI网站上监控的构建。 一旦构建成功,GitHub也会在您的存储库中报告状态 – 使用您在README文件中放置的徽章:
您可以访问Travis CI网站访问构建的完整详细信息:
现在您已成功为新角色设置了Travis CI,您可以不断测试和集成对Ansible角色的更改。
结论
在本教程中,您分叉了一个角色,该角色通过GitHub安装和配置Apache Web服务器,并通过编写测试和配置这些测试来处理运行Ubuntu和CentOS的Docker容器,从而为Molecule添加了集成。 通过将新创建的角色推送到GitHub,您已允许其他用户访问您的角色。 当贡献者对您的角色进行更改时,Travis CI将自动运行Molecule来测试您的角色。
一旦您对创建角色并使用Molecule进行测试感到满意,就可以将其与Ansible Galaxy集成,以便在构建成功后自动推送角色。