Ubuntu18.04でMoleculeとTravisCIを使用してAnsibleロールの継続的テストを実装する方法

提供:Dev Guides
移動先:案内検索

著者は、 Write for DOnations プログラムの一環として、 MozillaFoundationを選択して寄付を受け取りました。

序章

Ansible は、YAMLテンプレートを使用して、ホストで実行されるタスクのリストを定義するエージェントレス構成管理ツールです。 Ansibleでは、 roles は、単一の複雑な機能を実行するために一緒に使用される変数、タスク、ファイル、テンプレート、およびモジュールのコレクションです。

Molecular は、Ansibleの役割の自動テストを実行するためのツールであり、一貫して適切に作成され維持されている役割の開発をサポートするように特別に設計されています。 Moleculeの単体テストを使用すると、開発者は複数の環境に対して、異なるパラメーターで同時に役割をテストできます。 開発者は、頻繁に変更されるコードに対して継続的にテストを実行することが重要です。 このワークフローにより、コードライブラリを更新するときに役割が引き続き機能することが保証されます。 Travis CI などの継続的インテグレーションツールを使用してMoleculeを実行すると、テストを継続的に実行できるため、コードへの貢献によって重大な変更が発生することはありません。

このチュートリアルでは、UbuntuおよびCentOSサーバーにApacheWebサーバーとファイアウォールをインストールして構成する事前に作成された基本ロールを使用します。 次に、そのロールでMoleculeシナリオを初期化してテストを作成し、ターゲット環境でロールが意図したとおりに実行されることを確認します。 Moleculeを構成した後、Travis CIを使用して、新しく作成したロールを継続的にテストします。 コードに変更が加えられるたびに、TravisCIはmolecule testを実行して、役割が引き続き正しく実行されることを確認します。

前提条件

このチュートリアルを開始する前に、次のものが必要です。

ステップ1—基本ロールリポジトリをフォークする

Apacheをインストールし、DebianベースおよびRedHatベースのディストリビューションにファイアウォールを構成するansible-apacheと呼ばれる事前に作成されたロールを使用します。 この役割をフォークしてベースとして使用し、その上に分子テストを構築します。 Forkingを使用すると、リポジトリのコピーを作成できるため、元のプロジェクトを改ざんすることなくリポジトリに変更を加えることができます。

ansible-apacheロールのフォークを作成することから始めます。 ansible-apache リポジトリに移動し、フォークボタンをクリックします。

リポジトリをフォークすると、GitHubがフォークのページに移動します。 これはベースリポジトリのコピーになりますが、自分のアカウントで行います。

緑色のCloneまたはDownloadボタンをクリックすると、 Clone withHTTPSのボックスが表示されます。

リポジトリに表示されているURLをコピーします。 これは次のステップで使用します。 URLは次のようになります。

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

usernameをGitHubユーザー名に置き換えます。

フォークを設定したら、サーバーにフォークを複製し、次のセクションで役割の準備を開始します。

ステップ2—役割の準備

前提条件のステップ1Ubuntu 18.04 でMoleculeを使用してAnsibleの役割をテストする方法を実行すると、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は変数を使用して、異なるシステム間の不一致を処理します。 Ubuntu18.04とCentOS7をホストとして使用しているため、ロールはOSファミリがそれぞれDebianとRed Hatであることを認識し、vars/Debian.ymlvars/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の場合、これらのサービスはhttpdfirewalldであり、Ubuntuの場合はapache2ufwです。
  • トラフィックを許可するようにファイアウォールを構成します:これには、tasks/configure-Debian-firewall.ymlまたはtasks/configure-RedHat-firewall.ymlのいずれかが含まれます。 Ansibleは、FirewalldまたはUFWのいずれかをファイアウォールとして構成し、httpサービスをホワイトリストに登録します。

この役割がどのように機能するかを理解したので、それをテストするようにMoleculeを構成します。 これらのタスクのテストケースを作成して、それらが行う変更をカバーします。

ステップ3—テストを書く

基本ロールが意図したとおりにタスクを実行することを確認するには、Moleculeシナリオを開始し、ターゲット環境を指定して、3つのカスタムテストファイルを作成します。

次のコマンドを使用して、この役割の分子シナリオを初期化することから始めます。

molecule init scenario -r ansible-apache

次の出力が表示されます。

Output--> 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構成に追加します。

〜/ 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サービスを使用しているため、特権モードで起動される2つのターゲットプラットフォームを指定しています。

  • centos7は最初のプラットフォームであり、milcom/centos7-systemdイメージを使用します。
  • ubuntu18は2番目のプラットフォームであり、solita/ubuntu-systemdイメージを使用します。 特権モードを使用して必要なカーネルモジュールをマウントすることに加えて、起動時に/sbin/initを実行して、iptablesが稼働していることを確認します。

ファイルを保存して終了します。

特権コンテナの実行の詳細については、公式のMoleculeドキュメントを参照してください。

デフォルトのMoleculeテストファイルを使用する代わりに、3つのカスタムテストファイルを作成します。1つはターゲットプラットフォームごとに1つ、もう1つはすべてのプラットフォームに共通のテストを作成するためのファイルです。 次のコマンドを使用して、シナリオのデフォルトのテストファイルtest_default.pyを削除することから始めます。

rm molecule/default/tests/test_default.py

これで、ターゲットプラットフォームごとに、test_common.pytest_Debian.py、およびtest_RedHat.pyの3つのカスタムテストファイルの作成に進むことができます。

最初のテストファイル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

