Ansibleのimport_tasksとinclude_tasksの違いと使い分け|静的・動的読み込みの設計判断

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Ansible > Ansibleのimport_tasksとinclude_tasksの違いと使い分け|静的・動的読み込みの設計判断
「import_tasksとinclude_tasks、どちらを使えばいい?」
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をデフォルトに


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

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.

import_tasksはパース時処理であるため、loopの値(変数など)はパース時に確定していないことが多く、技術的に対応できません。

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 での 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自体にのみ適用される

# include_tasks + tags - include_tasks: tasks/install.yml tags: install # → "install" タグはinclude_tasksというタスク自体のみに付く # ファイル内タスクへの伝播はない # --tags install でinclude_tasksは実行されるが、 # ファイル内タスクは独自のタグがないと --tags では細かく制御できない

include_tasksで --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の2件はタスク名のみです。この違いが、部分実行やデバッグの際に大きく影響します。

本記事のまとめ

import_tasksとinclude_tasksの主な違いをまとめます。
機能・挙動 import_tasks(静的読み込み) include_tasks(動的読み込み)
読み込みタイミング パース時(実行前) 実行時
ファイル名に変数使用 不可
whenの適用対象 各タスクにコピーして伝播 include_tasks自体に適用
loopのサポート 不可(エラー)
tagsの伝播 ファイル内全タスクに伝播 include_tasks自体のみ
--list-tasksでの表示 内部タスクまで表示 include_tasks名のみ
設計の原則は「特別な理由がなければimport_tasks、動的な読み込みが必要な箇所だけinclude_tasks」です。ファイル名への変数使用・loopによる繰り返し・条件によるファイル全体のスキップが必要な場合にinclude_tasksを選んでください。import_tasksは --list-tasks で全タスクを事前確認でき、tagsも自然に機能するため、Playbookを保守しやすくなります。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Ansible実践ハンズオンの詳細を見る >>

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

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

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

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

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

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

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

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

この記事を書いた人

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

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

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