備忘
Ansible Moleculeとは
一言で言うとTest KitchenのAnsible版。
Test Kitchenの様に、以下などを行うCI系ユーティリティ。pythonベースでpipにて導入。
- テスト環境デプロイ
- テスト環境へのコード適用
- テスト環境に対する検証実施
- テスト環境削除
- テスト環境へのログイン
- テスト環境の状態確認
kithenCIと異なり、テスト環境への反映はansibleのみが使用可能。
ごく簡単な比較
Test Kitchen | Ansible Molecule | |
---|---|---|
開発 | chef | redhat |
テスト対象 | chef cookbook | ansible role |
テスト環境 | vagrant+virtualbox, docker, 既存サーバー, aws ec2, ... | docker, vagrant+virtualbox, aws ec2, ... |
構成管理ツール | chef, ansible, .. | ansible |
テストツール | InSpec, ServerSpec, .. | ansible, testinfra, .. |
コマンド | $ kitchen | $ molecule |
chef cookbook/ansible roleのテンプレート作成 | $ chef generate cookbook <cookbook> | $ molecule init role <role> |
コードlint | ? | $ molecule lint |
テスト環境作成 | $ kitchen create | $ molecule create |
テスト環境への反映 | $ kitchen converge | $ molecule converge |
検証実施 | $ kitchen verify | $ molecule verify |
通しで実行(環境は削除) | $ kitchen test | $ molecule test |
通しで実行(環境を残す) | $ kitchen test --destroy=never | $ molecule test --destroy never |
テスト環境状況 | $ kitchen list | $ molecule list |
テスト環境ログイン | $ kitchen login | $ molecule login |
設定ファイル | kitchen.yml | molecule/default/molecule.yml |
ガッツリと影響を受けていますよね。
kitchenCIに慣れた人なら、moleculeに関してもなんとなく感触が掴めると思えました。
環境
- macOS 10.15.6
- pyenvによるPython 3.8.2環境
- docker desktop 2.4.0.0
導入手順
パス追加
コマンド類は~/.local/binに導入されたので、pathを通しておく
(ログインシェルはbashを継続使用)
$ echo 'export PATH=~/.local/bin:${PATH}' >> ~/.bash_profile
$ . ~/.bash_profile
導入
--user指定で入れてみる
$ python3 -m pip install --user "molecule[lint]"
...
$ molecule --version
molecule 3.0.8
ansible==2.10.2 python==3.8
(意図せず~/.local/binにansible v2.10も導入されたが、いつかは入れなければと思っていたので良い機会と思うこととする。)
moleculeからdockerを使うために以下も導入しておく
(後で出てくる molecule/default/INSTALL.rst にて指示される)
$ python3 -m pip install --user 'molecule[docker]'
...
getting started
以下に沿って試してみる。
https://molecule.readthedocs.io/en/latest/getting-started.html
ロール作成
$ molecule init role my-new-role
--> Initializing new role my-new-role...
Initialized role in /Users/xxxx/my-new-role successfully.
$ cd ./my-new-role
$ tree -a .
.
├── .travis.yml
├── .yamllint
├── README.md
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── molecule
│ └── default
│ ├── INSTALL.rst
│ ├── converge.yml
│ ├── molecule.yml
│ └── verify.yml
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
10 directories, 14 files
基本的には、moleculeディレクトリー以外は、ansible-galaxy init my-new-roleにて作成される、ほぼ通常のansible role構成
molecule/default/molecule.yml
moleculeの構成ファイル
roleをテストするときに使用する各ツールを構成
kitchenCIにおけるkitchen.ymlに相当
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: instance
image: docker.io/pycontribs/centos:8
pre_build_image: true
provisioner:
name: ansible
verifier:
name: ansible
いろいろな設定を実際にはどの様に行う必要があるのか要調査
kitchen.ymlではerbも使えたが、その様な柔軟性があるか
等
-
複数テスト環境を制御するには、platforms下のlistに要素を増やす
-
テスト環境にvagrant+virtualboxを使用するには、molecule-vagrantを導入し
$ python3 -m pip install --user python-vagrant molecule-vagrant
...
molecule.ymlを修正する
driver:
name: vagrant
platforms:
- name: instance
box: fedora/32-cloud-base
memory: 512
cpus: 1
設定の詳細
https://github.com/ansible-community/molecule-vagrant
- デフォルトではlint:セクションは追記されない。lintもさせるなら以下を追記しておく。
lint: |-
set -e
yamllint .
ansible-lint
flake8
参照:
https://molecule.readthedocs.io/en/latest/configuration.html#lint
yamllintのルールは./.yamllintに定義されている。必要に応じてルールを編集する。
yamllintの詳細:
https://yamllint.readthedocs.io/en/latest/
molecule/default/converge.yml
このロールを呼び出すansible playbook
---
- name: Converge
hosts: all
tasks:
- name: "Include my-new-role"
include_role:
name: "my-new-role"
どこでroles_pathを設定しているのか、などは未調査。
molecule/default/verify.yml
検証に使用されるplaybookの雛形
---
# This is an example playbook to execute Ansible tests.
- name: Verify
hosts: all
tasks:
- name: Example assertion
assert:
that: true
以前のデフォルトのverifierはtestinfraだったらしいが、現在のデフォルトはansible(のassertタスク)の様子。
testinfraはAIXなどUNIX系では使えないという理解なので、個人的にはansible assertの方がまし。
テスト環境作成: molecule create
$ molecule create
--> Test matrix
└── default
├── dependency
├── create
└── prepare
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'create'
--> Sanity checks: 'docker'
PLAY [Create] ******************************************************************
TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item=None)
TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item=None)
TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/docker.io/pycontribs/centos:8)
TASK [Create docker network(s)] ************************************************
TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=instance)
TASK [Wait for instance(s) creation to complete] *******************************
FAILED - RETRYING: Wait for instance(s) creation to complete (300 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (299 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (298 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (297 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (296 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (295 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (294 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (293 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (292 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (291 retries left).
changed: [localhost] => (item=None)
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=5 changed=2 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
--> Scenario: 'default'
--> Action: 'prepare'
Skipping, prepare playbook not configured.
テスト環境の状況表示: molecule list
$ molecule list
Instance Name Driver Name Provisioner Name Scenario Name Created Converged
--------------- ------------- ------------------ --------------- --------- -----------
instance docker ansible default true false
dockerコンテナ確認
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
544a355d38d6 pycontribs/centos:8 "bash -c 'while true…" 2 minutes ago Up 2 minutes instance
playbook処理を追記して適用: molecule converge
$ vi tasks/main.yml
...
$ cat tasks/main.yml
---
# tasks file for my-new-role
- name: Molecule Hello World!
debug:
msg: Hello, World!
$ molecule converge
--> Test matrix
└── default
├── dependency
├── create
├── prepare
└── converge
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'create'
Skipping, instances already created.
--> Scenario: 'default'
--> Action: 'prepare'
Skipping, prepare playbook not configured.
--> Scenario: 'default'
--> Action: 'converge'
--> Sanity checks: 'docker'
PLAY [Converge] ****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Include my-new-role] *****************************************************
TASK [my-new-role : Molecule Hello World!] *************************************
ok: [instance] => {
"msg": "Hello, World!"
}
PLAY RECAP *********************************************************************
instance : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ molecule list
Instance Name Driver Name Provisioner Name Scenario Name Created Converged
--------------- ------------- ------------------ --------------- --------- -----------
instance docker ansible default true true
verifyの項がない。
テスト環境の検証: molecule verify
テスト環境に対してmolecule/default/verify.yml playbookを適用
$ molecule verify
--> Test matrix
└── default
└── verify
--> Scenario: 'default'
--> Action: 'verify'
--> Running Ansible Verifier
--> Sanity checks: 'docker'
PLAY [Verify] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Example assertion] *******************************************************
ok: [instance] => {
"changed": false,
"msg": "All assertions passed"
}
PLAY RECAP *********************************************************************
instance : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verifier completed successfully.
テスト環境へのログイン: molecule login
$ molecule login
[root@instance /]# id
uid=0(root) gid=0(root) groups=0(root)
[root@instance /]# hostname
instance
[root@instance /]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"
[root@instance /]# exit
$
テスト環境削除: molecule destroy
$ molecule destroy
--> Test matrix
└── default
├── dependency
├── cleanup
└── destroy
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'cleanup'
Skipping, cleanup playbook not configured.
--> Scenario: 'default'
--> Action: 'destroy'
--> Sanity checks: 'docker'
PLAY [Destroy] *****************************************************************
TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance)
TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
changed: [localhost] => (item=None)
changed: [localhost]
TASK [Delete docker network(s)] ************************************************
PLAY RECAP *********************************************************************
localhost : ok=2 changed=2 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
--> Pruning extra files from scenario ephemeral directory
$ molecule list
Instance Name Driver Name Provisioner Name Scenario Name Created Converged
--------------- ------------- ------------------ --------------- --------- -----------
instance docker ansible default false false
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES