moleculeでAnsibleのローカルテスト環境を一瞬で構築する


moleculeとは

  • Ansibleのテスト環境の準備からテスト環境へのPlaybook実行、testinfraやinspec、Ansibleでのテスト実行、テスト環境の破棄を全てやってくれるテストフレームワーク。詳細は公式サイトにくわしい。
  • 2020/2/21時点の最新はv3.1、サポートするAnsibleのバージョンは最新の2メジャーバージョン。(v2.9が最新の場合はv2.8まで)

前提条件

  • docker daemonが起動している。
  • moleculeはバージョン3.0.1を使用。
  • Ansibleはバージョン2.9.5を使用。

インストール

pipでインストールする。

$ pip install 'molecule[docker]'

既存ロールにテストシナリオを追加

ロールのディレクトリに移動して実行すること

$ cd roles/nginx
$ moleculer init scenario
  • moleculeディレクトリが作成される。
  • デフォルトのオプションは以下
    • シナリオ名: default
    • driver: docker
    • provisioner: Ansible
    • Verifier: Ansible
roles/nginx/molecule
└── default
    ├── converge.yml
    ├── INSTALL.rst
    ├── molecule.yml
    └── verify.yml

テスト実行

  • molecule testを実行するだけ。デフォルトではシナリオ名defaultが実行される。個別にシナリオ指定することも可能。
$ molecule test
  • test では以下全ての工程が実行される。
❯ molecule test --help
Usage: molecule test [OPTIONS]

  Test (lint, cleanup, destroy, dependency, syntax, create, prepare,
  converge, idempotence, side_effect, verify, cleanup, destroy).
  • 今回作成したシナリオでは以下。

    • dockerイメージ取得
    • dockerコンテナ作成、起動
    • ansible-lintでPlaybookのチェック
    • playbook実行
    • ansibleでテスト実行
    • dockerコンテナ破棄
  • これらの工程を個別に指定して実行することも可能。
    convergeではコンテナ作成、Playbook実行、テスト実行、コンテナ破棄までやってくれる。

$ molecule converge

ローカルでテストするだけなら以上で完了。

小ネタ

依存関係のあるロールの実行

ロールに依存関係がある場合、たとえばnginxロールでyum installしているが、その前にcommonロールでyumのconfig設定している場合はnginxロールだけ実行してもエラーになる。
依存関係にある処理はprepare.ymlに書いておくことで事前に実行することができる。

prepare.yml
- name: prepare.yml
  hosts: all
  tasks:
    - name: "execute common role"
      include_role:
        name: "common"

lintのスキップ

molecule.ymlでオプションをつける

molecule.yml
lint: |
  yamllint .
  ansible-lint -x 701,703
  flake8

環境変数を使用

bashと同じ要領で使える。${var:-hoge}とか${var%/}とか(名前わからない)も使用可能。

molecule.yml
platforms:
  - name: instance
    image: ${DOCKER_IMAGE:-registry.example.com:5000/centos:7}

コンテナ内でsystemd起動させたい

molecule.yml
platforms:
# ~snip~
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:rw
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    command: /sbin/init
    capabilities:
      - SYS_ADMIN

Ansibleのhost_vars,group_varsを使用

molecule.yml
provisioner:
# ~snip~
  inventory:
    links:
      #hosts: ../../../inventory/hosts
      group_vars: ../../../..//group_vars/
      host_vars: ../../../../host_vars/

testフラグを立てる

molecule.yml
provisioner:
  name: ansible
  ansible_args:
    - "-e molecule_test=true"

さらにplaybookの中でwhen: not molecule_testをつければテストでスキップできる。

verifierをtestinfraに変更する

個人的にはAnsibleでプロビジョニングしたサーバをAsibleでテストすることに疑問を感じる。開発者の間でもかなり議論があった様子。
https://github.com/ansible-community/molecule/issues/2013

testinfraやInspecの学習コストが苦にならないならテストツールは分けるべきというのが個人的な意見なので変更する。

molecule.yml
verifier:
  name: testinfra

molecule.ymlカスタマイズ例

molecule.yml
---
dependency:
  name: galaxy
driver:
  name: docker
lint: |
  yamllint .
  ansible-lint -x 701,703
  flake8
platforms:
  - name: instance
    image: ${DOCKER_IMAGE:-registry.example.com:5000/centos:7}
    pull: true
    pre_build_image: true
    privileged: true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:rw
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    command: /sbin/init
    capabilities:
      - SYS_ADMIN
provisioner:
  name: ansible
  ansible_args:
    - "-e molecule_test=true"
  inventory:
    links:
      #hosts: ../../../inventory/hosts
      group_vars: ../../../..//group_vars/
      host_vars: ../../../../host_vars/
verifier:
  name: ansible

参考