Ansibleのエラー処理を甘く見ていませんか——現場で信頼されるコードの書き方

HOMEリナックスマスター.JP 公式ブログLinux学習ガイド > Ansibleのエラー処理を甘く見ていませんか——現場で信頼されるコードの書き方

この記事の監修:宮崎智広(Linux教育歴15年以上・受講者3,100名超)
「Ansibleって、エラーが出ても無視して動かせますよね」

セミナーで受講者の方からこんな発言を聞くことがあります。決して間違いではありません。
`ignore_errors: yes` という設定があり、確かにエラーが出ても処理を続けさせることができます。
でも、その言葉を聞くたびに私が感じるのは「あ、この人はまだエラーを設計に組み込んでいないな」ということです。

Ansibleを触り始めて数ヶ月経つと、「とにかく動かす」段階から抜け出せる人と、そこで止まる人に分かれていきます。
その分岐点の一つが、エラー処理への向き合い方です。

この記事では、20年以上Linuxサーバーを運用してきた経験から、Ansibleのエラー処理がなぜLinuxシェルの仕組みと深く結びついているのかを整理します。
そして「エラーを無視して動かすコード」と「エラーを設計に組み込んだコード」の差が、現場での評価にどう出てくるかを、具体的にお伝えします。

この記事のポイント

・AnsibleのエラーHandlingはLinuxシェルの終了コードを土台に設計されている
・`ignore_errors` は「便利な逃げ道」ではなく「意図的なトレードオフ」
・`failed_when` や `block/rescue/always` を使うとエラーが「設計の一部」になる
・現場で信頼されるエンジニアは、エラーが何を意味するかを語れる


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

AnsibleはLinuxシェルの延長線上にある——その感覚が掴めると景色が変わる

Ansibleを最初に触ったとき、「シェルスクリプトとは違う、宣言的な構成管理ツール」というイメージを持つ方が多いと思います。
それは正しい理解です。しかし「シェルとは別物」と切り離してしまうと、Ansibleの挙動を直感的に理解しにくくなります。

Ansibleの実体は、LinuxサーバーにSSHでログインし、Python(または場合によってはシェルスクリプト)のコードを実行し、その結果を受け取るという仕組みです。
裏側で動いているのは、まぎれもなくLinuxのプロセス管理・ファイル操作・終了コードの仕組みです。

Linuxの「終了コード」がAnsibleエラー処理の基盤

Linuxシェルには、すべてのコマンドが終了コード(exit code)を返すという原則があります。

・`0`:成功
・`0以外`:何らかの異常

この原則は、シェルスクリプトを書いたことがある方なら感覚で知っているはずです。
# 成功時は何も起きない
ls /etc/passwd && echo "ファイルが存在します"

# 失敗時は後続処理が止まる
ls /存在しないパス && echo "これは出力されない"
Ansibleも同じ原理で動いています。タスクがリモートサーバーで実行されると、そのプロセスの終了コードを受け取り、`0`なら成功(OK/CHANGED)、`0以外`なら失敗(FAILED)と判定します。

この「終了コードを返す」という行為は、LinuxがUNIX設計を受け継いでいる部分の一つです。
プロセスが終了コードを返すことで、上位のプロセスやシェルが「次に何をするか」を判断できます。Ansibleはこのメカニズムを、構成管理のオーケストレーションに使っているわけです。

シェルスクリプトとAnsibleの「止まり方」の違い

シェルスクリプトでは、エラー処理を自分で書く必要があります。
`set -e` を使うと、コマンドが失敗した時点でスクリプト全体を終了させることができます。
#!/bin/bash
set -e  # エラー発生時に即座に終了

echo "パッケージのインストール開始"
apt-get install -y nginx
echo "インストール完了"  # インストールが失敗したら、ここには到達しない
Ansibleはデフォルトで似た動作をします。プレイブック内のタスクが失敗すると、**そのホストに対する後続タスクはすべて止まります**。

これはAnsibleの意図的な設計です。失敗した状態で処理を続けると、何が起きるか予測できなくなるからです。
比較項目 シェルスクリプト(set -e) Ansible(デフォルト)
エラー検知 終了コード0以外で即終了 タスクFAILEDでホストの後続タスクを停止
複数ホスト 単一プロセス内のみ 失敗ホストだけ停止、他ホストは継続可
エラー無視 コマンド後に `|| true` を付ける `ignore_errors: yes` を使う
リカバリー処理 trap でシグナル捕捉 block/rescue/always で構造化

この対比を見ると、Ansibleのエラー処理がシェルの延長線上にあることがよく分かります。

