Claude Media
Claude CodeでAnsibleのPlaybookを書く手順 — 冪等性の検証まで

Claude CodeでAnsibleのPlaybookを書く手順 — 冪等性の検証まで

Claude CodeにAnsibleのインベントリとPlaybookを生成させ、--checkと--diffで冪等性を検証する手順をまとめます。

Claude CodeにAnsibleのPlaybookを書かせると、YAMLの雛形作成やインベントリ設計の反復作業を短くできます。ただし生成したPlaybookをそのまま本番の管理対象ノードに向けて実行するのは危険です。この記事では、インベントリとPlaybookの作成から、--check--diffを使った冪等性(idempotency)の検証までを手順化します。

Claude CodeでAnsible Playbookを書くとはどんな作業か

Ansibleは、制御ノード(Ansibleをインストールしたマシン)から管理対象ノードへSSH経由で接続し、YAML形式のPlaybookに書いた状態を適用する構成管理ツールです。Claude CodeはAnsible専用の統合機能を持つわけではなく、他のコードを書かせる作業と同じ通常のコーディング支援として、インベントリファイルやPlaybookのYAMLを生成します。

Ansibleの環境は3つの要素で構成されます。Ansibleをインストールしansibleansible-playbookコマンドを実行する制御ノード、管理対象ノードを論理的にまとめたインベントリ、そして実際に操作される管理対象ノードです。Claude Codeが担うのは、このうちインベントリとPlaybookのYAMLをテキストとして生成する部分であり、SSH接続や実際の変更適用はAnsible本体とローカルの実行環境が担います。

似た構成でAnsible Automation Platformの自動化をMCPサーバー経由でClaudeに任せる方法はAnsible MCPサーバーでAutomation Platformの自動化をClaudeに任せるで扱っており、こちらはジョブテンプレートの起動や実行結果の取得をMCP経由で行う構成です。本記事で扱うのは、その手前にあるPlaybook自体をローカルでどう書かせ、検証するかという工程です。

前提条件 — 制御ノードとインベントリ対象を用意する

Ansibleは制御ノードにインストールします。管理対象ノードには、制御ノードの公開SSH鍵をauthorized_keysに登録しておく必要があります。接続確認時にAnsibleが返す実行結果にはdiscovered_interpreter_pythonという項目が含まれ、管理対象ノード側のPython実行環境を自動検出していることが分かります。

検証目的であれば、管理対象ノードは本番サーバーである必要はなく、ローカルのコンテナや仮想マシンでも構いません。Claude CodeにPlaybookを生成させる場合、対象がテスト用の環境であることを明示しておくと、後述する--check--limitの使い方についてもClaude Codeが安全側の提案をしやすくなります。

Claude Code自身がBashツールでansibleコマンドを直接実行することも技術的には可能ですが、実行にはSSH鍵へのアクセスや対象ホストへの到達性が必要です。多くの環境では、Claude CodeにYAMLの生成とレビューまでを任せ、実行と接続確認は自分のシェルで行う分担が安全です。

手順1: インベントリファイルを作成する

インベントリは、管理対象ノードを論理的にまとめてAnsibleに伝えるファイルです。INI形式とYAML形式のどちらでも書けますが、管理対象ノードが少ない場合はINI形式のほうが読みやすいとされています。

Claude Codeに「myhostsグループに3台のホストを登録するインベントリをINI形式で作って」と伝えると、次のようなinventory.iniになる想定です(公式ドキュメントのインベントリ例に沿った内容)。

myhostsグループに192.0.2.50、192.0.2.51、192.0.2.52を登録するインベントリをINI形式で作って
[myhosts]
192.0.2.50
192.0.2.51
192.0.2.52

管理対象ノードが増えてくると、ホストごとに名前をつけてYAML形式で管理する方が扱いやすくなります。Claude Codeに「ホスト名を付けてYAML形式に書き直して」と続けると、ansible_hostフィールドを使った形に書き直されることが期待できます。

