👋

ansible + moleculeの環境構築

に公開

目的

ansible + moleculeが動くまでの最低限の環境を作成する手順を記載する
2025/08時点で検索で出てくるのは古い記事ばかりで手間取ったり、最小の構成でやりたかったので記事にした

最終目標としては、ansible + molecule + dockerで複数のUbuntuでテストをできるのを最終目的とするが、今回の記事は環境構築と最小限の動作確認まで

ansibleのインストール

参考文献:
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#pip-install

pythonのバージョンの確認

python3 -m pip -V
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)

なかったら、pythonをインストール

ansibleのインストール

python3 -m pip install --user ansible

ansibleのバージョンの確認

ansible --version
mozyanari@mozyanari-desktop:~$ ansible --version
ansible [core 2.17.13]
  config file = None
  configured module search path = ['/home/mozyanari/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mozyanari/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/mozyanari/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/mozyanari/.local/bin/ansible
  python version = 3.10.12 (main, May 27 2025, 17:12:29) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True
ansible collection locationについて

moleculeでansible collection locationはmoleculeでroleを探すときのパスになっているので、実はここの下にroleを作るのが一番簡単だが、「.ansible」の下にgit cloneするのはあまりないので、自分でroleを認識するパスは指定する

moleculeのインストール

参考文献
https://ansible.readthedocs.io/projects/molecule/installation/#install

$ python3 -m pip install --user molecule
mozyanari@mozyanari-desktop:~$ molecule --version
molecule 25.7.0 using python 3.10 
    ansible:2.17.13
    default:25.7.0 from molecule

Dockerのインストール

参考文献
https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository

mozyanari@mozyanari-desktop:~$ docker -v
Docker version 27.4.1, build b9d17ea

Dockerでpythonで使うためのライブラリ

pip install --user docker

moleculeのプラグインをインストール

pip install molecule-plugins

ansible + moleculeのフレームワークでテストが動くかをチェック

taskの雛形を作成

mkdir molecule-test
ansible-galaxy init test_role

testsフォルダがありますがmoleculeのフレームワークを使いたいので、このtestsフォルダは使いません

検索したときに出てきたがエラーが出たコマンド
mozyanari@mozyanari-desktop:~/molecule-test/test_role$ ansible-galaxy init role apt_install --driver-name docker
usage: ansible-galaxy [-h] [--version] [-v] TYPE ...
ansible-galaxy: error: argument TYPE: invalid choice: 'init' (choose from 'collection', 'role')
...
mozyanari@mozyanari-desktop:~/molecule-test/test_role$ molecule init role a
Usage: molecule init [OPTIONS] COMMAND [ARGS]...
Try 'molecule init -h' for help.

Error: No such command 'role'.

moleculeのテストの雛形を作成

cd test_role
molecule init scenario --driver-name docker

meta/main.ymlを修正

galaxy_info:
  author: your name
  description: your role description
  company: your company (optional)
  role_name: test_role ←追加
  namespace: localhost ←追加

role_nameは作成したroleの名前(今回はtest_role)
namespaceはlocalhostに仮に設定した

これって自動で追加出来ないのか?

テストを動くか試す

cd ~/molecule-test/test_role
molecule test

下記の実行結果のようにデフォルで入っているテストを実行出来た

実行結果
mozyanari@mozyanari-desktop:~/molecule-test/test_role$ molecule test
WARNING  Driver docker does not provide a schema.
WARNING  Driver docker does not provide a schema.
INFO     default ➜ discovery: scenario test matrix: dependency, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy
INFO     default ➜ prerun: Performing prerun with role_name_check=0...
INFO     default ➜ dependency: Starting
WARNING  default ➜ dependency: Skipping, missing the requirements file.
WARNING  default ➜ dependency: Skipping, missing the requirements file.
INFO     default ➜ dependency: Completed
INFO     default ➜ cleanup: Starting
WARNING  default ➜ cleanup: Skipping, cleanup playbook not configured.
INFO     default ➜ cleanup: Completed
INFO     default ➜ destroy: Starting
INFO     default ➜ destroy: ansible-playbook version: ansible-playbook 
  config file = None
  configured module search path = ['/home/mozyanari/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mozyanari/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/mozyanari/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/mozyanari/.local/bin/ansible-playbook
  python version = 3.10.12 (main, May 27 2025, 17:12:29)  (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True
INFO     Sanity checks: 'docker'

PLAY [Destroy] *****************************************************************

TASK [Set async_dir for HOME env] **********************************************
ok: [localhost]

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: [localhost]: Wait for instance(s) deletion to complete (300 retries left).
ok: [localhost] => (item=instance)

TASK [Delete docker networks(s)] ***********************************************
skipping: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     default ➜ destroy: Completed
INFO     default ➜ syntax: Starting
INFO     default ➜ syntax: ansible-playbook version: ansible-playbook 
  config file = None
  configured module search path = ['/home/mozyanari/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mozyanari/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/mozyanari/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/mozyanari/.local/bin/ansible-playbook
  python version = 3.10.12 (main, May 27 2025, 17:12:29)  (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True

playbook: /home/mozyanari/molecule-test/test_role/molecule/default/converge.yml
INFO     default ➜ syntax: Completed
INFO     default ➜ create: Starting
INFO     default ➜ create: ansible-playbook version: ansible-playbook 
  config file = None# 環境
Ubuntu
  configured module search path = ['/home/mozyanari/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mozyanari/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/mozyanari/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/mozyanari/.local/bin/ansible-playbook
  python version = 3.10.12 (main, May 27 2025, 17:12:29)  (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True

PLAY [Create] ******************************************************************

TASK [Set async_dir for HOME env] **********************************************
ok: [localhost]

TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item=None) 
skipping: [localhost]

TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item=instance)

TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item=instance) 
skipping: [localhost]

TASK [Synchronization the context] *********************************************
skipping: [localhost] => (item=instance) 
skipping: [localhost]

TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item=unix://var/run/docker.sock)

TASK [Create docker network(s)] ************************************************
skipping: [localhost]

TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/quay.io/centos/centos:stream8) 
skipping: [localhost]

TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item=instance)

TASK [Create molecule ins簡単な構成管理のコードを作成tance(s)] *********************************************
changed: [localhost] => (item=instance)

TASK [Wait for instance(s) creation to complete] *******************************
FAILED - RETRYING: [localhost]: Wait for instance(s) creation to complete (300 retries left).
FAILED - RETRYING: [localhost]: Wait for instance(s) creation to complete (299 retries left).
FAILED - RETRYING: [localhost]: Wait for instance(s) creation to complete (298 retries left).
changed: [localhost] => (item=instance)

PLAY RECAP *********************************************************************
localhost                  : ok=6    changed=2    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0

INFO     default ➜ create: Completed
INFO     default ➜ prepare: Starting
WARNING  default ➜ prepare: Skipping, prepare playbook not configured.
INFO     default ➜ prepare: Completed
INFO     default ➜ converge: Starting
INFO     default ➜ converge: ansible-playbook version: ansible-playbook 
  config file = None
  configured module search path = ['/home/mozyanari/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mozyanari/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/mozyanari/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/mozyanari/.local/bin/ansible-playbook
  python version = 3.10.12 (main, May 27 2025, 17:12:29)  (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True

PLAY [Converge] ****************************************************************

TASK [Replace this task with one that validates your content] ******************
ok: [instance] => {
    "msg": "This is the effective test"
}

PLAY RECAP *********************************************************************
instance                   : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     default ➜ converge: Completed
INFO     default ➜ idempotence: Starting
INFO     default ➜ idempotence: ansible-playbook version: ansible-playbook 
  config file = None
  configured module search path = ['/home/mozyanari/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mozyanari/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/mozyanari/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/mozyanari/.local/bin/ansible-playbook
  python version = 3.10.12 (main, May 27 2025, 17:12:29)  (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True

PLAY [Converge] ****************************************************************

TASK [Replace this task with one that validates your content] ******************
ok: [instance] => {
    "msg": "This is the effective test"
}

PLAY RECAP *********************************************************************
instance                   : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     default ➜ idempotence: Idempotence completed successfully.
INFO     default ➜ idempotence: Completed
INFO     default ➜ side_effect: Starting
WARNING  default ➜ sideeffect: Skipping, side effect playbook not configured.
INFO     default ➜ side_effect: Completed
INFO     default ➜ verify: Starting
INFO     default ➜ verify: Running Ansible Verifier
WARNING  default ➜ verify: Skipping, verify playbook not configured.
INFO     default ➜ verify: Verifier completed successfully.
INFO     default ➜ verify: Completed
INFO     default ➜ cleanup: Starting
WARNING  default ➜ cleanup: Skipping, cleanup playbook not configured.
INFO     default ➜ cleanup: Completed
INFO     default ➜ destroy: Starting
INFO     default ➜ destroy: ansible-playbook version: ansible-playbook 
  config file = None
  configured module search path = ['/home/mozyanari/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mozyanari/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/mozyanari/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/mozyanari/.local/bin/ansible-playbook
  python version = 3.10.12 (main, May 27 2025, 17:12:29)  (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True

PLAY [Destroy] *****************************************************************

TASK [Set async_dir for HOME env] **********************************************
ok: [localhost]

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: [localhost]: Wait for instance(s) deletion to complete (300 retries left).
changed: [localhost] => (item=instance)

TASK [Delete docker networks(s)] ***********************************************
skipping: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     default ➜ destroy: Completed
INFO     default ➜ scenario: Pruning extra files from scenario ephemeral directory

まとめ

今回の手順でmoleculeが最低限動くことが確認出来た
フォルダ構成は下記のようになった

mozyanari@mozyanari-desktop:~/molecule-test$ tree -L 4
.
└── test_role
    ├── README.md
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── molecule
    │   └── default
    │       ├── converge.yml
    │       ├── molecule.yml
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml
GitHubで編集を提案

Discussion