ansible-lintとMoleculeによるコード検証入門|静的解析とroleテストで変更事故を防ぐ

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Ansible > ansible-lintとMoleculeによるコード検証入門|静的解析とroleテストで変更事故を防ぐ
「Playbookに変更を加えたら、本番サーバーで想定外の動作が起きた。commitする前に問題を検出できていれば」
Ansibleの運用経験が増えるほど、こういったヒヤリハットが積み重なっていきます。

ansible-lintとMoleculeを組み合わせれば、コードを実際に本番へ流す前に大多数の問題を事前検出できます。ansible-lintが構文・スタイルの静的解析を担い、Moleculeがroleの実行テストと冪等性確認を担います。この2段構えの仕組みをCIに組み込めば、Pushのたびに自動でコード品質を守れます。

この記事では、RHEL 10 / Rocky Linux 9の実行環境を前提に、ansible-lintのインストールから.ansible-lintでのルール調整、Moleculeの初期化からmolecule testの全フェーズ実行、そしてGitHub Actionsへの組み込みまでを手順ごとに解説します。

この記事のポイント

・ansible-lintはPlaybookとroleのコード品質違反を静的解析で即座に検出するツール
・Moleculeはroleをコンテナで実行して冪等性テストを自動化するフレームワーク
・molecule testで全フェーズ(create/converge/idempotence/verify/destroy)を一括実行できる
・GitHub Actionsに組み込めばPushごとにlintとroleテストが自動実行される


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

なぜansible-lintとMoleculeが必要なのか|手作業チェックの限界

Ansibleは「書いてすぐ動く」手軽さが魅力ですが、その手軽さが落とし穴になることがあります。

yes/noを真偽値として使っているコードがバージョンアップで警告に変わる
・モジュール名を短縮形(yum)で書いているとFQCN(完全修飾コレクション名)への移行で動作が変わる
・roleの途中でエラーが起きてもignore_errors: yesで握り潰していると、実は冪等でない処理が混入している

これらを人間の目視だけでチェックするのは限界があります。特にチーム開発では「誰かがレビューするだろう」という抜け漏れが積み重なります。

ansible-lintの役割

ansible-lintはAnsibleコードに対して静的解析を実行するツールです。実際にコマンドを実行せずに、コードを解析してルール違反を報告します。主な検出対象は以下のとおりです。

YAML構文の問題: インデントや真偽値の書き方(yes/noは非推奨)
FQCN違反: yum/copy等の短縮形はansible.builtin.yum/ansible.builtin.copyに変更が推奨
冪等性の疑い(要注意): command/shellモジュールでchanged_when: falseなし等
命名規則: task名がない、role名がスネークケースでない等

Moleculeの役割

Moleculeはroleを実際のコンテナや仮想環境で実行してテストするフレームワークです。単純に「エラーなく動いた」ではなく、「2回実行しても結果が同じか(冪等性)」「意図した状態になっているか(verify)」まで自動確認します。

ansible-lintが「設計図に誤りがないか」を確認するとすれば、Moleculeは「実際に建てたら設計通りに仕上がるか」を確認する工程です。

ansible-lintの基本的な使い方

1. ansible-lintのインストールと動作確認

ansible-lintはPython製のツールで、pipで導入します。RHEL 10 / Rocky Linux 9ではPython 3.11以上が標準で利用できます。

# 仮想環境を作成してansible-lintをインストール(推奨) python3 -m venv ~/.venv/ansible source ~/.venv/ansible/bin/activate # ansible-coreとansible-lintをインストール pip install ansible-core ansible-lint # バージョン確認 ansible-lint --version

上のコマンドを実行すると、以下のような出力が確認できます。

ansible-lint 25.1.0 using ansible-core:2.17.8 ansible:10.7.0 python:3.11.9 config-file: None rulesdir: /home/user/.venv/ansible/lib/python3.11/site-packages/ansiblelint/rules

ansible-lintansible-coreのバージョンの組み合わせが表示されます。ansible-core 2.17以上を使う場合はansible-lint 25.x系を使うのが基本です。

2. PlaybookとRoleを対象に実行する

最もシンプルな実行はPlaybookファイルを引数に渡す方法です。

# Playbookを直接対象にする ansible-lint site.yml # roleディレクトリ全体をチェックする ansible-lint roles/webserver/ # カレントディレクトリ配下を全部スキャンする ansible-lint

