エラーの内容
Ansible Playbookを実行すると、直ちに次のエラーで失敗します:
fatal: [host]: FAILED! => {"changed": false, "msg": "Could not find or access 'templates/nginx.conf.j2' on the Ansible Controller."}
ほとんどの場合、ansible.builtin.template(または短縮形のtemplate)を使用しているタスクが原因です。エラーメッセージをよく見ると、Ansibleが検索したのはリモートホストではなく、ansible-playbookを実行したコントローラーマシンであることがわかります。つまり、Ansibleが期待する場所にファイルが存在しなかったということです。
原因
Ansibleは、PlaybookやロールからみてrelativeにあるNodeのtemplates/サブディレクトリを自動的に検索します。これはルックアップロジックに組み込まれています。そのため、srcにはファイル名だけを指定します。templates/nginx.conf.j2ではなく、nginx.conf.j2と書きます。
このエラーが発生する原因はほぼ次の2つです:
src: templates/nginx.conf.j2と書いた場合、Ansibleはtemplates/templates/nginx.conf.j2を探しますが、そのパスは存在しません。.j2ファイルが間違ったディレクトリに置かれており、Ansibleが実際に検索する場所にありません。
修正手順
ステップ1 — templateモジュールの呼び出し方を確認する
タスク内のsrcフィールドを確認します:
# 誤り — "templates/" プレフィックスを含めてはいけない
- name: nginx設定をデプロイ
ansible.builtin.template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
# 正しい — ファイル名のみを指定する
- name: nginx設定をデプロイ
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
AnsibleはPlaybookの隣、またはロール内のtemplates/を自動的に検索します。プレフィックスを追加すると、パスがtemplates/templates/nginx.conf.j2のように二重になり、そのパスは存在しません。
ステップ2 — ファイルが正しい場所にあるか確認する
シナリオA:Playbookレベルのテンプレート(ロールなし)
テンプレートはPlaybookのすぐ隣にあるtemplates/ディレクトリに配置する必要があります:
site.yml
templates/
nginx.conf.j2 ← ここに配置する必要がある
確認コマンド:
ls -la templates/nginx.conf.j2
シナリオB:ロール内のテンプレート
ロール内のタスクは、プロジェクトルートではなく、そのロール自身のtemplates/フォルダを参照します:
roles/
nginx/
tasks/
main.yml
templates/
nginx.conf.j2 ← ここに配置する必要がある
確認コマンド:
ls -la roles/nginx/templates/nginx.conf.j2
よくあるミス:テンプレートをプロジェクトルートのtemplates/に置いたまま、ロール内のタスクから実行してしまうケースです。Ansibleはロールのディレクトリを優先して検索するため、プロジェクトルートのファイルは見つかりません。
ステップ3 — ディレクトリ構造を修正する
ディレクトリが存在しない、または場所が間違っている場合は、ディレクトリを作成してファイルを移動します:
# "nginx" という名前のロールの場合
mkdir -p roles/nginx/templates
mv nginx.conf.j2 roles/nginx/templates/
# Playbookレベルのテンプレートの場合
mkdir -p templates
mv nginx.conf.j2 templates/
ステップ4 — タイポと大文字・小文字の区別を確認する
Linuxのファイルシステムは大文字・小文字を区別します。Nginx.conf.j2とnginx.conf.j2は全く別のファイルです。ディスク上の正確なファイル名を確認してください:
ls templates/
# 表示されるべきファイル名: nginx.conf.j2 (Nginx.conf.j2 ではない)
ステップ5 — 絶対パスを使用する(最終手段)
標準外の場所にテンプレートが保存されている場合は、フルパスを直接指定します:
- name: nginx設定をデプロイ
ansible.builtin.template:
src: /opt/configs/nginx.conf.j2
dest: /etc/nginx/nginx.conf
この方法は動作しますが、Playbookが特定のマシンに依存してしまいます。共有や再利用を予定しているPlaybookでは避けてください。
修正の確認
詳細なログを出力して、Ansibleが解決するパスを確認します:
ansible-playbook site.yml -vvv 2>&1 | grep -i "template\|j2"
正常に動作した場合、次のような出力が表示されます:
TASK [nginx設定をデプロイ] ****
ok: [host] => changed=true
ファイルを変更せずにテストしたい場合は、--checkオプションを追加します:
ansible-playbook site.yml --check
クイックリファレンス:Ansibleがテンプレートを検索する場所
# Playbookレベル(プロジェクトルートにsite.ymlがある場合)
./templates/
./
# ロールレベル(roles/nginx/tasks/main.yml内のタスク)
roles/nginx/templates/
roles/nginx/
./templates/ ← ここも確認されるが、ロールのテンプレートが優先される
./
Ansibleはこのリストを上から順に検索し、最初に見つかったものを使用します。templates/ディレクトリはすでに検索パスに含まれているため、srcにこのプレフィックスを追加すると、パスが二重になって検索が失敗する原因になります。
ヒント
srcにtemplates/プレフィックスを絶対に付けない — これがこのエラーの最大の原因であり、パッと見では気づきにくいポイントです。- フラットなPlaybookからロールにタスクを移行する際は、テンプレートも同時にロールの
templates/ディレクトリに移動してください。そうしないとAnsibleの検索パス外になります。 templates/内のサブディレクトリはsrcで問題なく使用できます。例:src: nginx/nginx.conf.j2はtemplates/nginx/nginx.conf.j2に解決されます。- テンプレートパスを調べる前に、
ansible-playbook --list-tasksを実行して、どのロールがそのタスクを所有しているか確認しましょう。

