コンテナ内でsystemdモジュール使用時のAnsible「Failed to connect to bus: No such file or directory」エラーの修正

intermediate🔧 Ansible2026-05-16| Ansible 2.9以降、Dockerコンテナ、LXCコンテナ、systemdモジュール、Ubuntu/Debian/CentOSゲスト

Error Message

Failed to connect to bus: No such file or directory
#ansible#systemd#dbus#docker#container

エラーの内容

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 システムのないコンテナ内では、serviceservice バイナリまたは 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.systemdansible.builtin.service に切り替える
  • CI/Moleculegeerlingguy/docker-ubuntu2204-ansible--privileged + cgroup マウントで使用する
  • 混在インベントリ/.dockerenv または ansible_virtualization_type でコンテナを検出し、when: でゲートする
  • 根本原因:init システムを持たないコンテナには D-Bus ソケット /run/dbus/system_bus_socket が存在しない

Related Error Notes