違反があると次のような出力が表示されます。

WARNING Listing 3 violation(s) that are fatal yaml[truthy]: Use 'true' instead of 'yes'. (Line: 12, Column: 9) yaml[truthy]: Use 'false' instead of 'no'. (Line: 24, Column: 9) fqcn[action-core]: Use FQCN for builtin actions: yum -> ansible.builtin.yum Action: yum [roles/webserver/tasks/main.yml:8] Finished with 3 failure(s), 0 warning(s) on 2 files.

yaml[truthy]はYAML真偽値の書き方、fqcn[action-core]はFQCNへの変更が必要な箇所です。それぞれ以下のように修正します。

# yaml[truthy] の修正例 # 修正前 - name: Ensure httpd is enabled ansible.builtin.service: name: httpd enabled: yes # ← NG # 修正後 - name: Ensure httpd is enabled ansible.builtin.service: name: httpd enabled: true # ← OK # fqcn[action-core] の修正例 # 修正前 - name: Install httpd yum: # ← NG(短縮形) name: httpd state: present # 修正後 - name: Install httpd ansible.builtin.dnf: # ← OK(RHEL 10はdnf推奨) name: httpd state: present

3. .ansible-lintでルールをカスタマイズする

プロジェクトルートに.ansible-lintファイルを置くことで、スキャン対象・除外ルール・警告レベルを細かく制御できます。

# .ansible-lint の設定例 --- # チェック対象のPlaybook/roleを明示(省略時はカレントディレクトリ全体) # lint_paths: # - site.yml # - roles/ # 特定のルールIDをスキップする(チームで合意した例外を記載) skip_list: - yaml[line-length] # 長い行を許容する場合 # 警告扱いにするルール(NG→警告に緩和) warn_list: - experimental # Moleculeのテスト用シナリオを除外(lint対象外にする) exclude_paths: - molecule/ - .git/ - .github/ # 実行環境プロファイル(min/basic/moderate/safety/shared/production) profile: production

profileproductionにすると最も厳格なルールセットが適用されます。チームで統一した.ansible-lintをリポジトリに含めることで、個人の環境差を排除できます。

MoleculeによるroleのテストフローをCIへ

1. Moleculeのインストールとrole初期化

Moleculeのドライバーとしてはdockerが最もよく使われます。検証機にDockerをインストールしておいてください。

# molecule本体とdockerドライバーをインストール pip install molecule molecule-plugins[docker] # バージョン確認 molecule --version

新規roleを作成する場合はmolecule init roleを使うと、roleのディレクトリ骨格とMoleculeのテスト設定が同時に生成されます。

# dockerドライバーでwebserverというroleを初期化 molecule init role --driver-name docker webserver # 生成されたディレクトリ構造を確認 find webserver -type f | sort

webserver/ defaults/ main.yml handlers/ main.yml meta/ main.yml molecule/ default/ converge.yml ← roleを適用するシナリオPlaybook molecule.yml ← テスト環境の定義ファイル verify.yml ← 検証タスクの定義ファイル tasks/ main.yml vars/ main.yml

既存roleにMoleculeを追加する場合はroleのディレクトリでmolecule init scenarioを実行します。

# 既存roleのディレクトリに移動してMoleculeシナリオを追加 cd roles/webserver molecule init scenario --driver-name docker default

2. molecule.ymlのシナリオ設計(platforms・driver設定)

molecule.ymlはテスト環境全体の設定ファイルです。どのコンテナイメージを使うか、どのドライバーを使うかを定義します。

# molecule/default/molecule.yml --- dependency: name: galaxy driver: name: docker platforms: - name: instance # RHEL 10互換のRocky Linux 9イメージ(systemdが使えるAnsiblize済みイメージ) image: geerlingguy/docker-rockylinux9-ansible pre_build_image: true # systemdを使うサービス管理が必要な場合 command: /usr/sbin/init privileged: false volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro tmpfs: - /run - /tmp provisioner: name: ansible config_options: defaults: interpreter_python: auto_silent env: ANSIBLE_FORCE_COLOR: "1" verifier: name: ansible lint: | set -e ansible-lint

platformsには複数のOSを並べることで、RHEL 10互換・Ubuntu 24.04の両方でテストするマトリクス実行も可能です。

3. verify.ymlで検証タスクを定義する

