Ansible MoleculeとGitHub ActionsでCI/CDを体験してみた
概要
以前Moleculeを使ってRoleのテストをしてみた記事を書きました。
今回はその時に使ったRoleを基にGitHub ActionsによるCI/CD、テストの自動化を行なっていこうと思います。Moleculeについて
MoleculeはAnsible Roleのテストを支援してくれるためのツールです。
(2020/10現在のAnsibleの最新安定バージョンは2.9系なため、2.8系までサポート対象です)
molecule test
を実行することで、構文規約のチェックからテスト用環境の構築、テスト用環境内でのRoleの実行、テストが終了した開発環境の破棄までを行なってくれる便利なツールです。
GitHub Actionsについて
GitHub ActionsはGitHub社が提供するCI/CDツールです。
GitHubのリポジトリに対して、プッシュしたりPRしたりすると、ソースコードのビルド、テスト、デプロイなどを自動で行なってくれます。ワークフロー
GitHub Actionsはワークフローという単位で一連の処理を自動化します。
ソフトウェアのビルド、パッケージ作成、デプロイなどを処理をワークフローとして自動化できます。またGitHub ActionsはIssueやPRが発行されたときにSlackへ通知する作業もワークフローとして自動化できます。
イベント
ワークフローを起動させるトリガーになるものをイベントと呼びます。例としてリポジトリへのコミットのプッシュ、PR作成、タグ・リリースの作成などがあります。
ジョブ
ワークフローは1つ以上のジョブで構成されており、ジョブの中身が一連のステップとなっております。複数のジョブをワークフローに設定でき、同時並行の実行や、Aジョブが完了したらBジョブを起動するといった依存関係の設定も行なえます。
ステップ
ジョブは1つ以上のステップから構成されており、ステップはアクションを実行できる個々のタスクとなっております。
アクション
アクションが実際の処理をまとめたGitHub Actionsの最小のコンポーネントとなっております。
独自にアクションも作成できますが、GitHubの公式に用意されているアクションもいくつかあります。
ランナー
ランナーはジョブを実行するためのGitHubが用意している仮想環境です。現在用意されている仮想環境は
- Ubuntu
- Windows
- Mac
以上3つが用意されています。(それぞれの最新バージョン以外もちろん使用可能。Fedora系は残念ながらないようです。)
やること
以前の記事で作成したリポジトリにGitHub Actionsを導入して、テストの自動化を行ないます。
使うリポジトリはこちらです。
またテストの内容自体はSoftware Design2020年6月号で紹介されている単純なものを使用しております。
テスト準備
まずはMoleculeをインストールしてみます
基本的には公式リファレンス通り進めば問題ありません。前提条件として、AnsibleとPython3系がインストールされている必要があります。
pip install --user "molecule[docker,lint]"
pipパッケージからインストールできまして、インストールが完了されましたら、テンプレート構成を作成します。
$ molecule --version
molecule 3.1.5
ansible:2.9.13 python:3.8
delegated:3.1.5 from molecule
docker:0.2.4 from molecule_docker
$ molecule init role testmol
--> Initializing new role testmol...
Initialized role in /home/yuta/Desktop/work/ansible/molecule/testmol successfully.
$ tree
.
├── README.md
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── molecule
│ └── default
│ ├── INSTALL.rst
│ ├── converge.yml
│ ├── create.yml
│ ├── destroy.yml
│ ├── molecule.yml
│ └── verify.yml
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
10 directories, 14 files
molecule init role ロール名
でカレントディレクトリにロール名のディレクトリが作成され、その直下にmoleculeのテンプレートディレクトリが作成されます。
この時molecule/default
配下にcreate.yml
とdestory.yml
がありますが、今回の検証では使わないうえ、放置したままmolecule test
を実行しますとテスト動作が上手くいかないことがありますので、削除しておきます。(ローカルマシンがCentOS 8のときはこの2つのファイルは作成されていなかったのですが、OSによるものなのかMoleculeのバージョン更新が原因なのかはいまいち理由がよくわかっていません)
2020/11/21追記
上記の件についてTeratailで質問したところ、Moleculeのバージョン更新によるものとわかりました。
moleculeは3.1.0(α版含む)からデフォルトドライバがdelegatedになったので、最新版だと自動的に
create.yml
とdestroy.yml
が作成されるようになりました。
molecule
ディレクトリに、テスト実行のための環境実装ファイルやテスト項目ファイルなどを配置します。molecule/default/molecule.yml
の中身を以下のように書き換えます。
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: instance1
image: docker.io/centos:7
pre_build_image: true
privileged: True
command: /sbin/init
- name: instance2
image: docker.io/centos:8
pre_build_image: true
privileged: True
command: /sbin/init
provisioner:
name: ansible
verifier:
name: ansible
テスト実行用のCentoS7,8のDockerコンテナをビルドしています。
次に、tasks/main.yml
にテスト対象となるタスクを記載します。
---
# tasks file for testmol
- name: install httpd package
yum:
name: httpd
state: latest
- name: start httpd
systemd:
name: httpd
state: started
enabled: yes
ご覧の通り、内容としてはApacheをインストールして、起動しているだけのシンプルな実装となっております。このタスクに対するテストをmolecule/default/verify.yml
に記載します。
---
# This is httpd install playbook to execute Ansible tests.
- name: Verify
hosts: all
tasks:
- ignore_errors: yes
block:
- name: httpdパッケージの存在を確認する
yum:
list: httpd
register: result_rpm
- name: httpdプロセスが起動していることを確認する
shell: ps -ef | grep http[d]
register: result_proc
- name: httpdサービスが自動起動になっているかを確認する
shell: systemctl is-enabled httpd
register: result_enabled
- name: 結果をまとめて確認する
assert:
that: "{{ result.failed == false }}"
loop:
- "{{ result_rpm }}"
- "{{ result_proc }}"
- "{{ result_enabled }}"
loop_control:
loop_var: result
これでテストの準備が完了しましたので、molecule test
で実行します。
$ molecule test
--> Test matrix
└── default
├── dependency
├── lint
├── cleanup
├── destroy
├── syntax
├── create
├── prepare
├── converge
├── idempotence
├── side_effect
├── verify
├── cleanup
└── destroy
--> Scenario: 'default'
--> Action: 'dependency'
Skipping, missing the requirements file.
Skipping, missing the requirements file.
--> Scenario: 'default'
--> Action: 'lint'
--> Lint is disabled.
--> 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=instance1)
changed: [localhost] => (item=instance2)
TASK [Wait for instance(s) deletion to complete] *******************************
ok: [localhost] => (item=None)
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Delete docker network(s)] ************************************************
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
--> Scenario: 'default'
--> Action: 'syntax'
playbook: /home/yuta/Desktop/work/docker/ansible-Molecule/testmol/molecule/default/converge.yml
--> Scenario: 'default'
--> Action: 'create'
PLAY [Create] ******************************************************************
TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item=None)
skipping: [localhost] => (item=None)
TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item=None)
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item=None)
skipping: [localhost] => (item=None)
TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item=None)
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/docker.io/centos:7)
skipping: [localhost] => (item=molecule_local/docker.io/centos:8)
TASK [Create docker network(s)] ************************************************
TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item=None)
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=instance1)
changed: [localhost] => (item=instance2)
TASK [Wait for instance(s) creation to complete] *******************************
changed: [localhost] => (item=None)
FAILED - RETRYING: Wait for instance(s) creation to complete (300 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.
--> Scenario: 'default'
--> Action: 'converge'
PLAY [Converge] ****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance2]
ok: [instance1]
TASK [Include testmol] *********************************************************
TASK [testmol : install httpd package] *****************************************
changed: [instance2]
changed: [instance1]
TASK [testmol : start httpd] ***************************************************
changed: [instance2]
changed: [instance1]
PLAY RECAP *********************************************************************
instance1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
instance2 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
--> Scenario: 'default'
--> Action: 'idempotence'
Idempotence completed successfully.
--> Scenario: 'default'
--> Action: 'side_effect'
Skipping, side effect playbook not configured.
--> Scenario: 'default'
--> Action: 'verify'
--> Running Ansible Verifier
PLAY [Verify] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance2]
ok: [instance1]
TASK [httpdパッケージの存在を確認する] ******************************************************
ok: [instance2]
ok: [instance1]
TASK [httpdプロセスが起動していることを確認する] *************************************************
changed: [instance2]
changed: [instance1]
TASK [httpdサービスが自動起動になっているかを確認する] **********************************************
changed: [instance2]
changed: [instance1]
TASK [結果をまとめて確認する] *************************************************************
ok: [instance1] => (item={'results': [{'envra': '0:httpd-2.4.6-93.el7.centos.x86_64', 'name': 'httpd', 'repo': 'base', 'epoch': '0', 'version': '2.4.6', 'release': '93.el7.centos', 'yumstate': 'available', 'arch': 'x86_64'}, {'envra': '0:httpd-2.4.6-93.el7.centos.x86_64', 'name': 'httpd', 'repo': 'installed', 'epoch': '0', 'version': '2.4.6', 'release': '93.el7.centos', 'yumstate': 'installed', 'arch': 'x86_64'}], 'failed': False, 'changed': False}) => {
"ansible_loop_var": "result",
"changed": false,
"msg": "All assertions passed",
"result": {
"changed": false,
"failed": false,
"results": [
{
"arch": "x86_64",
"envra": "0:httpd-2.4.6-93.el7.centos.x86_64",
"epoch": "0",
"name": "httpd",
"release": "93.el7.centos",
"repo": "base",
"version": "2.4.6",
"yumstate": "available"
},
{
"arch": "x86_64",
"envra": "0:httpd-2.4.6-93.el7.centos.x86_64",
"epoch": "0",
"name": "httpd",
"release": "93.el7.centos",
"repo": "installed",
"version": "2.4.6",
"yumstate": "installed"
}
]
}
}
ok: [instance2] => (item={'msg': '', 'results': [{'name': 'httpd', 'arch': 'x86_64', 'epoch': '0', 'release': '21.module_el8.2.0+494+1df74eae', 'version': '2.4.37', 'repo': '@System', 'nevra': '0:httpd-2.4.37-21.module_el8.2.0+494+1df74eae.x86_64', 'yumstate': 'installed'}, {'name': 'httpd', 'arch': 'x86_64', 'epoch': '0', 'release': '21.module_el8.2.0+494+1df74eae', 'version': '2.4.37', 'repo': 'AppStream', 'nevra': '0:httpd-2.4.37-21.module_el8.2.0+494+1df74eae.x86_64', 'yumstate': 'available'}], 'failed': False, 'changed': False}) => {
"ansible_loop_var": "result",
"changed": false,
"msg": "All assertions passed",
"result": {
"changed": false,
"failed": false,
"msg": "",
"results": [
{
"arch": "x86_64",
"epoch": "0",
"name": "httpd",
"nevra": "0:httpd-2.4.37-21.module_el8.2.0+494+1df74eae.x86_64",
"release": "21.module_el8.2.0+494+1df74eae",
"repo": "@System",
"version": "2.4.37",
"yumstate": "installed"
},
{
"arch": "x86_64",
"epoch": "0",
"name": "httpd",
"nevra": "0:httpd-2.4.37-21.module_el8.2.0+494+1df74eae.x86_64",
"release": "21.module_el8.2.0+494+1df74eae",
"repo": "AppStream",
"version": "2.4.37",
"yumstate": "available"
}
]
}
}
ok: [instance1] => (item={'changed': True, 'end': '2020-11-03 07:59:36.635845', 'stdout': 'root 363 1 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 364 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 365 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 366 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 367 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 368 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'cmd': 'ps -ef | grep http[d]', 'rc': 0, 'start': '2020-11-03 07:59:35.547485', 'stderr': '', 'delta': '0:00:01.088360', 'stdout_lines': ['root 363 1 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 364 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 365 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 366 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 367 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 368 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND'], 'stderr_lines': [], 'failed': False}) => {
"ansible_loop_var": "result",
"changed": false,
"msg": "All assertions passed",
"result": {
"changed": true,
"cmd": "ps -ef | grep http[d]",
"delta": "0:00:01.088360",
"end": "2020-11-03 07:59:36.635845",
"failed": false,
"rc": 0,
"start": "2020-11-03 07:59:35.547485",
"stderr": "",
"stderr_lines": [],
"stdout": "root 363 1 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 364 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 365 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 366 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 367 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 368 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"stdout_lines": [
"root 363 1 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 364 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 365 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 366 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 367 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 368 363 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND"
]
}
}
ok: [instance2] => (item={'cmd': 'ps -ef | grep http[d]', 'stdout': 'root 404 1 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 429 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 431 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 432 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 433 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'stderr': '', 'rc': 0, 'start': '2020-11-03 07:59:35.568724', 'end': '2020-11-03 07:59:35.587274', 'delta': '0:00:00.018550', 'changed': True, 'stdout_lines': ['root 404 1 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 429 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 431 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 432 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND', 'apache 433 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND'], 'stderr_lines': [], 'failed': False}) => {
"ansible_loop_var": "result",
"changed": false,
"msg": "All assertions passed",
"result": {
"changed": true,
"cmd": "ps -ef | grep http[d]",
"delta": "0:00:00.018550",
"end": "2020-11-03 07:59:35.587274",
"failed": false,
"rc": 0,
"start": "2020-11-03 07:59:35.568724",
"stderr": "",
"stderr_lines": [],
"stdout": "root 404 1 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 429 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 431 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 432 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND\napache 433 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"stdout_lines": [
"root 404 1 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 429 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 431 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 432 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND",
"apache 433 404 0 07:58 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND"
]
}
}
ok: [instance1] => (item={'changed': True, 'end': '2020-11-03 07:59:39.966874', 'stdout': 'enabled', 'cmd': 'systemctl is-enabled httpd', 'rc': 0, 'start': '2020-11-03 07:59:38.881374', 'stderr': '', 'delta': '0:00:01.085500', 'stdout_lines': ['enabled'], 'stderr_lines': [], 'failed': False}) => {
"ansible_loop_var": "result",
"changed": false,
"msg": "All assertions passed",
"result": {
"changed": true,
"cmd": "systemctl is-enabled httpd",
"delta": "0:00:01.085500",
"end": "2020-11-03 07:59:39.966874",
"failed": false,
"rc": 0,
"start": "2020-11-03 07:59:38.881374",
"stderr": "",
"stderr_lines": [],
"stdout": "enabled",
"stdout_lines": [
"enabled"
]
}
}
ok: [instance2] => (item={'cmd': 'systemctl is-enabled httpd', 'stdout': 'enabled', 'stderr': '', 'rc': 0, 'start': '2020-11-03 07:59:39.213457', 'end': '2020-11-03 07:59:39.235024', 'delta': '0:00:00.021567', 'changed': True, 'stdout_lines': ['enabled'], 'stderr_lines': [], 'failed': False}) => {
"ansible_loop_var": "result",
"changed": false,
"msg": "All assertions passed",
"result": {
"changed": true,
"cmd": "systemctl is-enabled httpd",
"delta": "0:00:00.021567",
"end": "2020-11-03 07:59:39.235024",
"failed": false,
"rc": 0,
"start": "2020-11-03 07:59:39.213457",
"stderr": "",
"stderr_lines": [],
"stdout": "enabled",
"stdout_lines": [
"enabled"
]
}
}
PLAY RECAP *********************************************************************
instance1 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
instance2 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verifier completed successfully.
--> Scenario: 'default'
--> Action: 'cleanup'
Skipping, cleanup playbook not configured.
--> Scenario: 'default'
--> Action: 'destroy'
PLAY [Destroy] *****************************************************************
TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance1)
changed: [localhost] => (item=instance2)
TASK [Wait for instance(s) deletion to complete] *******************************
changed: [localhost] => (item=None)
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の動きについて
Moleculeはmolecule test
コマンドでテストを実行することが可能となり、ステップという単位で処理が順次実行されます。
ステップの内容は以下の通りで順次実行され、Roleのテストを行ないます。
ステップ | 実施内容 |
---|---|
dependency | 依存関係を処理 |
lint | 規約チェック |
cleanup | 環境の掃除 |
destroy | テスト環境の削除 |
syntax | 構文チェック |
create | テスト環境の構築 |
prepare | テストの前処理を実行 |
converge | Roleの実行 |
idempotence | Roleの再実行 |
side_effect | テスト実行のための副作用を発生させる |
verify | テストの実行 |
clenup | 環境の掃除 |
destroy | テスト環境の削除 |
※引用 SoftwareDesign 2020/6月号 | |
https://gihyo.jp/magazine/SD/archive/2020/202006 | |
上記のコマンド結果はdefaultというシナリオのなかで必要なステップが順次実行されております。 | |
(ステップはすべて実行されることはなく、省略されているものもあります) | |
ここまででAnsible MoleculeでRoleのテストを行なえることができました。 | |
次からGitHub ActionsによるCI/CDの実装に入りたいと思います。 |
GitHub Action導入
GitHub Actionsの導入はGitHubのリポジトリ内にあるActionsタブから新規に作成することができます。
GitHubが用意したいくつかのテンプレートワークフローから適したものを選ぶこともできますし、自分で一から作成することもできます。
Ansible Moleculeの公式サイトにサンプルがありましたので、ここではSimple workflowを選択して一からセットアップします。
セットアップしますと、.github/workflows/
ディレクトリが作成されその中にワークフローを設定するYAMLファイルを編集します。
ここでは、公式サイトに記載されている情報を基にワークフローファイルを作成しました。
---
name: Molecule Test
on:
pull_request:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
# キャッシュを活用
- uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: ${{ runner.os }}-pip-
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install ansible
python3 -m pip install "molecule[docker,lint]"
- name: Test with molecule
run: |
cd testmol ; molecule test
公式のサンプルでは、pushしたらGitHub Actionsが動きますが個人的にはあまり好きではありませんので、masterブランチにPRしたらGitHub Actionsが動くように変更しました。
GitHub Actionsが動くとランナーが起動し、Ansible Molecule関連のモジュールインストールとテストが実行されます。
所感
Ansible ModuleとGitHub Actionsを組み合わせることでCI/CDの一端にふれることができました。GitHub Actionsはまだ新しいサービスで資料も少なかったですが、GitHubへコミット、プッシュすればすぐに開始されたり、ローカルマシン上に何かしらの用意する必要もないので触ってみて便利な代物だと思いました。会社ではCircle CIを使っていますのですぐに導入することはないかもしれませんが、今後の知見のために触ってみようと思います。
追記 2021/6/5
見返すと少し情報が古くなっていたり、理解が足りていないところがありましたので修正しました。
当初はdockerをランナー内にインストールして、docker内でテスト対象のインスタンスを起動させましたがいつの間にか公式のサンプルソースコードからdockerのインストールが削除されていてそのままでも実行できるようになっていました。
たまに古い記事を見返すもの新しい発見になっていいものだと思いました。
LT資料
LTのスライド資料です。
Discussion