Ansibleを本格的に使い始めると、Playbookが大きくなってきてタスクを複数ファイルに分割したくなります。その際に選択肢となるのが、この2つのモジュールです。どちらも外部タスクファイルを読み込む命令ですが、読み込まれるタイミングが根本的に異なります。
間違えると「whenを付けたのに全タスクが動く」「loopが使えない」「tagsが思った通りに効かない」といった問題が起きます。この記事では、RHEL 9.4 / Rocky Linux 9.4で動作確認した実例をもとに、import_tasksとinclude_tasksの仕組みの違い、when・loop・tagsへの影響、そして設計判断の指針を解説します。
この記事のポイント
・import_tasksは静的(パース時)、include_tasksは動的(実行時)に読み込まれる
・whenをimport_tasksに付けると各タスクに条件がコピーされ、loopは使用不可
・include_tasksはwhenでファイル全体をスキップ、loopで繰り返し読み込みが可能
・動的ファイル名・条件付き読み込み・繰り返しが不要なら、import_tasksをデフォルトに
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
import_tasksとinclude_tasksとは何か
Ansibleには、Playbookを複数のタスクファイルに分割して管理する仕組みがあります。以前はinclude: という単一のモジュールが使われていましたが、Ansible 2.4から機能が明確に2つに分離されました。・import_tasks:タスクファイルを静的に読み込む。Playbookの実行前(パース時)に処理される。
・include_tasks:タスクファイルを動的に読み込む。Ansibleがそのタスクに到達した実行時に処理される。
「パース時」とは、Ansibleが実行を開始する前にPlaybook全体を解析するフェーズです。import_tasksはこの段階でファイルを読み込み、タスクリストにインライン展開されます。include_tasksは実行中に初めてファイルを開きます。この「いつ読み込まれるか」という違いが、when・loop・tagsの挙動の差として現れます。
静的読み込み(import_tasks)の仕組みと特徴
import_tasksを使うと、タスクファイルはPlaybook全体が読み込まれる段階(パース時)で処理されます。ファイルの内容が親Playbookにインライン展開されるイメージです。基本的な書き方は次のとおりです。
# playbook.yml - name: Webサーバーのセットアップ hosts: webservers tasks: - name: パッケージインストールタスクを読み込む import_tasks: tasks/install.yml - name: 設定ファイルタスクを読み込む import_tasks: tasks/configure.yml
1. --list-tasksで全タスクが事前確認できる
import_tasksで読み込まれたタスクは、パース時点で親Playbookのタスクリストにつなぎ込まれます。そのためansible-playbook --list-tasks を実行すると、読み込み先ファイルの中身がすべて一覧に表示されます。どのタスクが実行されるか事前に把握したい場合に便利です。2. whenの条件は各タスクにコピーされる
import_tasksにwhenを付けると、その条件は読み込んだファイルの各タスクにコピーされることを覚えておいてください。# import_tasks + when の例 - name: RedHat系のみパッケージをインストール import_tasks: tasks/install_redhat.yml when: ansible_os_family == 'RedHat' # Ansibleが内部で展開するイメージ(パース時) # - task_1: # ansible.builtin.dnf: ... # when: ansible_os_family == 'RedHat' # 各タスクにコピーされる # - task_2: # ansible.builtin.template: ... # when: ansible_os_family == 'RedHat' # 同様にコピーされる
3. loopは使用不可
import_tasksにloopを付けることはできません。実行しようとすると次のエラーが返されます。ERROR! You cannot use loops on 'import_tasks' statements. You should use 'include_tasks' instead.
4. ファイル名に変数は使えない
パース時処理であるため、ファイル名は静的な文字列でなければなりません。# NG例:ファイル名に変数を使用するとエラーになる - import_tasks: "tasks/{{ env }}.yml" # OK例:静的なファイル名 - import_tasks: tasks/production.yml
動的読み込み(include_tasks)の仕組みと特徴
include_tasksを使うと、タスクファイルはAnsibleの実行中にそのタスクに到達した時点で読み込まれます。include_tasks自体が1つの「タスク」として扱われ、Ansibleはその実行タイミングでファイルを開きます。# playbook.yml(include_tasksの基本例) - name: Webサーバーのセットアップ hosts: webservers vars: env: production tasks: - name: 環境別タスクを読み込む include_tasks: "tasks/{{ env }}.yml"
1. ファイル名に変数を使用できる
実行時処理であるため、ファイル名にJinja2変数を使えます。環境名・OS名・ロール名などを変数として渡し、動的にタスクファイルを切り替える用途に向いています。2. whenの条件はinclude_tasks自体に適用される
include_tasksにwhenを付けると、条件はinclude_tasksというタスク自体に適用されます。# include_tasks + when の例 - name: オプション設定が有効なときのみ読み込む include_tasks: tasks/optional.yml when: enable_optional | bool
when: false の場合、タスクファイル自体が読み込まれません。ファイル内のタスクは1件も実行されないだけでなく、ファイルを開く処理すら行われません。「特定の条件が揃った場合のみ処理が必要な場面」や「後続ステップの結果次第で処理を切り替えたい場面」に適した動作です。3. loopで同一ファイルを繰り返し読み込める
include_tasksにloopを付けると、ループの各アイテムごとにタスクファイルが読み込まれます。ユーザーリストやサービスリストに対して同じ処理を繰り返す場面で有効です。# include_tasks + loop の例 - name: ユーザーごとにセットアップタスクを実行 include_tasks: tasks/setup_user.yml loop: "{{ app_users }}" loop_control: loop_var: current_user
4. --list-tasksには内部タスクが表示されない
include_tasksは実行時にファイルを読み込むため、ansible-playbook --list-tasks の実行時点ではどのタスクが含まれるか未確定です。一覧には include_tasks のタスク名だけが表示され、ファイル内のタスク名は表示されません。when/loop/tagsの挙動の違い
import_tasksとinclude_tasksで最も重要な挙動の違いは when・loop・tags です。実務でつまずくポイントを整理します。1. whenの伝播の違い
import_tasks + when:各タスクに条件がコピーされる# 書いたコード - import_tasks: tasks/setup.yml when: env == 'production' # Ansibleが内部で解釈するイメージ(パース時にインライン展開) - name: タスク1(setup.yml内) ansible.builtin.dnf: name: httpd state: present when: env == 'production' # 各タスクに条件がコピーされる - name: タスク2(setup.yml内) ansible.builtin.template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf when: env == 'production' # 同様にコピーされる
# include_tasks での when の挙動 - include_tasks: tasks/setup.yml when: env == 'production' # env != 'production' の場合 → ファイルごとスキップ(タスクは1件も実行されない) # env == 'production' の場合 → ファイルを読み込み、全タスクを実行
2. loopの対応状況
loopはinclude_tasksでのみ使用できます。import_tasksにloopを付けるとエラーになります。Rocky Linux 9.4(ansible-core 2.15系)で動作確認した実例を示します。# playbook.yml - name: 複数サービスのセットアップ hosts: appservers vars: services: - name: nginx port: 80 - name: redis port: 6379 tasks: - name: サービスごとにセットアップを実行 include_tasks: tasks/service_setup.yml loop: "{{ services }}" loop_control: loop_var: service # --- 実行結果(app01.internal) --- # TASK [サービスごとにセットアップを実行] # included: /home/ansible/tasks/service_setup.yml for app01.internal # => (item={'name': 'nginx', 'port': 80}) # included: /home/ansible/tasks/service_setup.yml for app01.internal # => (item={'name': 'redis', 'port': 6379})
3. tagsの伝播の違い
import_tasks + tags:タグがファイル内の全タスクに伝播する# import_tasks + tags - import_tasks: tasks/install.yml tags: install # → tasks/install.yml 内の全タスクに "install" タグが付く # ansible-playbook site.yml --tags install で全タスクが実行される # ansible-playbook site.yml --list-tags でも "install" タグが表示される
# include_tasks + tags - include_tasks: tasks/install.yml tags: install # → "install" タグはinclude_tasksというタスク自体のみに付く # ファイル内タスクへの伝播はない # --tags install でinclude_tasksは実行されるが、 # ファイル内タスクは独自のタグがないと --tags では細かく制御できない
--tags を使っても、タスクファイル内のタスクにはタグが伝播しません。ファイル内タスクをタグで細かく制御したい場合は、各タスクに直接タグを付けるか、import_tasksに切り替えてください。import_tasks / include_tasksの使い分けを含むPlaybook構造設計を実機で体験したい方は、>> Ansibleハンズオン講座の詳細を見る をご覧ください。
設計判断の指針:どちらを使うべきか
import_tasksとinclude_tasksのどちらを使うかは、次のポイントで判断します。import_tasksを選ぶ場面
・タスクファイルは常に読み込まれる(条件によって読み込み自体をスキップしない)
・ファイル名が静的(変数を使わない)
・
--list-tasks / --list-tags で全タスク・全タグを事前確認したい・tagsをファイル内の全タスクに一括で適用したい
include_tasksを選ぶ場面
・ファイル名を変数で動的に切り替えたい(例:
"tasks/{{ os }}.yml")・条件次第でファイル全体の読み込みをスキップしたい
・同一ファイルをloopで繰り返し読み込みたい
・実行時に初めて確定する情報(変数・ファクト)に基づいてファイルを決定したい
シンプルな判断フロー
迷ったときは次の順序で確認します。・ファイル名に変数を使いたい → include_tasks(import_tasksは不可)
・loopで繰り返したい → include_tasks(import_tasksは不可)
・条件次第でファイル全体をスキップしたい → include_tasks
・上記に当てはまらない → import_tasks(デフォルト選択)
実務では「特別な理由がなければimport_tasks、動的な読み込みが必要な箇所だけinclude_tasksを使う」設計がトラブルを減らします。import_tasksは
--list-tasks で事前確認がしやすく、tagsも素直に機能するため、Playbookの可読性が高まります。なお、Ansible 2.4以前のコードで
include: を見かけた場合は、動的読み込みが必要かどうかを確認した上でinclude_tasks / import_tasksに移行してください。実践例:役割別にタスクファイルを分割する
Webサーバーのセットアップを例に、import_tasksとinclude_tasksを組み合わせた設計パターンを示します。1. ディレクトリ構成
site.yml tasks/ packages.yml # パッケージインストール(常に実行) configure.yml # 設定ファイルの配置(常に実行) firewall.yml # ファイアウォール設定(常に実行) setup_user.yml # ユーザー作成(ユーザーごとに繰り返す) debug.yml # デバッグ設定(開発環境のみ)
2. Playbookの構成例(Rocky Linux 9.4で動作確認済み)
# site.yml - name: Webサーバー構築 hosts: webservers vars: env: production app_users: - deploy - monitor tasks: # 常に必要なタスクはimport_tasks(静的・タグ伝播) - name: パッケージインストール import_tasks: tasks/packages.yml tags: packages - name: 設定ファイルの配置 import_tasks: tasks/configure.yml tags: configure - name: ファイアウォール設定 import_tasks: tasks/firewall.yml tags: firewall # ユーザーごとの繰り返し処理はinclude_tasks + loop - name: アプリユーザーのセットアップ include_tasks: tasks/setup_user.yml loop: "{{ app_users }}" loop_control: loop_var: target_user # 開発環境のみ読み込む設定はinclude_tasks + when - name: デバッグ設定の読み込み include_tasks: tasks/debug.yml when: env != 'production'
3. --list-tasksで確認した出力の違い
上記のPlaybookに対してansible-playbook site.yml --list-tasks を実行すると、import_tasksで読み込んだ packages.yml・configure.yml・firewall.yml の中身がすべて展開されて表示されます。一方、include_tasksで読み込む setup_user.yml・debug.yml は「include_tasksタスク名」のみが表示されます。[tomohiro@control-node ~]$ ansible-playbook site.yml -i inventory/hosts --list-tasks playbook: site.yml play #1 (webservers): Webサーバー構築 TAGS: [] tasks: パッケージインストール | httpd をインストール TAGS: [packages] パッケージインストール | mod_ssl をインストール TAGS: [packages] 設定ファイルの配置 | httpd.conf を配置 TAGS: [configure] ファイアウォール設定 | http ポートを開放 TAGS: [firewall] アプリユーザーのセットアップ TAGS: [] デバッグ設定の読み込み TAGS: []
本記事のまとめ
import_tasksとinclude_tasksの主な違いをまとめます。| 機能・挙動 | import_tasks(静的読み込み) | include_tasks(動的読み込み) |
|---|---|---|
| 読み込みタイミング | パース時(実行前) | 実行時 |
| ファイル名に変数使用 | 不可 | 可 |
| whenの適用対象 | 各タスクにコピーして伝播 | include_tasks自体に適用 |
| loopのサポート | 不可(エラー) | 可 |
| tagsの伝播 | ファイル内全タスクに伝播 | include_tasks自体のみ |
| --list-tasksでの表示 | 内部タスクまで表示 | include_tasks名のみ |
--list-tasks で全タスクを事前確認でき、tagsも自然に機能するため、Playbookを保守しやすくなります。
Ansible実践ハンズオンの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 前のページへ:Ansibleのasyncとpollで長時間タスクを制御する方法|タイムアウト対策と並行実行の設計
- この記事の属するカテゴリ:Ansibleへ戻る

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