在无头系统上启动共享会话 D-Bus 的 systemd 服务

Ole*_*olf 14 linux headless dbus systemd

我需要帮助在无头 Linux 系统上启动通过会话(不是系统)D-Bus 进行通信的服务。关键是没有人会登录无头系统。

到目前为止,我已经能够在三个不同的终端中代表未登录的用户(“其他用户”)启动 D-Bus 守护程序并测试 D-Bus 通信:

在第一个终端中,我为“otheruser”启动了一个 D-Bus 守护进程:

$ sudo -u otheruser dbus-daemon --session --print-address 1
unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48
Run Code Online (Sandbox Code Playgroud)

在第二个终端中,我使用上述 DBUS_SESSION_BUS_ADDRESS 响应启动 D-Bus 服务器应用程序:

$ sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" /usr/bin/my-dbus-service
Run Code Online (Sandbox Code Playgroud)

然后,在第三个终端中,我可以测试连接:

$ sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" gdbus introspect --session --dest com.mycompany.myappname --object-path /com/mycompany/interface
Run Code Online (Sandbox Code Playgroud)

但是,我想通过 systemd 启动 D-Bus 服务器应用程序以及一些客户端 D-Bus 服务。如何通过 systemd 启动 D-Bus 会话,以便将其 DBUS_SESSION_BUS_ADDRESS 环境变量传播到“otheruser”的 D-Bus 服务器和客户端服务?

一种可能的解决方案可能是将 dbus-daemon 的输出通过管道传输到“somefile”,然后在启动 D-Bus 服务器和客户端之前设置 DBUS_SESSION_BUS_ADDRESS=$(cat somefile)。这对我来说似乎有点太尴尬了;特别是因为我知道系统D-Bus 连接的 systemd 服务文件中的“Busname”指令有一些神奇之处。如何为“其他用户”正确启动 systemd 服务,以便这些 systemd 服务可以与会话 D-Bus 接口进行通信?

Kei*_*hel 21

您需要做几件事才能完成这项工作。

  1. 允许用户服务在引导时运行而无需用户登录(systemd linger)。
  2. 一个 systemd 套接字文件,用于指定 systemd 分配的 D-Bus 套接字。
  3. 用于启动 D-Bus 会话总线的 systemd 服务,然后为其他 systemd 服务设置 DBUS_SESSION_BUS_ADDRESS 环境变量。
  4. 确保您的 systemdmy-dbus-client.service文件属于Type=dbus或依赖于该dbus.socket单元,以确保它们分配 dbus 会话总线套接字并启动 dbus 会话服务(如果尚未启动)。

首先,要让给定用户的 Systemd 服务在引导时启动而无需登录,您需要启用 systemd 用户延迟 - 在配置为用户启用它时,这只需要以 root 身份完成一次:

# loginctl enable-linger otheruser
Run Code Online (Sandbox Code Playgroud)

接下来,如果您使用的是基于 Debian 的系统,对于接下来的两个步骤,您只需安装包 dbus-user-session 包:

# apt-get install dbus-user-session
Run Code Online (Sandbox Code Playgroud)

如果您正在使用其他发行版,想要手动执行此操作,或者只是想了解它是如何工作的,请继续。否则跳过的创建dbus.servicedbus.socket

使用以下内容创建文件/usr/lib/systemd/user/dbus.socket(注意,在某些发行版中,用户目录可能位于/lib而不是 下/usr/lib):

[Unit]
Description=D-Bus User Message Bus Socket

[Socket]
ListenStream=%t/bus
ExecStartPost=-/bin/systemctl --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus

[Install]
WantedBy=sockets.target
Also=dbus.service
Run Code Online (Sandbox Code Playgroud)

传播DBUS_SESSION_BUS_ADDRESS到所有服务,这是您的主要关注点,由ExecPostStart下面的行解决- 所有后续服务都将具有该设置。

%t被替换为XDG_RUNTIME_DIR-/run由 systemd 创建的临时目录,特定于用户会话,您可以填充文件。如果你想在其他地方创建这个套接字,你没有理由不能。只要确保它在某个地方是暂时的,或者在重新启动/会话拆卸时被清理干净。

我确实在尝试使 dbus unix 套接字成为抽象套接字时遇到了一些问题——由于某种原因,systemd 似乎不喜欢这种形式unix:abstract=@前缀。

现在创建/usr/lib/systemd/user/dbus.service具有以下内容的文件:

[Unit]
Description=D-Bus User Message Bus
Requires=dbus.socket

[Service]
ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig

[Install]
Also=dbus.socket
Run Code Online (Sandbox Code Playgroud)

systemd 在幕后进行了一些魔法,将已经创建的 unix 套接字传递给 dbus-daemon。Systemd 使用来自的信息dbus.socket来创建套接字,并且它的文件描述符在环境变量中设置,该变量LISTEN_FDS被传递到dbus-daemon. 上面列出的特殊选项使 dbus-daemon 使用传入的文件描述符而不是创建新的文件描述符。这允许 dbus 客户端与 dbus-daemon 并行启动,而不必担心套接字不存在。

最后,创建您自己的 systemd 用户服务,确保您将 type 设置为Type=dbus,设置BusName=为将由该服务注册的 dbus 服务名称之一的名称,或者确保Requires=dbus.socket在 Unit 部分中指定。下面是一个例子:

[Unit]
Description=Config Server Startup

[Service]
Type=dbus
BusName=com.example.app.configuree
ExecStart=/opt/example/app/configuration_server
Restart=on-failure

[Install]
WantedBy=default.target
Run Code Online (Sandbox Code Playgroud)

您可以将它们放在以下几个位置之一:- $HOME/.config/systemd/user -/usr/lib/systemd/user

启用您的服务systemctl --user enable <service name>并重新启动,一切都应该正常工作。


参考:

  • man loginctl 逗留
  • man pam_systemd XDG_RUNTIME_DIR 信息
  • man systemd.service 对于 Type=dbus、BusName= 和对 dbus.socket 的隐式依赖
  • man sd_listen_fds 有关 LISTEN_FDS 环境变量的信息
  • https://wiki.archlinux.org/index.php/Systemd/User - systemd 用户会话的一般信息

  • 这方面的文档有点少,而且很难将它们拼凑在一起。我很高兴它帮助了某人!也许将来它会再次帮助我。:D (2认同)