我有一个如下的用户服务~/.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.target
。man 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
或其他方式建立连接,这都是有效的。