myhosts:
  hosts:
    my_host_01:
      ansible_host: 192.0.2.50
    my_host_02:
      ansible_host: 192.0.2.51
    my_host_03:
      ansible_host: 192.0.2.52

インベントリのグループ名は大文字小文字を区別し、スペースやハイフン、数字始まりを避けるのが公式の推奨です(19th_floorではなくfloor_19のように書きます)。用途(db・web)、場所(datacenter・region)、段階(development・production)のいずれかの軸でグループを分けておくと、後述のPlaybookでhostsに指定するパターンも整理しやすくなります。

インベントリが書けたら、ansible-inventoryコマンドで内容を確認します。

ansible-inventory -i inventory.ini --list

さらにansibleコマンドのpingモジュールで、SSH接続と管理対象ノード側のPython実行環境が機能しているかを確認できます。

ansible myhosts -m ping -i inventory.ini

接続に成功すると、各ホストから"ping": "pong"という応答が返ります。制御ノードと管理対象ノードでSSHのユーザー名が異なる場合は、ansibleコマンドに-uオプションを付けて実行します。

手順2: Playbookを作成する

Playbookは、1つ以上の「play」を順番に並べたYAMLファイルです。各playは、対象ノードのパターン(hosts)と、実行するタスクの一覧(tasks)を最低限持ちます。各タスクはAnsibleのモジュールを1つ呼び出します。

Claude Codeに「myhostsグループにpingを打って、Hello worldを表示するPlaybookを書いて」と伝えると、次のような形のYAMLが返ってくる想定です(公式ドキュメントのPlaybook例と同じ内容)。

myhostsグループにpingを打って、Hello worldを表示するPlaybookを書いて
- name: My first play
  hosts: myhosts
  tasks:
    - name: Ping my hosts
      ansible.builtin.ping:
    - name: Print message
      ansible.builtin.debug:
        msg: Hello world

play・タスクのnameには、後から実行結果を読んで何をしているか分かる説明的な名前を付けておくと、ansible-playbookの実行ログとPlaybook自体の対応が取りやすくなります。モジュール名はansible.builtin.pingのように、コレクション名を含むFully Qualified Collection Name(FQCN)で書くのが、Ansible 2.10以降での公式推奨です。同名のモジュールが複数のコレクションに存在する場合があり、FQCNで書くことで意図したモジュールが確実に選ばれます。

Claude Codeに生成規約を守らせる

FQCNの指定漏れやstate: latestの多用は、指示のたびに書き添えるのではなく、プロジェクトのCLAUDE.mdにルールとして書いておくと、Claude Codeが生成するPlaybookに一貫して反映されます。例えば次のような記述をCLAUDE.mdに置きます。

## Ansible Playbookの生成規約
- モジュールは必ずFQCN(例: ansible.builtin.ping)で書く
- state: latestは明示的に指示されない限り使わず、state: presentを既定にする
- 本番インベントリ(inventory/production.ini)を直接編集しない。生成物はレビュー用のブランチに置く

これにより、都度の指示を省略しても、生成されるPlaybookの記法と安全策がプロジェクト全体で揺れなくなります。

実際の構成管理でよく使う例として、Webサーバーにパッケージをインストールし、設定ファイルを配置するPlaybookをClaude Codeに書かせる場合は、対象ホストグループとインストールしたいパッケージ、配置したい設定ファイルのパスを具体的に伝えます。

- name: Update web servers
  hosts: webservers
  remote_user: root
  tasks:
    - name: Ensure apache is at the latest version
      ansible.builtin.yum:
        name: httpd
        state: latest
    - name: Write the apache config file
      ansible.builtin.template:
        src: /srv/httpd.j2
        dest: /etc/httpd.conf