Ansibleが「便利」に見えるのは、このエラー処理を**複数ホストへのオーケストレーション**という文脈で構造化しているからです。シェルスクリプトを個別に管理する世界を経験していると、Ansibleの設計意図が体に入ってきます。

Ansibleのエラー処理を甘く見ていませんか——現場で信頼されるコードの書き方 - 解説1

エラーを「握りつぶす」コードを書いていませんか

Ansibleを学び始めた方が最初に覚えるエラー処理が、`ignore_errors: yes` です。
- name: 古いパッケージを削除(失敗しても構わない)
  ansible.builtin.apt:
    name: old-package
    state: absent
  ignore_errors: yes
この設定自体は、正当なユースケースがあります。
たとえば「存在するかどうかわからないパッケージの削除を試みる」「先行タスクが失敗してもクリーンアップだけは走らせたい」といった場面です。

しかし、`ignore_errors: yes` が増殖したプレイブックは、現場で深刻な問題を引き起こします。

「動いているように見える」が最も危険な状態

プレイブックを実行して、ターミナルに `PLAY RECAP` が表示されたとします。
PLAY RECAP *****
web01  : ok=8  changed=2  unreachable=0  failed=0  rescued=0  ignored=3
`failed=0` を見て「成功した」と思った経験はないでしょうか。
しかし `ignored=3` という数字を見てください。3つのタスクでエラーが発生していますが、`ignore_errors: yes` によって隠れています。

このコードで何が起きているか、実際に確認しないと分かりません。
nginx の設定ファイルの置き換えが失敗していた、でも `ignore_errors: yes` のせいで後続のサービス再起動まで動いてしまった、結果として古い設定のまま nginx が動いている——こういった事態が、ひっそりと起きていることがあります。

私がセミナーで「エラーを握りつぶしていませんか」と聞くのは、このパターンに気づいていない方が多いからです。

なぜ「とりあえず ignore_errors」が習慣になるのか

技術的な問題だけではなく、習慣的な問題もあります。

Ansibleを始めたばかりの頃、エラーが出るたびに止まるのが「ストレス」に感じられることがあります。
「この環境では古いパッケージが入っていないから失敗するけど、それは問題ないはず」という状況で、調べることよりも `ignore_errors: yes` をつけることで前に進もうとするわけです。

この判断自体が間違いとは言えません。しかし「とりあえず ignore_errors をつけると進む」という体験が積み重なると、エラーへの感度が下がっていきます。

現場で「このプレイブックを読んでください」と言われたとき、`ignore_errors: yes` が散在しているコードは、意図が読み取れません。
「このエラーは無視して良いと判断したのか」「気づかなかっただけなのか」が区別できないコードは、メンテナンスコストが跳ね上がります。

ignore_errors を使う前の3つの確認

`ignore_errors: yes` を書く前に、次の3点を確認する習慣をつけることをお勧めします。

1. **このエラーは本当に無視して良いか**:後続タスクの前提が崩れていないか確認する
2. **なぜ失敗するのか分かっているか**:理由が分からないエラーを無視するのは最も危険
3. **コメントに意図を書けるか**:「なぜ無視するのか」を一言書けないなら、まだ理解が浅い

`ignore_errors: yes` は「便利な逃げ道」ではなく「意図的なトレードオフ」です。
そのトレードオフを説明できる人が書いたコードと、そうでないコードは、現場での受け取られ方が大きく異なります。

Error Handlingを設計に組み込む人が、現場で長く信頼される理由

`ignore_errors` だけでAnsibleのエラー処理を語るのは不十分です。
Ansibleには、エラーを「設計の一部」として組み込むための仕組みが複数用意されています。

failed_when:「何をもって失敗とするか」を自分で定義する

Ansibleのデフォルトは「コマンドの終了コードが0以外ならFAILED」です。
しかし現実の運用では、終了コードだけで成否が判断できないケースがあります。
- name: パターンをgrepで検索(結果がない場合も正常とみなす)
  ansible.builtin.command: grep "ERROR" /var/log/app.log
  register: grep_result
  failed_when: grep_result.rc != 0 and grep_result.rc != 1
  # rc=0 は「ERROR発見」、rc=1 は「ERRORなし(正常)」、rc=2以上は「grepコマンド自体のエラー」
`grep` コマンドは検索対象が見つかれば終了コード`0`、見つからなければ`1`を返します。
単純に「終了コード0以外=失敗」とすると、ログに「ERROR」が存在しない正常なサーバーでもタスクが失敗になってしまいます。

