問題の概要
ロジックを複数のファイルに分割することで、Ansibleロールをクリーンで管理しやすい状態に保つことができます。通常、include_tasksやimport_tasksを使用して、これらのスニペットをmain.ymlに読み込みます。しかし、ファイルがディレクトリ内に確実に存在している場合でも、Ansibleが「Could not find or access(見つからない、またはアクセスできない)」というエラーを返し、自動化が停止してしまうことがあります。
エラーは通常、以下のようになります。
ERROR! Could not find or access '/path/to/tasks/setup.yml' on the Ansible Controller.
If we are using a role, the lookup is relative to the role's tasks/ directory.
Make sure the file exists and is readable.
原因
Ansibleは厳格な検索階層に従います。ロール内で実行される場合、エンジンはそのロールのtasks/サブディレクトリ内にあるタスクファイルを自動的に検索します。ほとんどの失敗は、以下の4つの見落としに起因します。
- 冗長なパス: Ansibleがすでに参照しているパスに、手動で「tasks/」を追加している。
- 実行コンテキスト: ルートディレクトリからプレイブックを実行したことで、相対パスの検索が正しく機能していない。
- 大文字・小文字の区別: Linuxでは、
Setup.ymlとsetup.ymlは異なるファイルとして認識されます。 - 壊れたシンボリックリンク: コントローラー上に存在しないターゲットを指しているリンクを使用している。
ステップバイステップの解決策
1. 冗長なディレクトリプレフィックスを削除する
ファイル構造が以下のようになっていると仮定します。
roles/
my_app/
tasks/
main.yml
setup.yml
main.ymlの中で、誤って次のように記述している可能性があります。
# 誤り - tasks/tasks/setup.yml を検索することになります
- name: Include setup tasks
include_tasks: tasks/setup.yml
Ansibleはすでにtasks/フォルダを対象としているため、再度追加すると存在しないパスが生成されます。ファイル名のみを使用するように修正してください。
# 正解
- name: Include setup tasks
include_tasks: setup.yml
2. {{ role_path }} マジック変数を使用する
複雑なプロジェクトでは、パスをハードコーディングするのはリスクが伴います。別のロールからタスクを呼び出す場合や、ネストされたインクルードを扱う場合は、role_path変数を使用してください。これにより、コントローラー上の絶対パスが強制され、曖昧さが排除されます。
- name: Include setup from current role safely
include_tasks: "{{ role_path }}/tasks/setup.yml"
このアプローチは、プレイブックが標準的でないディレクトリ構造にある場合に非常に有効です。
3. 拡張子とタイポ(打ち間違い)を確認する
Ansibleはファイル拡張子を推測しません。ファイルがsetup.yamlであるのにコードでsetup.ymlを参照している場合、タスクは即座に失敗します。ディスク上に実際に何があるか、以下のコマンドで素早く確認してください。
ls roles/my_app/tasks/
深夜のデバッグ作業を避けるために、プロジェクト全体で.ymlか.yamlのどちらかの拡張子に統一しましょう。
4. ファイルシステムのパーミッションを確認する
ファイルは存在するものの、エラーメッセージの「access」の部分(アクセス権限)が不足している場合があります。ansible-playbookを実行するユーザーは、ファイルに対する読み取り権限と、すべての親ディレクトリに対する実行権限を持っている必要があります。以下のコマンドでパーミッションを修正してください。
# 標準的な読み取り権限 (644) とディレクトリへのアクセス権限 (755) を設定する
chmod 644 roles/my_app/tasks/setup.yml
chmod 755 roles/my_app/tasks/
5. 静的タスクロードと動的タスクロードの比較
import_tasksとinclude_tasksは似ていますが、動作が異なります。import_tasksは静的であり、プレイブックが最初に解析されるときに処理されます。一方、include_tasksは動的であり、実行時に評価されます。パスに、プレイ開始まで定義されない変数を使用している場合、import_tasksは失敗します。
# 実行時に評価されるため、これは機能します
- name: Dynamic include
include_tasks: "{{ os_family }}_tasks.yml"
# os_family が収集されたファクト(fact)である場合、これは多くの場合失敗します
- name: Static import
import_tasks: "{{ os_family }}_tasks.yml"
確認方法
Ansibleが具体的にどこを探しているかを確認するには、詳細出力を最大(-vvv)にしてプレイブックを実行してください。これにより、検索パスのロジックをリアルタイムで確認できます。
ansible-playbook site.yml -vvv
出力結果からsearching for...で始まる行を探してください。もし.../tasks/tasks/setup.ymlのようなパスが表示されていれば、冗長なディレクトリ指定のバグが見つかったことになります。
プロのヒント
- 深いネストを避ける: 1つのロールに5〜6個以上のタスクファイルが必要な場合、そのロールの役割が多すぎる可能性があります。2つの小さく専門化されたロールに分割することを検討してください。
- リンターを活用する:
ansible-lintを使用しましょう。コードを実行する前に、パスの問題や非推奨の構文を検出してくれます。 - 1秒チェック:
main.ymlとサブタスクが同じtasks/フォルダにあることを常に確認してください。これらのエラーの90%は、単純な配置ミスです。