verify.ymlはroleを適用した後の状態確認(assertion)を記述します。単に「エラーなく終わった」だけでなく、「サービスが起動しているか」「ポートが開いているか」を明示的に確認します。

# molecule/default/verify.yml --- - name: Verify hosts: all gather_facts: false tasks: - name: httpd サービスが起動していることを確認する ansible.builtin.service_facts: - name: httpdがactiveであることをassertする ansible.builtin.assert: that: - "'httpd.service' in ansible_facts.services" - "ansible_facts.services['httpd.service'].state == 'running'" fail_msg: "httpd は起動していません" success_msg: "httpd が正常に起動しています" - name: ポート80が開いていることを確認する ansible.builtin.wait_for: port: 80 timeout: 10

4. molecule testで全フローを実行する

molecule testを実行すると、destroy→syntax→create→converge→idempotence→verify→destroyの全フェーズが自動で実行されます。

# テストシナリオ全体を実行する molecule test # または個別フェーズだけ実行する(開発中に便利) molecule create # コンテナを起動する molecule converge # roleを適用する molecule idempotence # 2回目の適用で変更なしを確認する molecule verify # verify.ymlの検証タスクを実行する molecule destroy # コンテナを削除する

molecule testの出力例です。Idempotence completed successfully.が表示されれば冪等性OK、Verifier completed successfully.が表示されれば検証もOKです。

INFO Running default > create PLAY [Create] ****************************************************************** TASK [Create molecule instance(s)] ******************************************** changed: [localhost] PLAY RECAP ********************************************************************* localhost : ok=2 changed=1 unreachable=0 failed=0 INFO Running default > converge PLAY [Converge] **************************************************************** TASK [Gathering Facts] ********************************************************* ok: [instance] TASK [webserver : Install httpd] *********************************************** changed: [instance] TASK [webserver : Start and enable httpd] ************************************** changed: [instance] PLAY RECAP ********************************************************************* instance : ok=3 changed=2 unreachable=0 failed=0 INFO Running default > idempotence TASK [webserver : Install httpd] *********************************************** ok: [instance] TASK [webserver : Start and enable httpd] ************************************** ok: [instance] PLAY RECAP ********************************************************************* instance : ok=3 changed=0 unreachable=0 failed=0 INFO Idempotence completed successfully. INFO Running default > verify TASK [httpd サービスが起動していることを確認する] ***** ok: [instance] TASK [httpdがactiveであることをassertする] ***** ok: [instance] INFO Verifier completed successfully. INFO Running default > destroy PLAY RECAP ********************************************************************* instance : ok=2 changed=1 unreachable=0 failed=0

idempotenceフェーズではchanged=0になることが必須です。changed=1以上になると「冪等性テスト失敗」として処理が止まります。

roleの設計とテストフローを実機でハンズオン体験したい方は、>> Ansibleハンズオン講座の詳細を見る をご覧ください。

GitHub ActionsでCI/CDパイプラインに組み込む

ansible-lintとMoleculeをGitHub Actionsに組み込むことで、Pull Requestのたびに自動でコード品質チェックが走ります。

1. ワークフローファイルの作成

.github/workflows/ansible-ci.ymlとして以下のファイルをリポジトリに含めます。

# .github/workflows/ansible-ci.yml --- name: Ansible CI on: push: branches: [main, develop] pull_request: branches: [main] jobs: lint: name: ansible-lint runs-on: ubuntu-latest steps: - name: コードをチェックアウトする uses: actions/checkout@v4 - name: Python環境をセットアップする uses: actions/setup-python@v5 with: python-version: "3.11" - name: ansible-lintをインストールする run: pip install ansible-core ansible-lint - name: ansible-lintを実行する run: ansible-lint molecule: name: Molecule Test runs-on: ubuntu-latest needs: lint # lintが通過してからtestを実行する strategy: matrix: role: - webserver - dbserver steps: - name: コードをチェックアウトする uses: actions/checkout@v4 - name: Python環境をセットアップする uses: actions/setup-python@v5 with: python-version: "3.11" - name: MoleculeとDockerドライバーをインストールする run: pip install ansible-core molecule molecule-plugins[docker] - name: Moleculeテストを実行する working-directory: roles/${{ matrix.role }} run: molecule test env: PY_COLORS: "1" ANSIBLE_FORCE_COLOR: "1"