state: latestのように「常に最新版に更新する」条件を指定すると、実行するたびにパッケージの更新チェックが走ります。バージョンを固定したい場合や更新タイミングを制御したい場合は、state: presentのように「存在していればよい」条件に変更するかどうかを、次の検証手順で確認します。

書けたPlaybookはansible-playbookコマンドで実行します。

ansible-playbook -i inventory.ini playbook.yaml

手順3: --checkと--diffで事前確認し、2回実行で冪等性を確かめる

Ansibleのモジュールの多くは、管理対象ノードが目的の状態に既に達していれば、何もせずに終了する設計になっています。この性質を「冪等性(idempotency)」と呼び、Playbookを1回実行しても複数回実行しても結果が変わらないことを意味します。ただし公式ドキュメントも明記しているとおり、すべてのモジュールがこの性質を持つわけではなく、不確かな場合はサンドボックス環境で複数回実行して確認することが推奨されています。

Claude Codeが生成したPlaybookをいきなり本番の管理対象ノードに適用する前に、--checkオプションを付けて実行します。

ansible-playbook -i inventory.ini playbook.yaml --check

--checkモードでは、管理対象ノードに実際の変更を加えず、チェックモードに対応したモジュールが「変更が必要になる箇所」だけを報告します。チェックモードに対応していないモジュールは、何も報告せず何も実行しません。公式ドキュメントは、チェックモードが単なるシミュレーションであり、直前のタスクで取得した登録変数を条件にした処理では正しい出力が得られない場合があると注記しています。

--diffオプションを組み合わせると、変更前と変更後の差分を表示できます。templateモジュールのようにファイルを操作するモジュールで特に有効です。

ansible-playbook -i inventory.ini playbook.yaml --check --diff --limit webserver01

--diffは出力量が多くなるため、対象を--limitで1台に絞って確認するのが公式の推奨です。機密情報が差分に出る懸念がある場合は、この1台に絞る運用に加えて出力先の扱いにも注意します。

--checkを付けたときでも必ず実行したいタスクにはcheck_mode: falseを、通常実行でも変更を加えずシミュレーションだけにしたいタスクにはcheck_mode: trueを指定します。check_mode: trueは「常にスキップする」指定ではなく、「常にチェックモードで動かす(変更しない)」指定である点に注意してください。

tasks:
  - name: This task will always make changes to the system
    ansible.builtin.command: /something/to/run --even-in-check-mode
    check_mode: false
  - name: This task will never make changes to the system
    ansible.builtin.lineinfile:
      line: "important config"
      dest: /path/to/myconfig.conf
      state: present
    check_mode: true

チェックモード中かどうかを条件分岐に使いたい場合は、ansible_check_modeという真偽値の特殊変数をwhen条件に使います。

--check--diffはあくまで実行前のシミュレーションです。冪等性そのものを確かめるには、同じPlaybookを実際に2回連続で実行し、2回目の結果を見るのが確実です。例えばmyhostsグループにpingとdebugだけのPlaybookを実行すると、次のようなPLAY RECAPが返ります。

PLAY RECAP *************************************************************
192.0.2.50: ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.0.2.51: ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.0.2.52: ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

このping・debugタスクはそもそも管理対象ノードの状態を変更しないため、1回目からchanged=0です。パッケージのインストールや設定ファイルの配置のように実際に状態を変更するタスクを含むPlaybookでは、1回目の実行でそのタスクのchangedカウンタが増えます。同じPlaybookをもう一度実行し、2回目のPLAY RECAPで該当タスクがchanged=0になれば、そのタスクは冪等に動作していると確認できます。2回目以降もchangedが増え続ける場合は、state: latestのように毎回チェックが走る指定になっていないかを見直します。

構文エラーやタスクの一覧を実行前に確認したい場合は、--syntax-check--list-tasks--list-hostsといったオプションも使えます。加えて、ansible-lintを使うとAnsible特有の設計上の注意点も検出できます。例えばstate: latestを指定したタスクに対しては、次のような警告が出ます。

ansible-lint verify-apache.yml
[403] Package installs should not use latest
verify-apache.yml:8
Task/Handler: ensure apache is at the latest version

Claude Codeが生成したPlaybookに対しても、--check --diffansible-lintの両方を通してから、対象を絞った1台に限定実行し、問題なければ対象を広げるという順で進めると、想定外の変更を本番の管理対象ノード全体に適用するリスクを抑えられます。検証コマンドの使い分けは次の表のとおりです。

コマンド/オプション何を確認するか実際の変更
--syntax-check何を確認するかYAML構文とキーワードの誤りを確認する実際の変更なし
--list-tasks / --list-hosts何を確認するか実行対象のタスクとホストの一覧を確認する実際の変更なし
--check何を確認するか変更が必要になる箇所を報告する(対応モジュールのみ)実際の変更なし
--check --diff何を確認するか変更前後の差分を表示する実際の変更なし
ansible-lint何を確認するか設計上のアンチパターンを検出する実際の変更なし
オプションなし実行何を確認するか実際に管理対象ノードへ変更を適用する実際の変更あり

手順4: 変更をコミットしてレビューに出す

インベントリとPlaybookが検証を通過したら、Gitでバージョン管理します。Ansible公式も、繰り返し使うPlaybookはソースコード管理下に置き、設定の変更履歴として使うことを勧めています。

Claude CodeでPRを作成する一連の流れをgit addからgh pr createまで自動化する手順はClaude CodeでPRを作成する手順にまとめています。Playbookの変更もコードの変更と同じ流れでレビューに出し、マージ前に--check --diffの実行結果をPR本文に貼っておくと、レビュアーが実際の変更内容を確認しやすくなります。

よくあるつまずき

FQCNを省略した指示で短縮名になる

Claude Codeに具体的なコレクション名を指定せず「pingして」のように指示すると、ansible.builtin.pingのようなFQCNではなく短縮名で書かれることがあります。複数のコレクションに同名モジュールが存在する環境では、意図しないモジュールが呼ばれる可能性があるため、生成後にFQCN表記になっているかを確認します。

チェックモードだけで冪等性を保証したと考える

--checkは変更が必要な箇所を報告するだけのシミュレーションで、モジュール自体が冪等でなければ複数回実行した結果が変わる可能性は残ります。前段で見た「同じPlaybookを2回実行してchanged=0になるか」を確かめる方法と組み合わせて判断します。

出力量が多いまま--diffを対象を絞らずに実行してしまうケースもよくあります。設定ファイルの中身などの詳細情報が大量に出るため、まず--limitで1台に絞って差分を確認し、問題がなければ範囲を広げます。

登録変数条件のタスクはチェックモードで検証できない点も見落としがちです。直前のタスクの結果をregisterで受け取り、その値を条件にした後続タスクは、チェックモードでは正しい出力が得られないことがあります。こうしたタスクは、チェックモードの結果だけで安全性を判断せず、テスト環境での実行結果も併せて確認します。

Claude CodeにSSH鍵や接続情報を渡してしまう

PlaybookのYAML自体に接続情報や機密情報を平文で書かせず、Ansible Vaultなどの仕組みで暗号化して分離する構成を、Claude Codeへの指示にも含めておきます。

まとめ

Claude CodeでAnsibleのPlaybookを書く場合、まずインベントリをINIまたはYAML形式で作り、ansible-inventorypingモジュールで接続を確認したうえでPlaybookを生成させる、という順で進めます。生成したPlaybookは--check --diffansible-lintを通し、--limitで対象を絞った実行結果を確認してから、対象を広げるのが安全です。冪等性はAnsibleのモジュール側の性質であり、チェックモードの結果だけで保証されるわけではない点を踏まえ、不確かなタスクはテスト環境での複数回実行で確かめます。

この記事を共有:XはてブLinkedIn