根本原因在于docker容器默认不以systemd为pid 1,且cgroup命名空间隔离、能力限制及挂载点缺失与systemd需掌控整机资源的架构前提直接冲突;必须显式设/sbin/init为cmd、加--privileged、挂载cgroup v2并安装dbus等依赖组件。

根本原因在于 Docker 容器默认不以 systemd 为 PID 1,且隔离机制(cgroup 命名空间、能力限制、挂载点缺失)与 systemd 的运行前提直接冲突。这不是配置疏漏,而是架构设计上的不兼容——systemd 需要掌控整机资源视图,而容器只提供受限的子集。
确保容器以 systemd 为 init 进程(PID 1)
这是最基础也最关键的一步。Docker 默认启动的是你指定的命令(如 /bin/bash 或应用二进制),而非初始化系统。必须显式将 /sbin/init 或 /usr/sbin/init 设为容器入口:
- 启动时用 docker run -it --privileged centos:8 /sbin/init,不能跟 /bin/bash
- Dockerfile 中写 CMD ["/sbin/init"],而非 CMD ["bash"] 或应用命令
- 必须加 --privileged,否则 systemd 启动时因缺少 CAP_SYS_ADMIN 等能力而失败
满足 cgroup v2 的挂载要求(Docker 20.10+ 默认启用)
新版 Docker 使用 cgroup v2,而 systemd 要求 /sys/fs/cgroup 以 unified 模式挂载。若容器内该路径为空或为 v1 混合挂载,systemd 会拒绝启动:
- 启动容器时添加 --mount type=bind,source=/sys/fs/cgroup,target=/sys/fs/cgroup,readonly=false
- 确保宿主机已启用 cgroup v2(检查 /proc/sys/fs/cgroup/unified_hierarchy 是否为 1)
- 避免混用 v1 控制器挂载;若必须兼容旧环境,可在宿主机启用 systemd.unified_cgroup_hierarchy=0 内核参数
补全 systemd 依赖的运行时环境
即使 init 启动成功,dbus、logind、journald 等组件缺失仍会导致 systemctl status 报 “Failed to get D-Bus connection”:
- 基础镜像需完整安装 systemd 相关包:CentOS 用 dnf install -y systemd dbus,Ubuntu 用 apt-get install -y systemd dbus
- 容器启动后,/run/dbus/system_bus_socket 和 /run/systemd/journal/socket 必须存在且可访问
- 推荐使用官方 centos:stream、ubuntu:22.04 等带完整 systemd 支持的镜像,避开 Alpine、Distroless 等精简版
验证与调试关键信号
不要仅凭 systemctl list-units 是否返回来判断成功,需逐层确认:
- 进容器执行 ps -p 1 -o comm=,输出必须是 systemd
- 运行 systemd-detect-virt,应返回 container-other(非 none)
- 检查 systemctl is-system-running,正常应返回 running,而非 initializing 或报错
- 若卡在 Starting Journal Service...,大概率是 /run/log/journal 权限或挂载问题











