シェルスクリプトなら
echo や set -x で処理の流れをすぐに追えますが、Ansibleは実際の処理がモジュールの中に隠れているため、同じ感覚でデバッグしようとすると詰まります。この記事では、Ansibleのデバッグを体系化する3つの道具——詳細ログフラグ(-v~-vvvv)・debugモジュール・assertモジュール——と、実行範囲を絞る--step・--start-at-taskの使い方を解説します。「どのツールをどの場面で使うか」を整理するだけで、デバッグにかかる時間は大幅に短縮できます。
この記事のポイント
・-vフラグで詳細ログを出し、タスク結果とモジュール引数を確認できる
・debugモジュールで変数の実際の値や条件式の評価結果を可視化できる
・assertモジュールで「期待通りの状態か」を宣言的に検証し失敗させられる
・--start-at-taskで問題箇所から実行を再開すれば検証サイクルが速くなる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜAnsibleのデバッグは難しいのか
シェルスクリプトのデバッグは直感的です。コマンドを1行ずつ実行してみれば、どこで失敗したかすぐに分かります。しかしAnsibleには独自の抽象層があり、慣れるまでは「何が起きているか見えない」と感じることが多いです。主な原因は3つあります。
・モジュール内部が隠れている:
dnf モジュールがどんなコマンドを実際に発行しているか、デフォルトでは表示されない・変数展開が遅延評価される: Jinja2テンプレートや変数が実際にどの値に展開されたか、実行時でないと分からない
・whenの評価結果が見えない: タスクがスキップされた理由が、変数の未定義なのか、条件が False なのか、一見して区別できない
この「見えない問題」を解決するのが、-vフラグ・debugモジュール・assertモジュールの組み合わせです。それぞれの役割を順に見ていきましょう。
詳細ログで原因を読む(-vフラグの使い方)
ansible-playbookコマンドに-v を付けると、実行ログの詳細度を段階的に上げられます。1. 詳細度の4段階
# -v : タスク結果(changed/ok/failed)と戻り値の一部を表示 # -vv : タスクのパラメータ(モジュール引数)も表示 # -vvv: 接続詳細(SSH接続先・ユーザー)・モジュールファイルのパスも表示 # -vvvv: SSHデバッグ出力まで表示(接続問題の切り分けに使う) ansible-playbook site.yml -i inventory/hosts -v ansible-playbook site.yml -i inventory/hosts -vvv
-vv を試すのが現場のお勧めです。-vvvv 以上はSSH関連まで出てきて情報量が多くなりすぎるため、接続問題が疑われる場合だけ使います。2. -vvの出力例と読み方
-vv で実行すると、以下のような出力が得られます。TASK [install httpd] ******************************************* task path: /home/ansible/site.yml:12 ok: [web01.example.com] => { "ansible_facts": {}, "changed": false, "msg": "", "rc": 0, "results": [ "httpd-2.4.57-11.el9.x86_64 providing httpd is already installed" ] }
・changed: false: パッケージは既にインストール済みで変更なし(べき等性が働いている)
・results: 実際に実行されたコマンドの結果(どのバージョンが入っているか)
・task path: このタスクがPlaybookの何行目に定義されているか
failed の場合は同様に msg や stderr の内容が表示されるため、エラーメッセージをそのままコピーして検索できるようになります。3. skippedタスクの原因を読む
when 条件でタスクがスキップされた場合、-vv では以下のように表示されます。TASK [rhel only setup] ***************************************** skipping: [web01.example.com] => { "changed": false, "skip_reason": "Conditional result was False" }
skip_reason: Conditional result was False と表示されます。「条件が False だったからスキップした」ことは分かりますが、条件式がどんな値に展開されたかは分かりません。ここで次のdebugモジュールが活躍します。debugモジュールで変数・条件を可視化する
debug モジュールは、PlaybookのタスクとしてAnsibleが保持している変数の値や条件式の評価結果を出力するためのモジュールです。「何が入っているか分からない変数」を可視化するための専用ツールだと思えば分かりやすいです。1. 変数の値を確認する
--- - name: 変数デバッグの例 hosts: webservers tasks: - name: ansible_os_familyの値を確認 debug: var: ansible_os_family - name: 複数変数をまとめて確認 debug: msg: | OS Family: {{ ansible_os_family }} Distribution: {{ ansible_distribution }} Version: {{ ansible_distribution_version }}
TASK [ansible_os_familyの値を確認] *** ok: [web01.example.com] => { "ansible_os_family": "RedHat" } TASK [複数変数をまとめて確認] *** ok: [web01.example.com] => { "msg": "OS Family: RedHat\nDistribution: Rocky\nVersion: 9.4\n" }
var: は変数名を直接指定する書き方({{ }}が不要)、msg: は文字列テンプレートを使う書き方です。複数の変数を組み合わせて確認したい場合は msg: の方が便利です。2. when条件の評価結果を確認する
when がなぜ False になるのかを確認するには、条件式をそのままdebugで出力するのが最速です。# 問題のあるwhen条件があるタスクの直前に追加する - name: when条件の評価確認 debug: msg: "os_family={{ ansible_os_family }}, 条件={{ ansible_os_family == 'RedHat' }}" - name: rhel only setup dnf: name: httpd state: present when: ansible_os_family == 'RedHat'
TASK [when条件の評価確認] *** ok: [web01.example.com] => { "msg": "os_family=Debian, 条件=False" }
ansible_os_family が Debian だったため条件が False になってスキップされていたことが一目で分かります。想定外の変数の値や、型の不一致(文字列 "9" と整数 9 の比較など)がよくある原因です。3. registerした変数の中身を確認する
register でタスクの戻り値を変数に保存した場合、中身の構造を確認するにはdebugが不可欠です。- name: パッケージ情報を取得 command: rpm -q httpd register: rpm_result ignore_errors: true # 戻り値の構造全体を確認する - name: rpm_resultの中身を確認 debug: var: rpm_result # 特定のフィールドだけ確認する - name: 終了コードと標準出力のみ確認 debug: msg: "rc={{ rpm_result.rc }}, stdout={{ rpm_result.stdout }}"
register の戻り値は辞書型で、rc(終了コード)・stdout(標準出力)・stderr(標準エラー)などのキーを持ちます。まず var: rpm_result で全体を出力して構造を把握してから、必要なフィールドに絞り込むのが効率的なデバッグの進め方です。Ansible実機ハンズオンはこちら
デバッグを含めたAnsibleの実践的な使い方を、RHEL環境を使って手を動かしながら学べます。
「読んで理解した」から「現場で使える」へのステップを最短で踏みたい方にお勧めです。
>> Ansibleハンズオン講座の詳細を見る
assertモジュールで期待値を宣言的に検証する
assert モジュールは、条件が満たされない場合にタスクを意図的に失敗させるモジュールです。debugが「値を確認する」受動的なツールだとすれば、assertは「この条件が成立しなければPlaybookを止める」という能動的な検証ツールです。1. assertの基本構文
- name: httpdがインストール済みであることを確認 assert: that: - rpm_result.rc == 0 fail_msg: "httpdがインストールされていません(rc={{ rpm_result.rc }})" success_msg: "httpdインストールを確認しました"
that: に条件式のリストを書きます。全ての条件が True でないと失敗し、Playbook全体が停止します。fail_msg にはどの条件が満たされなかったかを説明するメッセージを書いておくと、後から見た時に原因が追いやすくなります。2. 前提条件チェックに使う(early exit パターン)
assertの最も典型的な用途は、Playbookを実行する前に前提条件を確認して、問題があれば早期終了させることです。長いPlaybookが途中まで走って中途半端な状態になる事故を防ぎます。--- - name: 前提条件チェック hosts: webservers gather_facts: yes tasks: - name: OSのバージョン確認 assert: that: - ansible_os_family == 'RedHat' - ansible_distribution_major_version | int >= 9 fail_msg: > このPlaybookはRHEL/Rocky Linux 9以降が必要です。 現在: {{ ansible_distribution }} {{ ansible_distribution_version }} - name: 空きディスク容量確認(/に10GB以上必要) assert: that: - item.size_available > 10737418240 fail_msg: "{{ item.mount }} の空き容量が不足しています" loop: "{{ ansible_mounts | selectattr('mount', 'equalto', '/') | list }}"
3. 設定変更後の状態確認(smoke testパターン)
設定変更後に「本当に変更が効いているか」を確認するアサーションも実務では有効です。CI/CDパイプラインにAnsibleを組み込む場合は特に効果を発揮します。- name: httpdのサービス状態を取得 service_facts: - name: httpdが起動・有効化されていることを確認 assert: that: - "'httpd.service' in ansible_facts.services" - ansible_facts.services['httpd.service'].state == 'running' - ansible_facts.services['httpd.service'].status == 'enabled' fail_msg: > httpdが正常に起動していません。 状態: {{ ansible_facts.services['httpd.service'].state | default('unknown') }}
service_facts でサービス状態を取得してから assert で検証するパターンは、「構築後の状態確認」の定石です。Playbookがchangedで終わっても、本当にサービスが正常に動いているかをコードとして表現できます。--stepと--start-at-taskで実行範囲を絞る
変数の値や条件を確認できたら、次は「問題のあるタスクだけを素早く再実行する」方法が必要です。長いPlaybookを最初から毎回実行していては、検証サイクルが遅くなりすぎます。1. --start-at-taskで途中から再開する
# タスク名"httpdのサービス状態を取得"から実行を再開する ansible-playbook site.yml -i inventory/hosts --start-at-task="httpdのサービス状態を取得"
name: フィールドの文字列と完全一致で指定します。-vv で出力されていたタスク名をそのままコピーすれば確実です。注意点が一つあります。前のタスクで
register した変数や gather_facts の結果は、--start-at-task で途中から開始すると取得されません。依存関係があるタスク群をスキップした場合に変数未定義エラーが出ることがあります。その場合は1段前のタスクから再開するか、必要な変数をgroup_vars等でデフォルト値として定義しておくと解決します。2. --stepで1タスクずつ確認実行する
ansible-playbook site.yml -i inventory/hosts --step
--step を付けると、タスクの実行前に毎回「実行するか(y/n/c)」を問われます。y で実行、n でスキップ、c でそれ以降を確認なしで続行します。新しいPlaybookを初めて本番サーバーへ適用する前の「最終確認」として使うのが典型的な用途です。
--check フラグ(ドライラン)と組み合わせると、変更内容を確認しながら安全に通せます。よくあるエラーと切り分けパターン
1. 変数が未定義でエラーになる(AnsibleUndefinedVariable)
エラーメッセージ:AnsibleUndefinedVariable: 'my_variable' is undefined切り分け手順:
・
-vv でどのタスクで発生したか確認する・問題のタスクの直前に
debug: var: my_variable を追加して、変数が定義されているか確認する・変数が未定義なら group_vars・host_vars・vars:・register のどこで定義されるべきかを見直す
2. タスクがスキップされて設定が反映されない
when の条件が意図と違う場合によく起きます。切り分け手順:
・
-vv で skip_reason: Conditional result was False を確認する・
when の直前に debug: msg: "値={{ 変数 }}, 条件={{ 条件式 }}" を追加して展開結果を確認する・型の問題(文字列
"0" と整数 0 が == で一致しない等)は | int や | string でキャストして解決する3. commandモジュールが毎回changedになる(べき等性の欠如)
command や shell モジュールはAnsibleが変更を検出できないため、常に changed になります。切り分け手順:
・
-vv で changed: true になっているタスクのモジュール名を確認する・
changed_when や creates オプションで「変更なし」を明示的に定義する・可能なら
command/shell の代わりにべき等性を持つ専用モジュール(dnf・user・file 等)に差し替える4. SSH接続エラーで実行できない(UNREACHABLE)
エラーメッセージ:UNREACHABLE! Connection refused / Permission denied切り分け手順:
・
-vvvv でSSH接続先のホスト・ユーザー・鍵ファイルを確認する・
ansible -m ping 対象ホスト -i inventory/hosts -vvv でping単体をデバッグする・インベントリ変数(
ansible_user・ansible_ssh_private_key_file)の設定ミスが最多原因Ansibleデバッグのまとめ
Ansibleのデバッグツールを場面別にまとめます。| 場面 | 使うツール |
|---|---|
| タスクの実行結果・モジュール引数を確認したい | ansible-playbook site.yml -vv |
| 変数の実際の値を確認したい | debug: var: 変数名 |
| when条件がなぜFalseになるか確認したい | debug: msg: "値={{ 変数 }}, 条件={{ 条件式 }}" |
| registerした戻り値の構造を確認したい | debug: var: register変数名 |
| 前提条件が満たされない場合に早期終了させたい | assert: that: [条件式] |
| 問題箇所から実行を再開したい | ansible-playbook site.yml --start-at-task="タスク名" |
| 1タスクずつ確認しながら実行したい | ansible-playbook site.yml --step |
| SSH接続問題を詳細に調べたい | ansible-playbook site.yml -vvvv |
debug と assert を習慣的に使い始めると、「動いているけど本当に正しい状態なのか分からない」という不安がなくなります。Playbookのコードに品質検証の視点を持ち込む第一歩として、ぜひ取り入れてみてください。Ansibleをより実践的に学びたい方は、LinuxMaster.JPのAnsible専門ページもあわせてご覧ください。
Ansible実践ハンズオンの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:Ansibleのloopとregistered変数設計入門|with_items廃止後の繰り返し処理と結果制御パターン
- この記事の属するカテゴリ:Ansibleへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます