Ansibleのデバッグ設計入門|-vvvフラグ・debugモジュール・assertで実行時エラーを体系的に切り分ける方法

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Ansible > Ansibleのデバッグ設計入門|-vvvフラグ・debugモジュール・assertで実行時エラーを体系的に切り分ける方法
「Playbookを実行したのにサーバーの設定が変わっていない」「エラーは出ないのに期待通りに動かない」——Ansibleを使い始めた頃、こういった壁に必ずぶつかります。

シェルスクリプトなら echoset -x で処理の流れをすぐに追えますが、Ansibleは実際の処理がモジュールの中に隠れているため、同じ感覚でデバッグしようとすると詰まります。

この記事では、Ansibleのデバッグを体系化する3つの道具——詳細ログフラグ(-v~-vvvv)・debugモジュール・assertモジュール——と、実行範囲を絞る--step・--start-at-taskの使い方を解説します。「どのツールをどの場面で使うか」を整理するだけで、デバッグにかかる時間は大幅に短縮できます。

この記事のポイント

・-vフラグで詳細ログを出し、タスク結果とモジュール引数を確認できる
・debugモジュールで変数の実際の値や条件式の評価結果を可視化できる
・assertモジュールで「期待通りの状態か」を宣言的に検証し失敗させられる
・--start-at-taskで問題箇所から実行を再開すれば検証サイクルが速くなる


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

なぜ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" ] }

この出力から3つのことが分かります。

changed: false: パッケージは既にインストール済みで変更なし(べき等性が働いている)
results: 実際に実行されたコマンドの結果(どのバージョンが入っているか)
task path: このタスクがPlaybookの何行目に定義されているか

failed の場合は同様に msgstderr の内容が表示されるため、エラーメッセージをそのままコピーして検索できるようになります。

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_familyDebian だったため条件が 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 }}"

前提条件チェックをPlaybookの最初のPlay(またはpre_tasks)として配置しておくと、環境が整っていない状態で誤って構築処理が走ることを防げます。

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 の条件が意図と違う場合によく起きます。

切り分け手順:
-vvskip_reason: Conditional result was False を確認する
when の直前に debug: msg: "値={{ 変数 }}, 条件={{ 条件式 }}" を追加して展開結果を確認する
・型の問題(文字列 "0" と整数 0== で一致しない等)は | int| string でキャストして解決する

3. commandモジュールが毎回changedになる(べき等性の欠如)

commandshell モジュールはAnsibleが変更を検出できないため、常に changed になります。

切り分け手順:
-vvchanged: true になっているタスクのモジュール名を確認する
changed_whencreates オプションで「変更なし」を明示的に定義する
・可能なら command/shell の代わりにべき等性を持つ専用モジュール(dnfuserfile 等)に差し替える

4. SSH接続エラーで実行できない(UNREACHABLE)

エラーメッセージ: UNREACHABLE! Connection refused / Permission denied

切り分け手順:
-vvvv でSSH接続先のホスト・ユーザー・鍵ファイルを確認する
ansible -m ping 対象ホスト -i inventory/hosts -vvv でping単体をデバッグする
・インベントリ変数(ansible_useransible_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
デバッグの基本思想は「見えるようにする → 仮説を立てる → 確認する」のサイクルを最速で回すことです。Ansibleのデバッグツールはその各ステップに対応して設計されています。

debugassert を習慣的に使い始めると、「動いているけど本当に正しい状態なのか分からない」という不安がなくなります。Playbookのコードに品質検証の視点を持ち込む第一歩として、ぜひ取り入れてみてください。

Ansibleをより実践的に学びたい方は、LinuxMaster.JPのAnsible専門ページもあわせてご覧ください。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Ansible実践ハンズオンの詳細を見る >>

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

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

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

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

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

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

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

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

この記事を書いた人

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

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

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