Ansibleのpre_tasks・post_tasksで実行順序を設計する方法|Playbookの前処理・後処理とhandlerの実行タイミングを理解する設計入門

運営:リナックスマスター.JP(代表 宮崎智広)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Ansible > Ansibleのpre_tasks・post_tasksで実行順序を設計する方法|Playbookの前処理・後処理とhandlerの実行タイミングを理解する設計入門
「roleを実行する前にディスク残量を確認したい」「デプロイが終わってからヘルスチェックを走らせたい」。Ansible構成管理を運用で使い始めると、こうした要件が必ず出てきます。

Ansibleには、roleやtasksとは別に実行タイミングを制御する仕組みがあります。pre_tasksとpost_tasksです。この2つを設計に組み込むと、「roleが動く前にホストの前提条件を確認する」「全タスクが終わった後に通知やヘルスチェックを実行する」という構造が作れます。

この記事では、RHEL 9系~10系/Ubuntu 24.04 LTSを想定環境として、pre_tasks・post_tasksの役割と実践的な設計パターンを説明します。handlerとの実行タイミングの関係も整理します。

この記事のポイント

・pre_tasksはroles・tasks実行前、post_tasksは実行後に動く
・前提条件チェックをpre_tasksに入れると障害を事前に検出できる
・handlerの実行タイミングを把握するとPre/Post設計の信頼性が上がる
・flush_handlersでhandlerをその場で実行する場面を覚えておく


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

Ansibleのタスク実行順序を整理する

Playbookを実行したとき、タスクが動く順序はAnsibleが厳密に定めています。

1つのPlay(hosts:ブロック)の中での実行順序は、次のとおりです。

・pre_tasks
・rolesブロックに書いたrole(meta/main.ymlの依存roleも含む)
・tasksブロックに書いたタスク
・notifyで呼ばれたhandler(Play終了前にまとめて実行)
・post_tasks
・post_tasks内でnotifyされたhandler

この順序を把握していないと、「pre_tasksに書いたはずの確認が、roleより後に動いている」という見落としが起きます。

特に注意したいのは、roleとtasksの関係です。rolesブロックを書いた場合、tasksブロックより先にroleが動きます。「Playbookのtasksの前に動く処理」を書きたいときは、tasksに書くのではなくpre_tasksに書く必要があります。

pre_tasksで「始める前の確認」を設計する

pre_tasksの典型的な使い方は、roleやtasksを実行する前の前提条件チェックです。ここで問題を検出して処理を止めると、roleの途中で失敗するより被害が小さくて済みます。

1. ディスク残量を事前確認する

パッケージ展開やログ出力を伴うroleを動かす前に、ディスク残量が十分かどうかを確認する例です。

# pre_tasks でディスク残量を確認してから role を動かす例 - hosts: webservers pre_tasks: - name: ディスク残量が10GB以上あることを確認する ansible.builtin.assert: that: - ansible_mounts | selectattr('mount', '==', '/') | map(attribute='size_available') | first > 10737418240 fail_msg: "/ のディスク残量が不足しています。role の実行を中断します。" success_msg: "ディスク残量を確認しました。処理を続けます。" roles: - webserver_deploy

assertモジュールはthat:に指定した条件がfalseのとき、fail_msgを出してPlaybookを停止します。
roleが展開の途中で止まるより、pre_tasksで止まった方が後片付けが楽です。

2. 対象ホストのOSバージョンを確認する

RHELとUbuntuが混在する環境では、roleを動かす前にホストのOS情報を確認しておくと安全です。

# RHEL系のみに適用するroleを動かす前にOS確認 - hosts: all pre_tasks: - name: 対象OSがRHEL系であることを確認する ansible.builtin.assert: that: - ansible_os_family == "RedHat" fail_msg: "このPlaybookはRHEL系OSにのみ対応しています(検出: {{ ansible_os_family }})" roles: - rhel_hardening

ansible_os_familyはAnsibleが自動収集するfacts変数です。gather_facts: trueが前提で、デフォルトでは有効になっています。

3. サービスの起動状態を確認する

依存関係があるサービスが起動しているかどうかをpre_tasksで確認する例です。

# NTPサービスの起動を事前確認 - hosts: appservers pre_tasks: - name: chronydが起動していることを確認する ansible.builtin.service_facts: - name: chronydが起動状態であることをassertする ansible.builtin.assert: that: - ansible_facts.services['chronyd.service']['state'] == 'running' fail_msg: "chronydが起動していません。時刻同期を先に確認してください。" roles: - app_deploy

