エラーの内容
Ansible プレイブックで systemd モジュールを使ってサービスの起動・停止・有効化を行っています。通常の VM やベアメタルホストでは問題なく動作しますが、Docker や LXC コンテナをターゲットにすると、次のエラーが発生します:
TASK [Enable and start nginx] **************************
fatal: [container-host]: FAILED! => {
"changed": false,
"msg": "Failed to connect to bus: No such file or directory"
}
タスクは即座に失敗します。プレイブックの残りの処理も実行されません。
原因
Ansible の systemd モジュールは D-Bus 経由で systemd と通信します。通常の Linux ホストでは、D-Bus デーモンが /run/dbus/system_bus_socket をリッスンしており、問題なく接続できます。
コンテナにはそのソケットが存在しません。ほとんどのコンテナイメージには systemd や D-Bus が含まれていません。単一プロセスを実行するために作られており、フル init スタックを持つ設計ではないからです。Ansible が /run/dbus/system_bus_socket を探しても、そのファイルは存在しません。そのため No such file or directory というエラーになります。
このエラーが発生しやすい状況:
- Molecule テストや CI パイプラインで Docker コンテナを Ansible インベントリのターゲットとして使用している場合
- コンテナイメージが最小構成のディストリビューション(例:
ubuntu:22.04など、Ansible 専用イメージではないもの)の場合 - コンテナが
--privilegedオプションなし、または cgroup ファイルシステムをマウントせずに起動された場合 - Docker ドライバーを使用した Molecule でストックのベースイメージに対して実行している場合
修正方法 1: systemd の代わりに service を使う
systemd 固有の機能が不要な場合は、モジュールを切り替えるだけです。service モジュールは実際に稼働している init システムを自動検出して処理を委譲します:
# 修正前 — コンテナで失敗する
- name: Enable and start nginx
ansible.builtin.systemd:
name: nginx
state: started
enabled: true
# 修正後 — コンテナでも VM でも動作する
- name: Enable and start nginx
ansible.builtin.service:
name: nginx
state: started
enabled: true
init システムのないコンテナ内では、service は service バイナリまたは SysV init スクリプトを直接呼び出すフォールバック動作をします。D-Bus は不要です。ほとんどのケースで有効な一行修正です。
修正方法 2: ignore_errors でエラーを無視する(応急処置のみ)
コンテナ内では実質的に意味のない daemon_reload ステップでプレイブックが失敗するのを防ぎたいだけの場合、ignore_errors: true を付けることで一時的に回避できます:
- name: Reload systemd daemon
ansible.builtin.systemd:
daemon_reload: true
ignore_errors: true
- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
本番用プレイブックでは使用しないでください。実際の障害を隠蔽してしまいます。ロールをローカルで繰り返し確認する際に、テスト環境では daemon_reload が不要だとわかっている場合にのみ有用です。
修正方法 3: コンテナを検出して systemd タスクを条件付きでスキップする
VM とコンテナの両方に対して実行されるロールの場合、実行時に環境を検出し、when: 条件で systemd タスクをゲートするのが適切な方法です。
- name: Check if running inside a container
ansible.builtin.stat:
path: /.dockerenv
register: dockerenv_file
- name: Set container fact
ansible.builtin.set_fact:
is_container: "{{ dockerenv_file.stat.exists or ansible_virtualization_type in ['docker', 'lxc', 'container'] }}"
- name: Enable and start nginx (skip in containers)
ansible.builtin.systemd:
name: nginx
state: started
enabled: true
daemon_reload: true
when: not is_container
LXC コンテナには /.dockerenv が存在しないため、ansible_virtualization_type も合わせて確認してください。必要に応じて virtual サブセットを先に収集します:
- name: Gather virtualization facts
ansible.builtin.setup:
gather_subset:
- virtual
- name: Set is_container fact
ansible.builtin.set_fact:
is_container: "{{ ansible_virtualization_type in ['docker', 'lxc', 'podman', 'container', 'VirtualPC'] }}"
このアプローチにより、コンテナ版と VM 版でロールを分岐させることなく、ポータブルな構成を維持できます。
修正方法 4: systemd 対応コンテナを使う(Molecule / CI テスト)
サービス管理を本格的に扱うロールを作成する場合は、実際に systemd が動作するコンテナに対してテストしてください。Jeff Geerling の geerlingguy/docker-ubuntu2204-ansible イメージが標準的な選択肢です。systemd が設定済みの状態で利用できます。
# systemd サポート付きで docker run
docker run -d \
--name test-container \
--privileged \
--volume /sys/fs/cgroup:/sys/fs/cgroup:rw \
--cgroupns host \
geerlingguy/docker-ubuntu2204-ansible \
/lib/systemd/systemd
Molecule の場合は molecule/default/molecule.yml に以下のように設定します:
driver:
name: docker
platforms:
- name: instance
image: geerlingguy/docker-ubuntu2204-ansible
command: /lib/systemd/systemd
privileged: true
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
pre_build_image: true
systemd が PID 1 として起動すると、D-Bus も自動的に起動します。Ansible の systemd モジュールは通常通り接続でき、回避策は不要です。
修正方法 5: インベントリグループごとにサービスマネージャーを上書きする
VM とコンテナが混在するインベントリで、ロール全体に when: 条件を散在させたくない場合は、グループレベルで ansible_service_mgr を設定します:
# inventory/hosts
[containers]
container-01 ansible_connection=docker
[containers:vars]
ansible_service_mgr=sysvinit
ロールのタスクでは以下のように分岐します:
- name: Manage nginx service (systemd hosts)
ansible.builtin.systemd:
name: nginx
state: started
enabled: true
when: ansible_service_mgr == 'systemd'
- name: Manage nginx service (non-systemd hosts)
ansible.builtin.service:
name: nginx
state: started
when: ansible_service_mgr != 'systemd'
修正の確認
-v オプションを付けて再実行し、対象コンテナホストのみに絞ってバスエラーが解消されたことを確認します:
ansible-playbook -i inventory site.yml -v --limit container-01
正常な出力は次のようになります:
TASK [Enable and start nginx] **************************
ok: [container-01]
PLAY RECAP *********************************************
container-01 : ok=5 changed=1 unreachable=0 failed=0
修正方法 3(コンテナ検出)を採用した場合は、ファクトが正しく解決されているか確認するためにデバッグタスクを追加してください:
- name: Debug container detection
ansible.builtin.debug:
msg: "is_container={{ is_container }}, service_mgr={{ ansible_service_mgr }}"
クイックリファレンス
- 最速の修正:
ansible.builtin.systemd→ansible.builtin.serviceに切り替える - CI/Molecule:
geerlingguy/docker-ubuntu2204-ansibleを--privileged+ cgroup マウントで使用する - 混在インベントリ:
/.dockerenvまたはansible_virtualization_typeでコンテナを検出し、when:でゲートする - 根本原因:init システムを持たないコンテナには D-Bus ソケット
/run/dbus/system_bus_socketが存在しない

