Ansibleのcopyモジュールで発生する「could not find src」エラーの解決方法

beginner🔧 Ansible2026-06-30| Ansible (全バージョン), Linux/macOS コントロールノード, リモートターゲット (Ubuntu/CentOS/Debian)

Error Message

fatal: [host]: FAILED! => {"changed": false, "msg": "could not find src=/path/to/local/file.conf"}
#ansible#devops#トラブルシューティング#自動化#linux

問題のシナリオ

12台のWebサーバーに設定ファイルをデプロイしているとします。Playbookを実行し、一連の「changed」ステータスが緑色で表示されることを期待していますが、代わりにぶっきらぼうな赤いエラーメッセージが表示され、プロセスが停止してしまいます。

fatal: [web_server]: FAILED! => {"changed": false, "msg": "could not find src=/etc/configs/nginx.conf"}

自分のマシンで ls -l /etc/configs/nginx.conf を実行し、そこにファイルが存在することを確認すると、混乱が生じます。このエラーは、ディスクからファイルが消えたことを意味することは稀です。通常、Ansibleが相対パスを解決する方法により、意図した場所とは異なる場所を探していることを意味します。

なぜこのエラーが発生するのか

copy モジュールは、control node(コマンドを入力するノートPCやCI/CDランナー)から remote host へファイルを転送します。Ansibleプロセスがローカルでファイルを見つけられない場合、アップロードすることはできません。この失敗は通常、次の4つの問題のいずれかに起因します。

  • パスの不一致: ~/projects/ から ansible-playbook を実行したが、ソースパスが ~/projects/ansible/playbooks/ からの相対パスになっている。
  • ロール階層の違反: Ansibleロール内の標準的な files/ ディレクトリではなく、config/ という名前のフォルダにファイルを配置した。
  • 変数の失敗: {{ config_path }} のような変数が未定義であるか、タイポがあり、パスがnullまたは壊れている。
  • 権限の障壁: Ansibleを実行しているローカルユーザーにソースファイルの読み取り権限がなく、モジュールから「見えない」状態になっている。

クイックフィックス

1. 絶対パスでテストする

診断ステップとして絶対パスを使用します。フルパスでタスクが成功すれば、相対パスの問題であることが確認できます。例えば、src/home/dev/deploy/configs/app.conf に変更してみてください。これで動作する場合、ファイルにはアクセス可能であり、マッピングだけがずれていたことがわかります。

- name: Diagnostic copy using absolute path
  ansible.builtin.copy:
    src: /home/user/project/configs/app.conf
    dest: /etc/app/app.conf

2. Playbookのディレクトリに合わせる

デフォルトでは、Ansibleは実行している .yml ファイルからの相対パスでファイルを探します。ディレクトリ構造が以下の例のようになっている場合、src はPlaybookの隣にあるフォルダを指すだけで済みます。

# ディレクトリ構造:
# ├── site.yml
# └── files/
#     └── app.conf

- name: Copy app configuration
  ansible.builtin.copy:
    src: files/app.conf
    dest: /etc/app/app.conf

恒久的な対策とベストプラクティス

ロールのディレクトリ構造を活用する

ロールには、タスクを簡素化する組み込みの検索ロジックが備わっています。タスクが roles/webserver/tasks/main.yml 内にある場合、Ansibleは自動的に roles/webserver/files/ からソースファイルを探します。パスを完全に省略することも可能です。

標準的なロール構造:

roles/
  common/
    tasks/main.yml
    files/ntp.conf

main.yml 内のタスク:

- name: Deploy NTP config
  ansible.builtin.copy:
    src: ntp.conf  # Ansibleはこれを自動的に ../files/ から見つけます
    dest: /etc/ntp.conf

playbook_dir でパスを固定する

複雑なプロジェクトでは、異なるサブフォルダからPlaybookを実行することがよくあります。パスのポータビリティを維持するために、playbook_dir マジック変数を使用してください。これにより、コマンドをどこから実行したかに関わらず、常にPlaybookフォルダのルートからパスが計算されるようになります。

- name: Copy script from project root
  ansible.builtin.copy:
    src: "{{ playbook_dir }}/scripts/setup.sh"
    dest: /usr/local/bin/setup.sh
    mode: '0755'

ローカルコントローラーをデバッグする

エラーが解消されない場合は、Ansibleにローカルマシンの状態を強制的に報告させます。stat モジュールと delegate_to: localhost を使用して、コピーを試行する前にファイルの存在を確認します。これは、権限の問題や空の変数を特定する最も速い方法です。

- name: Verify local file existence
  ansible.builtin.stat:
    path: "{{ playbook_dir }}/files/my-config.conf"
  register: local_file
  delegate_to: localhost

- name: Fail if file is missing
  ansible.builtin.fail:
    msg: "The file was not found on the control node!"
  when: not local_file.stat.exists

検証ステップ

修正を適用した後、次の3つのステップでソリューションを検証します。

  • 詳細度を上げる: ansible-playbook -vv を実行します。出力により、Ansibleがローカルディスク上で開こうとしている正確な絶対パスが明らかになります。
  • ドライランを実行する: --check を付けて実行します。「could not find src」エラーが消えていれば、Ansibleはローカルファイルのマッピングに成功しており、プッシュする準備ができています。
  • 権限を確認する: Ansibleユーザーが読み取れるように、ローカルファイルに少なくとも 644 権限 (-rw-r--r--) があることを確認してください。

標準的なロール構造を使用したり、{{ playbook_dir }} でパスを固定したりすることで、これらのエラーの90%を排除できます。これらの習慣により、自動化の予測可能性が高まり、異なるチーム環境間でのポータビリティが確保されます。

Related Error Notes