service_factsモジュールはホスト上の全サービスの状態を収集します。その結果をassertに渡すことで、特定サービスの稼働確認が1パターンで書けます。

post_tasksで「終わった後の処理」を設計する

post_tasksは、roleとtasksが終わった後に実行します。デプロイ後のヘルスチェック、通知送信、ログ記録など「後処理」に使います。

1. デプロイ後のヘルスチェック

Webアプリケーションをデプロイした後、エンドポイントが応答するかどうかを確認する例です。

# roleでデプロイ後にヘルスチェックを走らせる - hosts: webservers roles: - app_deploy post_tasks: - name: アプリケーションのヘルスチェックエンドポイントを確認する ansible.builtin.uri: url: "http://{{ inventory_hostname }}:8080/health" return_content: false status_code: 200 retries: 5 delay: 10 register: health_result until: health_result.status == 200

uriモジュールにretriesとdelayを設定すると、起動直後でレスポンスが遅れる場合でも再試行します。
post_tasksで確認が取れない場合はPlaybookが失敗するので、デプロイ成功の判定として使えます。

2. 通知を後処理として入れる

Slackへの通知をpost_tasksに入れると、Playbook全体の成否に関わらず「実行が終わった」ことを知らせる設計ができます。

# post_tasks で Slack 通知を送る post_tasks: - name: Slack にデプロイ完了を通知する community.general.slack: token: "{{ slack_token }}" msg: "{{ inventory_hostname }} へのデプロイが完了しました" channel: "#deploy-notify" delegate_to: localhost

delegate_to: localhostはこのタスクだけコントロールノード側で実行する指定です。SlackへのHTTPリクエストはコントロールノード側から送るのが一般的なパターンです。
Ansibleの構成管理・役割設計をより体系的に学びたい方には、AnsibleによるLinuxサーバー自動化講座で実務設計の全体像を整理できます。

handlerとpre/post_tasksの実行タイミングを理解する

handlerはnotifyで呼ばれたとき「その場ではなくPlaybook末尾にまとめて実行される」というルールがあります。このルールを把握していないと、pre_tasks・post_tasksとhandlerを組み合わせたときに予期しない順序で処理が動くことがあります。

1. handlerの実行タイミング

標準の動作では、handlerはPlay全体のタスク(pre_tasks・roles・tasks・post_tasks)が終わってから一度だけ実行されます。

次のような設計にしたとき、期待どおりに動かないケースがあります。

# 間違えやすい例: post_tasks の前に httpd を再起動したい tasks: - name: Apacheの設定ファイルを更新する ansible.builtin.template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf notify: httpd を再起動する post_tasks: - name: Apacheが応答することを確認する # この時点ではhandlerがまだ動いていない ansible.builtin.uri: url: "http://localhost/health" status_code: 200 handlers: - name: httpd を再起動する ansible.builtin.service: name: httpd state: restarted

この書き方では、post_tasksのヘルスチェックが実行されるときにhttpdの再起動がまだ終わっていません。設定変更が反映される前の状態でヘルスチェックが走ります。

2. flush_handlersでhandlerをその場で実行する

flush_handlersを使うと、その時点でnotifyされているhandlerをまとめて実行できます。

# flush_handlers で handler を先に実行してから post_tasks へ - hosts: webservers tasks: - name: Apacheの設定ファイルを更新する ansible.builtin.template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf notify: httpd を再起動する - name: notifyされたhandlerをここで先に実行する ansible.builtin.meta: flush_handlers post_tasks: - name: Apacheが応答することを確認する # この時点でhandlerは完了済み ansible.builtin.uri: url: "http://localhost/health" status_code: 200 handlers: - name: httpd を再起動する ansible.builtin.service: name: httpd state: restarted

ansible.builtin.meta: flush_handlersはタスクの一種として書きます。これを入れた時点で、それまでにnotifyされているすべてのhandlerが実行されます。

「設定変更→サービス再起動→後続タスク」という依存関係が必要な設計では、flush_handlersを明示的に入れることを検討してください。

3層構造のPlaybook設計パターン

pre_tasks・roles・post_tasksを使った「前処理→本処理→後処理」の3層構造は、Ansibleでよく使われる設計パターンです。

