以用户身份运行 systemd 时出错 - 无法连接到总线:$DBUS_SESSION_BUS_ADDRESS 和 $XDG_RUNTIME_DIR 未定义

sal*_*lly 12 services systemd

我有一个以 root 身份运行的脚本,并尝试让它设置用户服务来运行 IPFS 守护进程。问题是我需要以用户身份而不是 root 身份启用该服务。它通常在重新启动后起作用,但我想如果可以的话避免这种情况。

服务脚本位于~/.config/systemd/user/ipfs.service

它包含了:

[Unit]
Description=IPFS daemon

[Service]
# Environment="IPFS_PATH=/data/ipfs"  # optional path to ipfs init directory if not default (\$HOME/.ipfs)
ExecStart=/usr/local/bin/ipfs daemon
Restart=on-failure

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

(我从这里获取了这段代码:https ://github.com/ipfs/go-ipfs/tree/master/misc )

如果我以用户身份运行这些命令,它可以正常工作:

systemctl --user enable ipfs
systemctl --user start ipfs
Run Code Online (Sandbox Code Playgroud)

问题是我的脚本以 root 身份运行,我不知道如何让它以用户身份运行。到目前为止我已经尝试过了:

    # Enable linger so IPFS can run at boot
    loginctl enable-linger $USER_ACCOUNT

    # Enable the service to run at boot
    sudo -u $USER_ACCOUNT systemctl --user enable ipfs

    # Start the service now
    sudo -u $USER_ACCOUNT systemctl --user start ipfs
Run Code Online (Sandbox Code Playgroud)

不幸的是,服务无法启动,当我收到此错误消息时:

无法连接到总线:$DBUS_SESSION_BUS_ADDRESS 和 $XDG_RUNTIME_DIR 未定义(考虑使用 --machine=@.host --user 连接到其他用户的总线)

一旦脚本完成并重新启动,服务就会正常启动,但我希望避免用户必须重新启动(如果可以的话)。任何帮助,将不胜感激。

Abd*_*ull 7

快速解决方案

假设someuser使用bash作为登录 shell,请将以下导出添加到~someuser/.profile[1]:

export XDG_RUNTIME_DIR="/run/user/$UID"
export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
Run Code Online (Sandbox Code Playgroud)

然后,具有 root/ sudo权限的用户可以someuser通过将命令包装为与 systemd交互runuser

sudo runuser someuser -l -c "systemctl --user enable ipfs"
sudo runuser someuser -l -c "systemctl --user start ipfs"
Run Code Online (Sandbox Code Playgroud)

runuser someuser -l -c "printenv"可以帮助对这些和其他导出的环境变量进行故障排除。


[1]:相反,将这些导出放入~someuser/.bashrc可能会无效,因为默认设置.bashrc通常设置为在检测到正在交互式运行时提前退出;请参阅https://unix.stackexchange.com/a/257613/20230

干净的解决方案

一般来说,设置XDG_RUNTIME_DIRDBUS_SESSION_BUS_ADDRESS手动/显式更像是一种解决方法;更好的方法是使用 user正确登录someuser正确登录将自动设置这些环境变量,并避免someuser原始用户的设置污染环境变量。

这种正确的登录可以通过命令完成machinectl,例如对于Ubuntu 22.04 LTS jammy可以通过 apt package 获得systemd-container

可用时machinectl,任何用户都可以正确someuser登录到其 shell,并正确设置所有环境变量:

sudo machinectl shell someuser@
Run Code Online (Sandbox Code Playgroud)

  • @william_grisaitis,到目前为止,“machinectl shell ...”是我发现“自动”初始化这些环境变量的唯一方法。https://unix.stackexchange.com/a/477049/20230 、 https://github.com/systemd/systemd/issues/825#issuecomment-127917622 和 https://www.reddit.com/r/linuxadmin /comments/rxrczr/in_interesting_tidbit_i_just_learned_about_the/ 提供了一些关于为什么 `su(do)` 不设置这些环境变量的基本原理的见解。归根结底是出于安全原因,因为“su”的历史目的、范围和意图对于 *systemd* 和其他人引入的现代概念来说已经变得过于模糊。 (2认同)

use*_*675 3

这些变量是用户特定的。它们是在用户登录时由 systemd 的用户实例设置的。如果您的脚本作为系统服务运行,那么它当然无法访问特定用户的此变量。

如果您使用systemctl --user --global enable,则将为所有用户启用该服务。

  • 有两个 systemd 进程。第一个作为 /sbin/init 运行并启动全局服务。第二个是在用户登录并启动用户服务时启动的。这里讨论的两个变量是由第二个进程设置的。 (3认同)

Cod*_*tan 1

我在 Ubuntu 22.04 LTS 上按照https://docs.docker.com/desktop/install/ubuntu/安装 docker-desktop 后遇到了这个问题。

以下解决了这个问题。首先检查“下载”目录中下载的 .deb 文件的权限,或者只是设置它:

sudo chmod 755 docker-desktop-<version>-<arch>.deb

接下来将您的用户添加到 docker 组:

sudo usermod -aG docker $USER

激活对组的更改:

newgrp docker

现在尝试执行命令来启动 docker-desktop:

systemctl --user start docker-desktop

要修复 docker-desktop 的 docker-hub 登录问题:

https://docs.docker.com/desktop/get-started/#credentials-management-for-linux-users

参考:https: //docs.docker.com/engine/install/linux-postinstall/