Sửa lỗi Ansible 'Failed to connect to bus: No such file or directory' khi dùng module systemd trong Container

intermediate🔧 Ansible2026-05-16| Ansible 2.9+, Docker containers, LXC containers, systemd module, Ubuntu/Debian/CentOS guests

Error Message

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

Lỗi Gặp Phải

Playbook Ansible của bạn dùng module systemd để start, stop hoặc enable một service. Trên VM hoặc máy chủ bare-metal thì chạy tốt. Nhưng khi target vào Docker hay LXC container, bạn gặp lỗi này:

TASK [Enable and start nginx] **************************
fatal: [container-host]: FAILED! => {
    "changed": false,
    "msg": "Failed to connect to bus: No such file or directory"
}

Task dừng ngay lập tức. Không có gì trong playbook chạy tiếp nữa.

Nguyên Nhân

Module systemd của Ansible giao tiếp với systemd qua D-Bus. Trên một Linux host bình thường, D-Bus daemon lắng nghe tại /run/dbus/system_bus_socket và mọi thứ kết nối suôn sẻ.

Container không có socket đó. Hầu hết các image container được ship mà không có systemd hay D-Bus — chúng được xây dựng để chạy một process duy nhất, không phải một init stack đầy đủ. Khi Ansible đi tìm /run/dbus/system_bus_socket, file đơn giản là không tồn tại. Do đó: No such file or directory.

Bạn sẽ gặp lỗi này thường xuyên nhất khi:

  • Bạn đang dùng Docker container làm Ansible inventory target cho Molecule testing hoặc CI pipeline
  • Image container của bạn là bản distro tối giản (ví dụ: ubuntu:22.04, không phải image Ansible chuyên dụng)
  • Container được khởi động mà không có --privileged hoặc không mount cgroup filesystem
  • Bạn đang chạy Molecule với Docker driver trên một base image mặc định

Fix 1: Dùng service Thay Vì systemd

Không cần tính năng đặc thù của systemd? Chỉ cần đổi module. Module service tự dò init system đang chạy và ủy thác cho nó:

# Trước — bị lỗi trong container
- name: Enable and start nginx
  ansible.builtin.systemd:
    name: nginx
    state: started
    enabled: true

# Sau — hoạt động trong container lẫn VM
- name: Enable and start nginx
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

Bên trong container không có init system, service sẽ fallback sang gọi trực tiếp binary service hoặc SysV init script. Không cần D-Bus. Đây là cách fix một dòng cho hầu hết các trường hợp.

Fix 2: Bỏ Qua Lỗi Bằng ignore_errors (Giải Pháp Tạm Thời)

Đôi khi bạn chỉ cần playbook không bị crash trong bước daemon_reload vốn không thực sự quan trọng trong container. Thêm ignore_errors: true vào để giải quyết tạm thời:

- name: Reload systemd daemon
  ansible.builtin.systemd:
    daemon_reload: true
  ignore_errors: true

- name: Start nginx
  ansible.builtin.service:
    name: nginx
    state: started

Đừng dùng cách này trong playbook production. Nó che giấu các lỗi thật sự. Chỉ hữu ích khi bạn đang phát triển role ở local và biết rõ rằng daemon_reload không liên quan trong môi trường test của mình.

Fix 3: Phát Hiện Container Và Bỏ Qua Task Systemd Có Điều Kiện

Với các role chạy trên cả VM lẫn container, cách đúng đắn là phát hiện môi trường lúc runtime và đặt điều kiện when: cho các task systemd.

- name: Kiểm tra xem có đang chạy trong container không
  ansible.builtin.stat:
    path: /.dockerenv
  register: dockerenv_file

- name: Đặt fact container
  ansible.builtin.set_fact:
    is_container: "{{ dockerenv_file.stat.exists or ansible_virtualization_type in ['docker', 'lxc', 'container'] }}"

- name: Enable and start nginx (bỏ qua trong container)
  ansible.builtin.systemd:
    name: nginx
    state: started
    enabled: true
    daemon_reload: true
  when: not is_container

LXC container sẽ không có /.dockerenv, nên cần kiểm tra thêm ansible_virtualization_type. Thu thập virtual subset trước nếu chưa làm:

- name: Thu thập virtualization facts
  ansible.builtin.setup:
    gather_subset:
      - virtual

- name: Đặt fact is_container
  ansible.builtin.set_fact:
    is_container: "{{ ansible_virtualization_type in ['docker', 'lxc', 'podman', 'container', 'VirtualPC'] }}"

Cách này giúp role của bạn linh hoạt mà không cần fork thành hai phiên bản riêng cho container và VM.

Fix 4: Chạy Container Có Hỗ Trợ Systemd (Molecule / CI Testing)

Viết role thực sự quản lý service? Hãy test nó trên container chạy được systemd. Image geerlingguy/docker-ubuntu2204-ansible của Jeff Geerling là lựa chọn tiêu chuẩn — đã được cấu hình sẵn systemd và sẵn sàng dùng.

# docker run với hỗ trợ systemd
docker run -d \
  --name test-container \
  --privileged \
  --volume /sys/fs/cgroup:/sys/fs/cgroup:rw \
  --cgroupns host \
  geerlingguy/docker-ubuntu2204-ansible \
  /lib/systemd/systemd

Với Molecule, cấu hình trong 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

Khi systemd chạy như PID 1, D-Bus khởi động tự động. Module systemd của Ansible kết nối bình thường — không cần workaround nào.

Fix 5: Ghi Đè Service Manager Theo Inventory Group

Inventory hỗn hợp — vừa có VM vừa có container — và bạn không muốn rải điều kiện when: khắp nơi trong role? Đặt ansible_service_mgr ở cấp độ group:

# inventory/hosts
[containers]
container-01 ansible_connection=docker

[containers:vars]
ansible_service_mgr=sysvinit

Sau đó phân nhánh theo biến này trong task của role:

- name: Quản lý nginx service (host dùng systemd)
  ansible.builtin.systemd:
    name: nginx
    state: started
    enabled: true
  when: ansible_service_mgr == 'systemd'

- name: Quản lý nginx service (host không dùng systemd)
  ansible.builtin.service:
    name: nginx
    state: started
  when: ansible_service_mgr != 'systemd'

Kiểm Tra Sau Khi Fix

Chạy lại với -v và giới hạn vào container host để xác nhận lỗi bus đã biến mất:

ansible-playbook -i inventory site.yml -v --limit container-01

Output sạch trông như thế này:

TASK [Enable and start nginx] **************************
ok: [container-01]

PLAY RECAP *********************************************
container-01  : ok=5  changed=1  unreachable=0  failed=0

Nếu bạn dùng Fix 3 (phát hiện container), thêm một debug task để xác nhận fact được resolve đúng:

- name: Debug phát hiện container
  ansible.builtin.debug:
    msg: "is_container={{ is_container }}, service_mgr={{ ansible_service_mgr }}"

Tóm Tắt Nhanh

  • Fix nhanh nhất: đổi ansible.builtin.systemdansible.builtin.service
  • CI/Molecule: dùng geerlingguy/docker-ubuntu2204-ansible với --privileged + mount cgroup
  • Inventory hỗn hợp: phát hiện container qua /.dockerenv hoặc ansible_virtualization_type, kiểm soát bằng when:
  • Nguyên nhân gốc rễ: D-Bus socket /run/dbus/system_bus_socket không tồn tại trong các container không chạy init system

Related Error Notes