使脚本在网络启动后执行?


102

我对systemd比较陌生,正在学习其体系结构。

现在,我正在尝试弄清楚如何使自定义外壳脚本运行。网络层启动,需要运行此脚本。

我正在运行Arch,同时使用systemd和netctl。

为了进行测试,我编写了一个简单的脚本,该脚本仅执行ip addr list > /tmp/ip.txt。我为此脚本创建了以下服务文件。

(/etc/systemd/system/test.service)
[Unit]
Description=test service

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

然后,我使用以下命令启用了脚本:

systemctl enable test

重新启动后,该脚本确实确实在运行,但是在网络启动之前运行。换句话说,中的输出ip.txt不显示分配给主接口的IPv4地址。在我登录时,确实已分配了IPv4地址,并且网络已建立。

我猜我可以通过弄乱WantedBy参数来更改脚本的运行点,但是我不确定如何做到这一点。

有人可以指出我正确的方向吗?

Answers:


126

在systemd网络配置依赖项上

影响systemd的单元订购非常容易。另一方面,您需要注意已完成的设备所能提供的保证。

配置服务

在当前系统上,订购后network.target仅能保证网络服务已启动,而不是有任何实际配置。您需要先订购network-online.target然后拉入以实现该目标。

[Unit]
Wants=network-online.target
After=network-online.target

为了与旧系统兼容,您可能还需要在network.target之后订购。

[Unit]
Wants=network-online.target
After=network.target network-online.target

这用于服务的单位文件和systemd。

在当前版本的软件中实施

现在,您需要确保它能network-online.target按预期运行(或至少可以使用network.target)。

当前版本的NetworkManager提供了NetworkManager-wait-online.servicenetwork-online.target因此可以通过您的服务获得。此特殊服务确保您的服务将等待,直到配置为自动启动的所有连接都成功,失败或超时。

