使 systemd 用户服务依赖于系统目标

使 systemd 用户服务依赖于系统目标

我有一个如下的用户服务~/.config/systemd/user/example.service

[Unit]
Description=Example service
After=network.target

[Service]
ExecStart=/bin/bash -c 'host google.com > /var/tmp/example'

[Install]
WantedBy=default.target

我试图控制的实际服务实际上做了一些有用的事情并访问网络,当然;这只是一个简化的例子。

该服务通过创建指向的systemctl --user enable example.service符号链接来启用。~/.config/systemd/user/default.target.wants/example.service~/.config/systemd/user/example.service

使用此设置,并systemd按照建筑维基,服务在启动时以我的用户身份启动。但是,在设置网络后,它实际上并未启动;相反,它似乎立即启动,因为/var/tmp/example包含:

;; connection timed out; no servers could be reached

(并且我尝试控制的实际服务也无法访问网络,并且出现类似的名称查找错误)

这意味着服务实际上不会在 之后运行network.target。如何让它network.target在运行之前等待?

答案1

忘记了network.targetman systemd.special说:

network.target
       systemd automatically adds dependencies of type After for
       this target unit to all SysV init script service units
       with an LSB header referring to the $network facility.

所以,这个目标主要是 SysV 初始化脚本的兼容性黑客。

假设您的网络连接由 NetworkManager 处理,您当然可以依赖此目标,因为NetworkManager.service定义了Before=network.target。但这仅意味着 NetworkManager 已启动,而并不意味着网络连接已实际建立。这可能需要一段时间(dhcp 往返、wifi 握手等),并且完全是 NetworkManager 的工作。至少在我的系统 (F18) 上有一个名为 的服务。NetworkManager-wait-online它使用nm-online实用程序进行阻止,直到建立了活动连接。尝试Require, Before在您的 Unit 定义中这样做或单独使用该工具。

答案2

我遇到了同样的问题,用户空间备份脚本需要访问互联网。我通过添加以下内容解决了这个问题:~/.config/systemd/user/wait-for-network.service只需 ping 即可google.com,直到可以访问:

[Unit]
Description=Ping a server on the internet until it becomes reachable

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'while ! ping -c1 google.com; do sleep 1; done'
TimeoutStartSec=60s

然后我让我的备份脚本依赖它,如下所示:

[Unit]
Description=...
Requires=wait-for-network.service
After=wait-for-network.service

无论您使用NetworkManager或其他方式建立连接,这都是有效的。

相关内容