`failed_when` を使うことで「このコマンドにとっての失敗とは何か」を明示的に定義できます。
これがシェルスクリプトの終了コード設計の延長線上にある、Ansible流の「成功の定義」です。

changed_when:冪等性を明示的に管理する

Ansibleの重要な概念の一つが冪等性(idempotency)です。
「何度実行しても、同じ結果になる」——これがAnsibleプレイブックの理想です。

しかし `command` モジュールや `shell` モジュールを使うと、Ansibleは実行結果が変化したかどうかを自動で判断できません。毎回 `CHANGED` が報告されてしまいます。
- name: サービスの状態を確認
  ansible.builtin.command: systemctl is-active nginx
  register: nginx_status
  changed_when: false  # このタスクは状態確認のみ、変更は起こさない
`changed_when: false` を書くことで「このタスクはサーバーの状態を変えない」という意図が明示されます。
差分レポートが正確になり、「本当に変更が起きたタスク」と「確認だけのタスク」が区別できるようになります。

block/rescue/always:try-catch-finally の発想をAnsibleで実現する

プログラミング経験がある方なら、`try-catch-finally` という構造に馴染みがあるでしょう。
Ansibleでは `block/rescue/always` がこれに相当します。
- name: デプロイ処理(エラー時のロールバック付き)
  block:
    - name: アプリのバイナリを配置
      ansible.builtin.copy:
        src: /tmp/app-new
        dest: /opt/app/bin/app
        mode: '0755'

    - name: サービスを再起動
      ansible.builtin.service:
        name: myapp
        state: restarted

  rescue:
    - name: デプロイ失敗——旧バージョンに戻す
      ansible.builtin.copy:
        src: /opt/app/bin/app.bak
        dest: /opt/app/bin/app
        mode: '0755'

    - name: ロールバック後にサービス再起動
      ansible.builtin.service:
        name: myapp
        state: restarted

    - name: 失敗をfailモジュールで明示的に伝播
      ansible.builtin.fail:
        msg: "デプロイに失敗しました。旧バージョンにロールバックしました。"

  always:
    - name: デプロイ結果をログに記録(成功・失敗を問わず)
      ansible.builtin.shell: echo "$(date) deploy attempt" >> /var/log/deploy.log
このコードが何をしているかを説明できますか。

・`block`:通常のデプロイ処理
・`rescue`:blockのいずれかが失敗したときだけ実行(ロールバック処理)
・`always`:成功・失敗に関わらず必ず実行(ログ記録)

エラーを「何が起きたか」「どう対処するか」「最後に必ず何をするか」に分けて設計する——これがAnsibleのError Handlingを「設計に組み込む」という意味です。

エラー処理の設計チェックリスト

プレイブックのレビューをするときに私が確認している項目を共有します。

・[ ] `ignore_errors: yes` には理由をコメントで記載している
・[ ] `command/shell` モジュールに `failed_when` または `changed_when` が適切に設定されている
・[ ] 複数タスクが連携する箇所に `block/rescue/always` でエラーフローが設計されている
・[ ] `rescue` ブロックの最後に `fail` モジュールでエラーを明示的に伝播させている(握りつぶしていない)
・[ ] `PLAY RECAP` の `ignored` の数が意図した通りか確認している

この5項目を意識するだけで、プレイブックの品質が大きく変わります。

Ansibleのエラー処理を甘く見ていませんか——現場で信頼されるコードの書き方 - 解説2

構成管理ツールの習得で、Linuxの理解はもう一段深まる

Ansibleを使い始めると、Linux自体の理解が深まるという効果があります。
これは偶然ではありません。

Ansibleのタスクが「なぜ失敗するのか」を調べようとすると、必ずLinuxの内部に入ることになります。

・パーミッションエラー → Linuxのファイル権限・SELinuxポリシーを調べることになる
・サービス起動失敗 → systemdのユニットファイル・journalctlのログを読むことになる
・コマンドが見つからない → PATHの設定・パッケージのインストール状態を確認することになる

この「エラーに向き合う」体験が、Linuxの理解を層として積み上げていきます。

Ansibleエラーから学べるLinuxの知識領域

実際にAnsiblにのエラーを調べた経験が、どのLinux領域の理解につながるかを整理します。
よくあるAnsibleエラー 調査に必要なLinux知識 身につく領域
Permission denied ls -la / chmod / chown / sudo設定 ファイル権限・特権管理
service failed to start journalctl -xe / systemctl status systemd・ログ管理
command not found which / echo $PATH / locate 環境変数・パス管理
firewall blocking connection firewall-cmd / iptables -L / ss -tlnp ネットワーク・ファイアウォール
no space left on device df -h / du -sh / lsblk ストレージ管理

