无法获取 D-Bus 连接:操作不允许

无法获取 D-Bus 连接:操作不允许

我正在尝试使用以下方式列出在 Docker 中运行的 CentOS 映像上的服务

systemctl list-units  

但我收到此错误信息:

Failed to get D-Bus connection: Operation not permitted

有什么建议可以说明问题是什么吗?

答案1

我猜你正在运行一个non-privileged容器。systemd 需要 CAP_SYS_ADMIN 功能,但 Docker 在非特权容器中放弃了该功能,以增加安全性。

systemd 还需要容器内 cgroup 文件系统的 RO 访问权限。您可以使用以下命令添加它:–v /sys/fs/cgroup:/sys/fs/cgroup:ro

因此,这里有一些关于如何在 Docker 容器内使用 systemd 运行 CentOS 的步骤:

  1. 拉取 centos 镜像
  2. 设置如下所示的 docker 文件:
FROM centos
MAINTAINER "Yourname" <[email protected]>
ENV container docker
RUN yum -y update; yum clean all
RUN yum -y install systemd; yum clean all; \
(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 ["/usr/sbin/init"]
  1. 构建它 -docker build -t centos7-systemd - < mydockerfile

  2. 使用以下命令运行容器docker run --rm --privileged -ti -e container=docker -v /sys/fs/cgroup:/sys/fs/cgroup centos7-systemd /usr/sbin/init

  3. 你的容器中应该有 systemd

答案2

这不是对你的问题的直接回答,但实际上它可能更重要,我在阅读这里的其他答案时偶然意识到了这一点。

我曾经有过将一些复杂系统迁移到 Docker 的经验,其中的一个重要认识就是理想情况下每个应用程序/服务或“每个守护进程”应该有一个 Docker 容器。

其中一个非常重要的原因是Docker 不会彻底关闭使用 systemctl 启动的服务事实上,您最终可能会遇到与意外断电相同的数据库损坏问题。

更深入地讲:当 Docker 向容器发出“停止”命令时,它只会向使用 CMD/ENTRYPOINT 启动的单个进程发送 SIGTERM 信号,而不会向所有服务和守护进程发送。因此,一个服务会收到警告以彻底关闭,而所有其他服务都会被毫不客气地终止。

如果您必须将两个服务打包到同一个容器中(即您的应用程序和 PostgreSQL 数据库或类似的东西),那么您需要将 CMD/ENTRYPOINT 作为一个脚本,该脚本可以捕获 SIGTERM,然后将其重新广播到那些已知服务。这是可以做到的,但如果有机会,请重新考虑您的解决方案并尝试将其拆分到多个容器中。

附录

有一个有趣的Docker 网站上的注释/页面如果您确实需要在同一个容器中运行多个服务,请使用supervisord。

答案3

我已成功在 CentOS:7 Docker 容器中修复了此问题。我主要遵循CentOS Docker 镜像项目指南

FROM centos:7

ENV container docker
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/*;

# Install anything. The service you want to start must be a SystemD service.

CMD ["/usr/sbin/init"]

现在,构建图像,并使用至少以下命令参数来运行它docker run-v /run -v /sys/fs/cgroup:/sys/fs/cgroup:ro

那么主要的一点是它/usr/sbin/init必须是 Docker 容器内的第一个进程。

因此,如果您想使用在运行之前执行某些命令的自定义脚本/usr/sbin/init,请在脚本末尾使用exec /usr/sbin/init(在 bash 脚本中)启动它。

以下是一个例子:

ADD cmd.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/cmd.sh

CMD ["/usr/local/bin/cmd.sh"]

以下是 的内容cmd.sh

#!/bin/bash

# Do some stuffs

exec /usr/sbin/init # To correctly start D-Bus thanks to https://forums.docker.com/t/any-simple-and-safe-way-to-start-services-on-centos7-systemd/5695/8

System is booting up. See pam_nologin(8)如果您使用 PAM 系统,那么在这种情况下,您可以删除/usr/lib/tmpfiles.d/systemd-nologin.conf它,因为它会创建生成此特定错误的Dockerfile文件。/var/run/nologin

答案4

我不想必须将 systemd 作为 init/PID 1 启动。在完成其他人提到的清理步骤后,我从启动脚本中以 的身份启动 systemd /usr/lib/systemd/systemd --system &

这允许 systemd 启动并运行已注册的服务,但 systemctl 因 D-Bus 错误而失败。

对我来说,缺失的环节是缺少目录/run/systemd/system,通过stracesystemctl 发现了这一点。

在运行 systemctl 之前手动创建此目录可以使 systemctl 为我工作。

相关内容