Sửa lỗi 'Failed to get D-Bus connection' trong Docker

trung bình🐳 Docker2026-07-10| Docker Engine, CentOS 7/8, Ubuntu 18.04+, Debian và các container dựa trên systemd khác.

Error Message

Failed to get D-Bus connection: Operation not permitted
#docker#systemd#devops#linux-admin

Vấn đề: Tại sao systemctl thất bạiCó thể bạn đang cố gắng khởi động một dịch vụ—như Nginx, Apache hoặc cơ sở dữ liệu—bên trong một container CentOS hoặc Ubuntu. Bạn chạy systemctl start, nhưng thay vì dịch vụ hoạt động, bạn lại gặp bế tắc. Terminal hiển thị một lỗi ngắn gọn: Failed to get D-Bus connection: Operation not permitted.

Điều này xảy ra vì các Docker container được thiết kế để nhẹ và cô lập. Theo mặc định, chúng không có quyền giao tiếp với systemd của máy chủ (host) hoặc quản lý phiên bản systemd của chính chúng. Systemd yêu cầu phải là tiến trình đầu tiên (PID 1) và cần quyền truy cập trực tiếp vào các control groups (cgroups) của máy chủ để hoạt động. Các cấu hình bảo mật tiêu chuẩn của Docker chặn quyền truy cập này để giữ an toàn cho máy chủ của bạn.

Cách khắc phục nhanh: Sử dụng Privileged ModeĐể systemd hoạt động, bạn cần gỡ bỏ các hạn chế mặc định của Docker. Điều này bao gồm việc cấp cho container các đặc quyền mở rộng và mount thư mục cgroup của máy chủ để systemd có thể quản lý các tiến trình một cách chính xác.

Khởi chạy container của bạn bằng các flag cụ thể sau:

docker run -d \  --name web-server \  --privileged \  -v /sys/fs/cgroup:/sys/fs/cgroup:ro \  centos:7 /usr/sbin/init

Giải thích câu lệnh:- --privileged: Cấp cho container quyền truy cập gần như toàn bộ vào phần cứng và các tính năng kernel của máy chủ.- -v /sys/fs/cgroup:/sys/fs/cgroup:ro: Ánh xạ các control groups của máy chủ vào container. Nếu không có lệnh này, systemd không thể theo dõi hoặc giới hạn tài nguyên của dịch vụ.- /usr/sbin/init: Đây là phần quan trọng nhất. Bạn đang yêu cầu Docker khởi động tiến trình init của systemd dưới dạng PID 1 thay vì chỉ đưa bạn vào shell bash.## Tự động hóa với Docker ComposeViệc nhập các câu lệnh docker run dài dòng một cách thủ công rất tẻ nhạt. Nếu bạn muốn cấu hình này cố định, hãy thêm các tham số này vào tệp docker-compose.yml của bạn. Điều này đặc biệt hữu ích cho các môi trường phát triển cục bộ nơi bạn thường xuyên khởi động lại các stack.

version: '3' 
services:
  app-server:
    image: centos:7
    privileged: true
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    command: /usr/sbin/init

Triển khai cấu hình đã cập nhật bằng một câu lệnh duy nhất:

docker-compose up -d

Điều gì đang diễn ra bên dưới?Docker được tối ưu hóa để chạy một tiến trình ứng dụng duy nhất. Ngược lại, systemd là một trình quản lý toàn diện được thiết kế để giám sát hàng chục dịch vụ chạy ngầm. Để thực hiện công việc của mình, systemd phải là tiến trình "cha" (PID 1).

Khi bạn chạy một container tiêu chuẩn, shell (bash) hoặc ứng dụng của bạn thường là PID 1. Khi bạn cố gắng sử dụng systemctl, nó sẽ tìm kiếm kết nối D-Bus để giao tiếp với PID 1. Vì systemd thực tế không chạy dưới dạng tiến trình init, kết nối sẽ thất bại. Bằng cách sử dụng /usr/sbin/init--privileged, về cơ bản bạn đang biến container của mình thành một máy ảo nhẹ.

Một giải pháp thay thế nhẹ nhàng hơn: Flag --initBạn có thực sự cần systemctl không, hay bạn chỉ cần quản lý các tiến trình? Nếu bạn chỉ muốn xử lý các tín hiệu (như SIGTERM) hoặc dọn dẹp các tiến trình zombie, bạn không cần toàn bộ gánh nặng của systemd. Docker 1.13 và các phiên bản mới hơn bao gồm một tiến trình init tích hợp sẵn gọi là tini.

docker run -it --init ubuntu:20.04 /bin/bash

Lưu ý: Cách này sẽ không sửa được lỗi D-Bus nếu ứng dụng của bạn bắt buộc yêu cầu systemctl. Tuy nhiên, đây là một cách an toàn hơn nhiều để xử lý quản lý tiến trình trong môi trường production.

Xác minh bản sửa lỗiSau khi khởi động container với flag privileged, hãy xác minh rằng systemd đang hoạt động tốt. Đầu tiên, truy cập vào terminal của container:

docker exec -it web-server /bin/bash

Sau đó, kiểm tra trạng thái hệ thống:

systemctl status

Nếu mọi thứ được thiết lập chính xác, bạn sẽ thấy State: running và danh sách các unit đang hoạt động. Bây giờ bạn có thể khởi động các dịch vụ của mình như bình thường trên một máy chủ vật lý:

systemctl start httpd
systemctl status httpd

Cảnh báo bảo mậtSử dụng --privileged là một cách tiếp cận khá mạnh tay. Nó cấp cho container quyền truy cập cấp root vào máy chủ của bạn. Trong môi trường production, đây là một rủi ro bảo mật đáng kể. Nếu một container bị xâm nhập, kẻ tấn công có khả năng thoát ra máy chủ. Hãy luôn cố gắng cấu trúc lại Dockerfile của bạn để chạy ứng dụng trực tiếp (sử dụng ENTRYPOINT) trước khi tìm đến giải pháp chạy systemd bên trong container.

Related Error Notes