我正在构建一个 Docker 映像,用于运行一堆使用 D-Bus 相互通信的后台进程。我的图像基于 Ubuntu Bionic。该系统已经可以在本机 Debian 9 上运行。
我需要做什么才能使 D-Bus 在容器内工作?我通过谷歌搜索找到了一些想法,但互联网上的大多数问题都是关于在容器和主机之间使用D-Bus,而我只需要连接容器内运行的进程。到目前为止,我最成功的尝试都失败了,错误消息表明缺少与 X11 相关的内容,这是事实,因为此时我根本没有安装 X11。
我将在容器内运行并连接到的 D-Bus 服务示例:
#!/usr/bin/env python
import gobject
import dbus
import dbus.service
import dbus.mainloop.glib
import sys
service_name = "com.testservice"
object_path = "/testservice"
interface_name = service_name
class SomeObject(dbus.service.Object):
def __init__(self, bus, object_path):
dbus.service.Object.__init__(self, bus, object_path)
@dbus.service.method(service_name, in_signature='', out_signature='')
def Exit(self):
mainloop.quit()
if __name__ == '__main__':
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
name = dbus.service.BusName(service_name, session_bus)
object = SomeObject(session_bus, object_path)
mainloop = gobject.MainLoop()
mainloop.run()
目前,尝试启动该服务会给出以下输出:
Traceback (most recent call last):
File "/hostwork/dbus-test.py", line 35, in <module>
session_bus = dbus.SessionBus()
File "/usr/lib/python2.7/dist-packages/dbus/_dbus.py", line 211, in __new__
mainloop=mainloop)
File "/usr/lib/python2.7/dist-packages/dbus/_dbus.py", line 100, in __new__
bus = BusConnection.__new__(subclass, bus_type, mainloop=mainloop)
File "/usr/lib/python2.7/dist-packages/dbus/bus.py", line 122, in __new__
bus = cls._new_for_bus(address_or_type, mainloop=mainloop)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NotSupported: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
答案1
我自己找到了解决方案:
在我的 Dockerfile 中,我安装了 dbus 软件包,但没有与 X11 相关的内容。我还安装了我的软件的所有依赖项,包括我在问题中共享的 Python 脚本的依赖项。
在我的 Dockerfile 中,我有以下几行:
COPY start.sh /usr/local/bin
RUN chmod +x /usr/local/bin/start.sh
ENTRYPOINT ["/bin/bash", "/usr/local/bin/start.sh"]
start.sh的内容是这样的:
#!/usr/bin/env bash
export DBUS_SESSION_BUS_ADDRESS=`dbus-daemon --fork --config-file=/usr/share/dbus-1/session.conf --print-address`
exec bash
这样,运行容器就会为我提供一个适当设置了 DBUS_SESSION_BUS_ADDRESS 的 shell。我可以运行测试脚本后台并说
dbus-send --print-reply --session --dest=com.testservice /testservice com.testservice.Exit
杀死它。