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

Sno*_*ash 56 centos systemd systemctl docker

我正在尝试使用在 Docker 中运行的 CentOS 映像列出服务

systemctl list-units  
Run Code Online (Sandbox Code Playgroud)

但我收到此错误消息:

Failed to get D-Bus connection: Operation not permitted
Run Code Online (Sandbox Code Playgroud)

任何建议可能是什么问题?

13d*_*tar 43

我的猜测是您正在运行一个non-privileged容器。systemd 需要 CAP_SYS_ADMIN 功能,但 Docker 在非特权容器中删除了该功能,以增加更多安全性。

systemd 还需要 RO 访问容器内的 cgroup 文件系统。你可以添加它–v /sys/fs/cgroup:/sys/fs/cgroup:ro

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

  1. 拉取centos镜像
  2. 设置一个 docker 文件,如下所示:
FROM centos
MAINTAINER "Yourname" <youremail@address.com>
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"]
Run Code Online (Sandbox Code Playgroud)
  1. 建造它 - docker build --rm -t centos7-systemd - < mydockerfile
  2. 运行一个容器 docker run --privileged -ti -e container=docker -v /sys/fs/cgroup:/sys/fs/cgroup centos7-systemd /usr/sbin/init

  3. 您应该在容器中安装 systemd

  • 答对了!我正在使用 `/bin/bash` 运行容器以获得一个 shell。但是,这给了我前面提到的错误。当我按照建议使用 `/usr/sbin/init` 运​​行它然后附加一个 shell 时一切顺利。很明显,我遗漏了关于 `/usr/sbin/init` 的细微差别。这个答案值得一些实质性的支持。 (8认同)
  • 万一我不清楚!我仍然收到错误“无法获得 D-Bus 连接:不允许操作” (2认同)

Mur*_*ams 13

这不是您问题的直接答案,但实际上可能更重要,我在阅读此处的其他答案时发现了这一点。

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

一个非常重要的原因是Docker 不会干净地关闭您使用 systemctl 启动的服务,事实上,您最终可能会因意外断电而导致相同类型的数据库损坏。

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

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

附录

如果您绝对需要在同一个容器中运行多个服务,Docker 站点上有一个关于使用 supervisord的有趣注释/页面


Ant*_* O. 8

我已经在 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"]
Run Code Online (Sandbox Code Playgroud)

现在,构建映像,并至少使用以下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"]
Run Code Online (Sandbox Code Playgroud)

这是内容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
Run Code Online (Sandbox Code Playgroud)

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