needs: lintを設定することで、ansible-lintが通過したroleだけMoleculeテストを実行します。静的解析でNGになったコードをコンテナ起動の費用を使ってテストする無駄を省けます。

2. PRチェックとキャッシュ最適化のTips

pipキャッシュ: actions/cacheでpipパッケージをキャッシュするとジョブ時間を40%以上短縮できる
Dockerイメージのキャッシュ: GHA(GitHub Actions)上でDockerイメージをpullする時間が長い場合はpre_build_image: falseにしてGHAキャッシュと組み合わせる方法もある
Branch protectionルール: リポジトリの設定でmainブランチのPRにansible-lintとMoleculeジョブのステータスチェックを必須化すると、CI通過前のマージを防げる

トラブルシュート|よくあるエラーと対処法

「yaml[truthy]: Use 'true' instead of 'yes'」が大量に出る

原因: 古いPlaybookやroleでyes/noを真偽値として使っている。YAML 1.2以降ではこれらは文字列として扱われる変更が行われており、ansible-lintはYAML 1.2準拠のルールで警告する。

対処: プロジェクト全体を一括置換する。

# enabled: yes を enabled: true に一括置換(バックアップ付き) find . -name "*.yml" -not -path "./molecule/*" -exec sed -i.bak 's/: yes$/: true/g' {} \; # バックアップファイルを削除する find . -name "*.yml.bak" -delete

一括置換後にansible-lintを再実行して他の違反がないことを確認してください。

「TASK [Create molecule instance(s)] FAILED!」が出る

原因: Dockerデーモンが起動していない、または現在のユーザーがdockerグループに属していない。

対処: 検証機でDockerの状態を確認する。

# Dockerデーモンの状態を確認する systemctl status docker # 起動していなければ起動する sudo systemctl start docker sudo systemctl enable docker # 現在のユーザーをdockerグループに追加する(再ログイン必要) sudo usermod -aG docker $USER # グループ変更を即時反映する(ログアウト不要) newgrp docker # 動作確認 docker run --rm hello-world

「Idempotence test failed」が出る

原因: 2回目のmolecule convergeでもchangedタスクが残っている。roleの設計が冪等でない箇所がある。

典型的なパターンと対処法:

command/shellモジュールの無条件実行: createsパラメータかchanged_when/when条件を追加する

# NG: 毎回変更ありになる - name: アーカイブを展開する ansible.builtin.command: tar xzf /tmp/app.tar.gz -C /opt/app # OK: 展開済みならスキップする - name: アーカイブを展開する ansible.builtin.command: tar xzf /tmp/app.tar.gz -C /opt/app args: creates: /opt/app/bin/app # このファイルが存在すればスキップ

ファイルのタイムスタンプが毎回変わる: ansible.builtin.templateansible.builtin.copyでコンテンツが同一ならchangedにならない。差分が生まれているなら元ファイルとテンプレートの内容を見直す
サービス再起動の無条件実行: notifyhandlersを使って「設定ファイルが変更されたときのみ再起動」に変える

本記事のまとめ

やりたいこと コマンド/設定
ansible-lintをインストールする pip install ansible-core ansible-lint
Playbookを静的解析する ansible-lint site.yml
ルールをカスタマイズする プロジェクトルートに.ansible-lintを配置する
MoleculeとDockerドライバーをインストールする pip install molecule molecule-plugins[docker]
新規roleとMoleculeシナリオを生成する molecule init role --driver-name docker role名
既存roleにMoleculeシナリオを追加する molecule init scenario --driver-name docker default
テストの全フェーズを一括実行する molecule test
convergeだけ実行する(開発中のデバッグ) molecule converge
冪等性チェックだけ実行する molecule idempotence
verify.ymlの検証タスクだけ実行する molecule verify
ansible-lintとMoleculeは、単独でも有効ですが組み合わせることで最大の効果を発揮します。ansible-lintで構文・スタイル・FQCNの問題を事前に除去し、Moleculeで実際のコンテナ上での動作と冪等性を自動確認する。この2段階のゲートをGitHub ActionsのCI/CDに組み込んで自動化することで、チーム全体のPlaybook品質を継続的に守れます。

「変更するたびに本番で何かが壊れるかもしれない」という不安から解放され、安心してroleを改善し続けられる開発体制への第一歩です。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Ansible実践ハンズオンの詳細を見る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。