当前版本的systemd-networkd会阻塞您的服务,直到按照要求配置了所有设备。更为容易的是,它目前仅支持在引导时(更具体地说是`systemd-networkd.service的启动时)应用的配置。

为了完整起见,/etc/init.d/networkFedora中的服务(由systemd的当前版本解释)会阻塞network.target,因此间接阻塞了network-online.target您的服务。这是基于脚本的实现的示例。

如果您的实现(无论是基于守护程序还是基于脚本)均表现为上述网络管理服务之一,则它将延迟服务的启动,直到网络配置成功完成,有充分的理由失败或在合理的时间后超时框架完成。

您可能要检查netctl是否以相同的方式工作,而该信息将是对该答案的宝贵补充。

旧版软件中的实现

我认为您不会在systemd的旧版本中无法正常工作。但是您可以检查至少network-online.target存在,并在之后进行排序network.target

以前,NetworkManager仅保证将应用至少一个连接。甚至为了使它起作用,您还必须NetworkManager-wait-online.service显式启用该功能。这个问题在Fedora中已得到修复,但直到最近才在上游应用。

systemctl enable NetworkManager-wait-online.service

有关network.target和network-online.target实现的说明

你不应该在任何时候需要让你的软件依赖于NetworkManager.serviceNetworkManager-wait-online.service或任何其他特定的服务。取而代之的是,所有网络管理服务应在订购之前network.target(可选)进行订购network-online.target

一个基于脚本的简单网络管理服务应在退出之前完成网络配置,并应在此之前network.target(因此间接在此之前)对其进行订购network-online.target

[Unit]
Before=network.target

[Service]
Type=oneshot
ExecStart=...
RemainAfterExit=yes

network.target即使不是很有用,基于守护程序的网络管理服务也应该先订购自己。

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

等待守护程序完成的服务应在特定服务之后和之前对其进行订购network-online.target。它应该Requisite在守护程序服务上使用,以便在不使用相应的网络管理服务的情况下立即失败。

[Unit]
Requisite=...
After=...
Before=network-online.target

[Service]
Type=oneshot
ExecStart=...
RemainAfterExit=yes

该软件包应在wants目录中的等待服务上安装一个符号链接,network-online.target以便希望等待已配置网络的服务将其引入。

ln -s /usr/lib/systemd/system/... /usr/lib/systemd/system/network-online.target.wants/

相关文件

最后的笔记

我希望我不仅可以在您提出问题时回答您的问题,而且还有助于改善上游和Linux发行版中的情况,以便现在我能提供比编写原始问题时更好的答案。 。


您是否通过“等待直到配置为自动启动的所有连接都成功”来表示自动连接选项?当我设置no-auto-default = *但在其中一个连接上具有autoconnect = yes时,可以利用此功能吗?最后一个问题-我不了解nm-online和手册页的--wait-for-startup选项没有太大帮助。感谢您的撰写,非常感谢!
lzap 2015年

据我所知,nm-online并不关心no-auto-default,仅auto。您有什么具体问题吗?在我看来,nm-online联机帮助页明确指出,-s它等待所有自动连接尝试,即连接或失败。
PavelŠimerda

在处理了一个小时的废话之后,我找到了解决方案:apt-get install sysv-init。:-) systemd取代了一些shell脚本而增加的复杂性令人难以置信。
某人

@Someone我担心在这种情况下initscripts不能解决问题。如果您使用的是NetworkManager或任何其他动态配置工具,则初始化脚本无法在完全配置的网络后对其进行排序。您可以使用/etc/init.d/network或类似方式来获得有限的动态配置,但这种配置无法普遍使用。
PavelŠimerda'16

@PavelŠimerdaInit会串行执行,并且在完成后续脚本需要依赖的操作之前,不会返回正确的init脚本。对于网络,这意味着已准备好所有适用的适配器。除非是幸运的时机,否则NM在此情况下表现良好。当然,真正的问题是NM重塑了网络处理方式,而不是在现有的简单,久经考验的结构上进行构建。桌面人员似乎对复杂性的危险一无所知。;-)
有人

9

您可以After[Unit]部分中使用来定义应在服务启动之前启动的服务。例如,如果您使用的是NetworkManager,则可以在启动NetworkManager之后启动服务。

[Unit]
Description=test service
After=NetworkManager.service

BindsTo在这里不太合适,因为该服务是一次性事件,而不是持久性服务(除非它还包括ExecStop在网络中断时触发的功能)。
goldilocks 2014年

删除BindsTo
人群

你可以添加的东西来替代BindsTo,但是,例如,Requires如果你只是想运行的服务,如果 NetworkManager的一样。 After实际上并没有做到这一点-它只是意味着,如果 NM也在运行,那么之后运行此。如果不打算运行NM,则该服务将在任意点运行。
goldilocks 2014年

4
After = network.target比After = NetworkManager.service更好,因为它更通用。
PavelŠimerda2014年

7
请注意,如果尚未启动,则指定After=foo不会导致该foo单元启动,如果它们同时启动,则只会告诉systemd如何订购它们。如果未启动,请同时使用After=fooWants=fooRequires=foo将具有拉入的效果foo,并且还可以使systemd正确订购这些单元。
Emil Lundberg 2014年

8

如果您的服务提供了一个服务器,该服务器可以被动地等待某人连接到它,请使用以下命令:

[Unit]
After=network.target

您的服务应绑定在通配符接口上。如果它使用套接字激活(推荐),或者它是仅限本地的,则可以完全忽略网络目标。

如果您的服务充当客户端,或者是对等的,则更合适:

[Unit]
After=network-online.target
Requires=network-online.target

systemd 213之前,network-online.target需要Pavel提到的解决方法(您需要手动启用将等待网络启动的服务)。从systemd 213开始,默认情况下会完成此操作。systemd-networkd-wait-online将等待至少一个地址(可路由或本地链接)在非环回接口上配置。

配置systemd-networkd,NetworkManager或同等功能是一项独立的任务。DHCP(用于IPv4)和NDP(用于IPv6)往往是开箱即用的,但是您应该对其进行配置,以使触发“网络正常”的精确定义network-online.target

说明文件:


很好奇为什么需要一个新的答案,而不仅仅是对现有的(希望)结构合理的答案进行小的改进。
PavelŠimerda2014年

前两个文档链接当前已失效。
彼得·汉森

为什么使用Requires而不是Want?
莫里森

4

我想我可以通过弄乱WantedBy参数来更改脚本的运行点

那会产生与您想要的相反的效果。来自man systemd.unit

WantedBy =,RequiredBy =

[...]通过systemctl enable安装每个列出的单元的.wants /或.requires /目录中会创建一个符号链接。这样的效果是将类型为Wants =或Requires =的依赖项列出的单元添加当前单元

基于此,我们可以看到正确的单位选项是“ Wants”或“ Requires”;根据这些说明,“要求”可能是正确的,加上“之后”以确保不仅可以运行网络服务,而且可以确保它在此单元之前运行。

单位选项AFAIK都不能包含已启动的前提条件必须已经完成或达到某个点(联网可能是守护程序服务)的规定,只能先启动。考虑到这一点,您可能希望制作脚本Type=forking并抛出正常的延迟(例如30秒),或某种包括延迟在内的成功退出循环,以确保首先拥有DHCP租约。


1
WantedBy和RequiredBy都不影响订购。
PavelŠimerda2014年

1
@PavelŠimerda:这里没有人声称他们这样做。排序是为什么我AfterRequires“确保网络服务不仅运行,而且在该单元之前运行” 一起明确提到的原因。
goldilocks 2014年

1
是的,After可以一起工作Wants或以Requires这种方式工作。另一方面,在基于依赖项的工具中,明确的延迟是个坏习惯,尤其是当有明确的方法要等到systemd文档指定网络配置后,因此,我不得不坚持不懈地投票。
PavelŠimerda2014年

3

After在该[Unit]部分中使用可以指定在您自己的服务之前应开始的操作。(以上大部分答案是正确的。)

要在网络启动后启动服务,请使用网络目标,无论您使用的是NetworkManager,Arch中的conf.d / netctl系统还是systemd知道的其他服务,都应使用网络目标。

[Unit]
#.....
After=network.target

简要查看将确认系统上依赖网络连接的所有其他服务都包含此指令。

它也可以移植到任何使用systemd的发行版中。对于Arch,Fedora,RHEL 7,Debian的未来版本,您的单位文件将相同。


服务,启动网络连接,如凯旋门的脚本,或者你自己的,应在指定所以自己的单元文件。

[Unit]
Wants=network.target
Before=network.target

我并不完全喜欢该Wants部分,因为它对其他软件包有副作用。请看看我的回答。
PavelŠimerda2014年

刚意识到Wantsnetwork.target这里是个好主意。
PavelŠimerda2014年

您确实要使用network-online.target。裁判
爱德华·托瓦尔兹

1

我想在本文中加一点。当前(2015年夏季)在RHEL7 / CentOS 7中,在建立IPv6网络之前错误地设置了network-online.target,因此具有

Wants=network-online.target
After=network-online.target

在其服务定义中也明确绑定到IPv6地址的服务可能会在IPv6启动并运行之前启动,从而导致它们失败。


我想只有基于内核的IPv6自动配置才是这种情况,但是还是有缺陷的。如果要在IPv6之后正确订购,则绝对应使用NetworkManager代替/etc/init.d/network。如果即使使用NM也遇到相同的问题,那么这是提交功能请求的一个很好的理由。我尚未与RHEL / CentOS核对过,如果您有兴趣,我可以为您提供详细信息。
PavelŠimerda'16

0
[Unit]
After=systemd-networkd.service

为我工作。


不确定在某些特殊情况下是否可以使用,但是出于几个原因它是错误的。其中之一是networkd提供自己的/ wait-online /服务。接单并订购network-online.target是支持该服务的任何正确方法。
PavelŠimerda'16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.