このテストでは、apache2およびufwパッケージがホストにインストールされているかどうかを確認します。

注: Moleculeテストファイルに複数のテストを追加する場合は、各テストの間に2つの空白行があることを確認してください。そうしないと、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()は、apache2およびufwサービスが実行され、有効になっているかどうかを確認します。

最後に、最後のテスト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()の3つのテストが含まれるようになりました。

test_Debian.pyを保存して終了します。

次に、test_RedHat.pyテストファイルを作成します。このファイルには、CentOSプラットフォームを対象とするRedHatディストリビューションに固有のテストが含まれています。

次のコマンドを実行して、CentOSテストファイルtest_RedHat.pyを作成および編集します。

nano molecule/default/tests/test_RedHat.py

Ubuntuテストファイルと同様に、test_RedHat.pyファイルに含める3つのテストを作成します。 テストコードを追加する前に、ファイルの先頭に次のコードを追加することで、必要なライブラリをインポートし、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()テストを追加します。このテストでは、httpdおよびfirewalldパッケージがホストにインストールされているかどうかを確認します。

ライブラリインポートのコードに従って、test_pkg()テストをファイルに追加します。 (繰り返しますが、新しいテストの前に2つの空白行を含めることを忘れないでください。)

〜/ 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()テストを追加して、httpdおよびfirewalldサービスが実行されて有効になっていることを確認できます。

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)

ライブラリをインポートして3つのテストを追加すると、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.py、およびtest_RedHat.pyの3つのファイルすべてでテストの記述が完了したので、役割をテストする準備が整いました。 次のステップでは、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にコミットし、継続的テスト用にTravisCIをセットアップできます。

ステップ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"

次の出力が表示されます。

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

これは、変更が正常にコミットされたことを意味します。 次に、次のコマンドを使用して、これらの変更をフォークにプッシュします。

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にあるフォークのリポジトリに移動すると、ファイルに加えた変更を反映したConfigured Moleculeという新しいコミットが表示されます。

これで、Travis CIを新しいリポジトリと統合して、役割に加えられた変更によってMoleculeテストが自動的にトリガーされるようになりました。 これにより、あなたの役割が常にUbuntuおよびCentOSホストで機能するようになります。

ステップ6—TravisCIの統合

このステップでは、TravisCIをワークフローに統合します。 有効にすると、フォークにプッシュする変更があれば、TravisCIビルドがトリガーされます。 これの目的は、寄稿者が変更を加えるたびにTravisCIが常にmolecule testを実行するようにすることです。 重大な変更が加えられた場合、Travisはビルドステータスをそのように宣言します。

Travis CI に進み、リポジトリを有効にします。 GitHubのActivateボタンをクリックできるプロファイルページに移動します。

TravisCIでのリポジトリのアクティブ化に関する詳細なガイダンスここを見つけることができます。

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がPython2.7とPython3.6の両方を使用してテストを実行することを指定しています。
  • services:Moleculeでテストを実行するにはDockerが必要です。 TravisがDockerがCI環境に存在することを確認する必要があることを指定しています。
  • install:ここでは、TravisCIがvirtualenvで実行する予備的なインストール手順を指定しています。 pip installmolecule dockerを使用して、DockerリモートAPIのPythonライブラリとともにAnsibleとMoleculeが存在することを確認します。
  • script:これは、TravisCIが実行する必要のあるステップを指定するためのものです。 ファイルでは、次の3つのステップを指定しています。 Molecular --versionは、Moleculeが正常にインストールされている場合、Moleculeバージョンを出力します。 ansible --versionは、Ansibleが正常にインストールされている場合、Ansibleバージョンを出力します。 分子テストは最終的に分子テストを実行します。

molecule --versionおよびansible --versionを指定する理由は、バージョン管理によるansibleまたはmoleculeの設定ミスの結果としてビルドが失敗した場合に、エラーをキャッチするためです。

コンテンツをTravisCI構成ファイルに追加したら、.travis.ymlを保存して終了します。

これで、リポジトリに変更をプッシュするたびに、TravisCIは上記の構成ファイルに基づいてビルドを自動的に実行します。 scriptブロックのコマンドのいずれかが失敗した場合、TravisCIはビルドステータスをそのように報告します。

ビルドステータスを確認しやすくするために、ビルドステータスを示すバッジをロールの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"

最後に、次のコマンドを使用して、これらの変更をフォークにプッシュします。

git push -u origin master

GitHubリポジトリに移動すると、最初に build:unknownが報告されていることがわかります。

数分以内に、TravisはTravisCIWebサイトで監視できるビルドを開始します。 ビルドが成功すると、GitHubはリポジトリにもステータスを報告します—READMEファイルに配置したバッジを使用します。

Travis CI Webサイトにアクセスすると、ビルドの完全な詳細にアクセスできます。

新しいロール用にTravisCIを正常にセットアップしたので、Ansibleロールへの変更を継続的にテストして統合できます。

結論

このチュートリアルでは、GitHubからApache Webサーバーをインストールして構成する役割をフォークし、UbuntuとCentOSを実行しているDockerコンテナーで動作するようにテストを記述し、これらのテストを構成することでMoleculeの統合を追加しました。 新しく作成したロールをGitHubにプッシュすることで、他のユーザーが自分のロールにアクセスできるようになります。 コントリビューターによってロールに変更があった場合、TravisCIは自動的にMoleculeを実行してロールをテストします。

ロールの作成とMoleculeでのテストに慣れたら、これを Ansible Galaxy と統合して、ビルドが成功するとロールが自動的にプッシュされるようにすることができます。