このように、Ansibleのエラー調査は「使えるLinuxコマンドの実戦的な練習」でもあります。
Ansibleを動かし、エラーが出て、LinuxにSSHで入って原因を調べて、修正してプレイブックに落とす——このサイクルを回すことが、Linux技術者としての実力を積み上げる最短コースの一つです。

「動かす」から「語れる」へ——エラーが理解の扉

セミナーで気づくのですが、Linuxの技術力が急に伸びる方には共通点があります。
「エラーを面白がるようになった」ということです。

エラーが出たとき、多くの方は「また止まった」「なんで動かないんだ」とストレスを感じます。
しかし、技術が深まる方は「このエラーはどこから来ているんだろう」「Linuxのどの仕組みが関わっているんだろう」という方向に思考が向かいます。

Ansibleを「ただのツール」として使う人と、「Linuxを深く理解するための窓」として使う人では、1年後の理解の深さが大きく変わります。

学習として取り組む際の実践フロー

Ansibleのエラー処理を体系的に学ぶ流れを提案します。

1. **まず意図的に失敗させる**
存在しないパスにファイルを置くタスクを書いて実行する。どんなエラーメッセージが出るかを観察する。

2. **`-v` オプションで詳細を見る**
`ansible-playbook site.yml -v`(または `-vv`, `-vvv`)で詳細ログを確認する。Linuxレベルで何が起きているかが見えてくる。

3. **ignore_errors → failed_when → block/rescue の順に理解する**
エラーを「丸ごと無視する」→「条件付きで無視する」→「構造的に処理する」の順序で、段階的に深める。

4. **エラーを見たら必ずLinuxで確認する**
Ansibleのエラーで止まったら、まず対象サーバーにSSHで入ってLinuxコマンドで現状を確認する。
「AnsibleのエラーとLinuxの状態をつなげる」経験を積む。

Ansibleのエラー処理を甘く見ていませんか——現場で信頼されるコードの書き方 - まとめ

まとめ:エラー処理の向き合い方が、エンジニアの姿勢を映す

Ansibleのエラー処理を通じて、今回お伝えしたかったことを整理します。

・AnsibleはLinuxシェルの終了コードを土台にしたツールです。Linuxを知ることがAnsibleの理解につながります
・`ignore_errors: yes` は「意図的に使うもの」です。理由を説明できない状態で書かれたコードは、後から読む人を困らせます
・`failed_when`・`changed_when`・`block/rescue/always` を使うことで、エラー処理を「設計の一部」にできます
・Ansibleのエラーに向き合うことが、Linuxの深い理解につながります

私がセミナーで見てきた「現場で長く信頼されるエンジニア」の特徴は、道具の使い方だけでなく「なぜその設計なのか」を語れることです。
エラー処理は、その「語れる」部分の一つです。

Ansibleを学ぶ中でエラーに出会ったとき、「また止まった」ではなく「これは何を教えてくれているんだろう」と受け取れるようになると、技術の身につき方が変わっていきます。

よくある質問(FAQ)

Q. ignore_errors と failed_when はどう使い分けますか?
A. 「エラーの定義を変えたい(条件を変えたい)」なら failed_when、「このタスクのエラーは何があっても後続に影響させたくない」なら ignore_errors です。できるだけ failed_when で意図を明示する方が、コードの可読性が上がります。

Q. block/rescue を使わないといけない場面はありますか?
A. 複数タスクが連携していて、失敗時にロールバック処理が必要な場面では block/rescue が不可欠です。シングルタスクのエラーは failed_when か ignore_errors で対応できますが、「デプロイ→確認→切り替え」のような一連の処理では block/rescue の構造が読みやすさと安全性を高めます。

Q. ansible.cfg で any_errors_fatal を設定するのは有効ですか?
A. `any_errors_fatal: true` を設定すると、1台のホストでエラーが出た時点でプレイ全体を停止します。本番環境への一括デプロイのような「1台でも失敗したら全体を止めるべき場面」では有効です。ただし開発・テスト環境では過剰になることもあるため、用途に応じて使い分けてください。

Q. Ansibleのエラーログはどこで確認できますか?
A. 実行時に `-v` オプションを付けると詳細ログが確認できます。また `ansible.cfg` の `log_path` にパスを指定するとファイルにログが保存されます。対象サーバー側のエラーは、SSH経由でそのサーバーの `/var/log/syslog` や `journalctl` を確認するのが確実です。


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

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

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

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

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

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

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

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

宮崎 智広

この記事を書いた人

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

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

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


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