Vấn đềBạn cố gắng chạy systemctl start nginx hoặc systemctl status ssh bên trong một Docker container. Thay vì dịch vụ được khởi chạy, bạn lại gặp phải lỗi phổ biến sau:
Failed to get D-Bus connection: Operation not permitted
Các Docker container được thiết kế để nhẹ và cô lập. Theo mặc định, chúng thiếu quyền để giao tiếp với D-Bus của máy chủ (host) hoặc quản lý các dịch vụ hệ thống. Systemd yêu cầu phải là tiến trình đầu tiên (PID 1). Nó cũng yêu cầu quyền truy cập trực tiếp vào các control groups (cgroups) của máy chủ, điều mà Docker hạn chế vì lý do bảo mật.
Tại sao điều này lại xảy ra vào lúc 2 giờ sángCác image tiêu chuẩn như ubuntu:22.04 hoặc centos:7 không khởi động hệ thống init theo mặc định. Khi bạn chạy docker run -it ubuntu /bin/bash, shell bash sẽ trở thành PID 1. Systemd thậm chí còn không chạy ngầm. Khi systemctl cố gắng tìm daemon systemd thông qua D-Bus, nó sẽ bị chặn lại. Container đơn giản là không có đặc quyền để giao tiếp với bus của máy chủ, vì vậy thao tác thất bại.
Giải pháp 1: Cờ Privileged và Gắn (Mount) CgroupĐôi khi bạn buộc phải chạy systemd, chẳng hạn như để kiểm thử các Ansible playbook hoặc các ứng dụng cũ (legacy). Cách khắc phục nhanh nhất là cấp cho container các đặc quyền mở rộng và gắn hệ thống tệp cgroup của máy chủ. Điều này thực chất cung cấp cho container quyền truy cập "tương đương root" vào phần cứng của máy chủ.
Các bước thực hiện:- Dừng và xóa container hiện tại của bạn.- Khởi chạy một container mới bằng cờ --privileged.- Gắn /sys/fs/cgroup dưới dạng một volume chỉ đọc (read-only).Đối với image CentOS 7, câu lệnh sẽ như sau:
docker run -d \
--name my-container \
--privileged \
-v /sys/fs/cgroup:/sys/fs/cgroup:ro \
centos:7 /usr/sbin/init
Lưu ý: Bạn phải sử dụng /usr/sbin/init làm lệnh khởi chạy. Điều này sẽ kích hoạt tiến trình systemd dưới dạng PID 1 bên trong container.
Giải pháp 2: Sử dụng Image Systemd chuyên dụng (Được khuyến nghị)Các base image gốc (vanilla) rất khó để cấu hình cho systemd. Thay vào đó, hãy sử dụng các image do cộng đồng duy trì đã được cấu hình sẵn cho mục đích này. Các image jrei là tiêu chuẩn công nghiệp trong trường hợp này. Chúng tự động xử lý quá trình bắt tay (handshake) phức tạp giữa Docker và systemd.
Dành cho Ubuntu:```
docker run -d \ --name systemd-ubuntu \ --privileged \ -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ jrei/systemd-ubuntu
### Dành cho CentOS:```
docker run -d \
--name systemd-centos \
--privileged \
-v /sys/fs/cgroup:/sys/fs/cgroup:ro \
jrei/systemd-centos
Truy cập vào container sau khi nó khởi động:
docker exec -it systemd-ubuntu bash
Chạy systemctl status. Bạn sẽ thấy một cây dịch vụ đang hoạt động thay vì một thông báo lỗi.
Giải pháp 3: Sử dụng DockerfileBạn đang xây dựng một image tùy chỉnh? Bạn cần cài đặt systemd và dọn dẹp các unit không cần thiết có thể gây lỗi trong môi trường ảo hóa. Đây là một đoạn mã đã được kiểm chứng cho Ubuntu 22.04:
FROM ubuntu:22.04
ENV container docker
RUN apt-get update && apt-get install -y systemd systemd-sysv && apt-get clean
# Strip down systemd to run inside a container
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/lib/systemd/systemd"]
Xác minh: Cách xác nhận lỗi đã được khắc phụcSau khi container đang chạy, hãy thực hiện hai bước kiểm tra nhanh. Đầu tiên, xác minh systemd là PID 1:
ps -p 1 -o comm=
Nó sẽ trả về systemd hoặc init. Tiếp theo, kiểm tra trạng thái hệ thống:
systemctl status
Nếu bạn thấy cây trạng thái systemd tiêu chuẩn, bạn đã vượt qua giới hạn D-Bus thành công.
Cảnh báo bảo mật quan trọngCờ --privileged giống như một "chiếc búa tạ". Nó phá vỡ cơ chế sandbox của container và cho phép các tiến trình bên trong container có khả năng can thiệp vào hệ thống máy chủ của bạn. Hãy tránh cấu hình này cho bất kỳ môi trường production nào công khai. Nó chỉ dành riêng cho việc phát triển cục bộ hoặc kiểm thử CI/CD có kiểm soát.
Mẹo nhỏ: Bạn có thực sự cần systemd không?Các phương pháp hay nhất (best practices) của Docker gợi ý nên chạy một tiến trình trên mỗi container. Thay vì sử dụng systemctl start nginx, hãy chạy trực tiếp file thực thi của dịch vụ ở chế độ foreground. Điều này giúp image của bạn nhẹ hơn—thường tiết kiệm hơn 100MB dung lượng đĩa—và an toàn hơn đáng kể.
- Đối với Nginx:
CMD ["nginx", "-g", "daemon off;"]- Đối với Apache:CMD ["apache2ctl", "-D", "FOREGROUND"]Bằng cách bỏ qua systemd, bạn hoàn toàn tránh được rắc rối với D-Bus và tuân theo đúng tư duy cloud-native.