# 前処理・本処理・後処理の3層構造 - hosts: appservers gather_facts: true pre_tasks: - name: ディスク残量を確認する(1GB以上) ansible.builtin.assert: that: - ansible_mounts | selectattr('mount', '==', '/') | map(attribute='size_available') | first > 1073741824 fail_msg: "ディスク残量不足のため処理を中断します" - name: 依存サービスの起動を確認する ansible.builtin.service_facts: - name: MariaDBが起動していることをassertする ansible.builtin.assert: that: - ansible_facts.services['mariadb.service']['state'] == 'running' fail_msg: "MariaDBが起動していません" roles: - app_deploy - nginx_config post_tasks: - name: notifyされたhandlerを先に実行する ansible.builtin.meta: flush_handlers - name: アプリケーションのヘルスチェック ansible.builtin.uri: url: "http://{{ inventory_hostname }}/health" status_code: 200 retries: 3 delay: 10 register: check_result until: check_result.status == 200 - name: デプロイ完了をSlackへ通知する community.general.slack: token: "{{ slack_token }}" msg: "{{ inventory_hostname }} のデプロイが完了しました(ヘルスチェック: OK)" channel: "#ops-notify" delegate_to: localhost

この構造にすると、どのPlaybookを見ても「前処理→本処理→後処理」という流れが一目でわかります。チームで複数のPlaybookを管理するとき、構造の一貫性が保守性に直結します。

設計上の注意点

pre_tasks・post_tasksを使う上で、実務でよく引っかかるポイントをまとめます。

gather_factsの確認
ansible_mountsやansible_os_familyなどのfacts変数を使うpre_tasksを書く場合、gather_facts: trueが前提です。デフォルトはtrueですが、実行速度のためにfalseに設定したPlaybookでは動きません。facts変数を使う前にgather_factsの設定を確認してください。

pre_tasksのfailed_when設計
assertモジュールはfail_msgを設定しておくと、どの条件で止まったかがエラーメッセージから分かります。チームで運用するときは、fail_msgを「何が不足しているか」を具体的に書く習慣を持つと、原因調査の時間が短くなります。

post_tasksの冪等性
post_tasksに書く処理も冪等性(何度実行しても同じ結果になる性質)を意識してください。ヘルスチェックのuriモジュールはGETリクエストなので問題ありません。しかし通知送信のように「実行するたびにSlackにメッセージが届く」処理は、べき等ではありません。重複通知を防ぐ設計(register変数で変更の有無を確認してから送信する等)が必要な場合があります。

block・rescue・alwaysとの組み合わせ
post_tasksをalwaysに似た感覚で使う人がいますが、動作が異なります。post_tasksはPlaybookが途中で失敗すると実行されません。「失敗しても必ず実行したい後処理」がある場合は、block・rescue・alwaysの組み合わせを検討してください。post_tasksは「正常終了後の処理」と理解しておくと設計上の混乱が減ります。

本記事のまとめ

pre_tasks・post_tasksとhandlerの実行タイミングを整理します。
タイミング 使う場所 代表的な用途
role・tasks実行前 pre_tasks 前提条件チェック(ディスク残量・OS確認・依存サービス確認)
role・tasks実行後 post_tasks ヘルスチェック・通知送信・ログ記録
notifyされた時点でまとめて handlers 設定変更後のサービス再起動
flush_handlersを書いた時点で即時 tasks内のmeta post_tasks実行前にhandlerを完了させたい場合
pre_tasksに前提条件チェックを入れると、roleが途中で止まる前に問題を検出できます。post_tasksにヘルスチェックや通知を入れると、Playbookの完了が「本当に動いているか」の確認まで含む設計になります。

handlerのデフォルト動作(Play末尾でまとめて実行)を理解した上で、post_tasksの前にflush_handlersを入れる場面を判断できると、実行順序の設計が確実になります。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Ansibleを使った構成管理の実践設計をハンズオンで学べる講座を用意しています。インベントリ設計からrole分割・Vault管理まで、実務で使える構成を2日間で習得できます。
>> Ansible構成管理講座の詳細を見る

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

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

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

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

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

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

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

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

運営

リナックスマスター.JP(代表 宮崎智広)

株式会社イーネットマーキュリーが運営するLinux教育サイトです。代表の宮崎智広は現役のLinuxサーバー管理者として20年以上の実務経験を持ち、累計3,100名以上のエンジニアを指導してきました。実践型のLinuxセミナーや無料マニュアルの配布を通じてLinux人材の育成に取り組んでいます。