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

现在,我试图弄清楚如何使自定义shell脚本运行。该脚本需要在网络层启动后运行。

我正在运行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参数来更改脚本的运行点,但是我我不确定该怎么做。

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

评论

您也可以使用networkd-dispatcher

#1 楼

在systemd网络配置依赖性上

很容易影响systemd的单元顺序。另一方面,您需要注意完整设备的保证。

配置服务

在当前系统上,
network.target之后的订购仅保证网络服务已经启动,并不是说有一些实际配置。您需要在network-online.target之后订购并拉入以实现此目的。

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


为了与旧系统兼容,您可能还需要在network.target之后订购。 br />
[Unit]
Wants=network-online.target
After=network.target network-online.target


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

当前版本软件中的实现

现在,您需要确保network-online.target可以正常工作(或者至少可以使用network.target)。

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

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

为了完整起见,Fedora中的/etc/init.d/network服务,如当前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之前订购自己。 />
[Unit]
Before=network.target

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


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

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...



等待守护程序完成的服务应在特定服务之后和network-online.target之前订购自己。它应在守护程序服务上使用network.target,以便在未使用相应的网络管理服务的情况下立即失败。在network-online.target目录中等待Requisite的服务,以便希望等待已配置网络的服务将其拉入。

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

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


相关文档


http://www.freedesktop.org/software/systemd/man/systemd.special.html#network-online.target
http://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/

最后的笔记

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

评论


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

–lzap
2015年11月11日,12:33

据我所知,nm-online不在乎无自动默认设置,仅在乎自动设置。您有什么具体问题吗?在我看来,nm-online联机帮助页明确指出,使用-s会等待尝试进行所有自动连接,即连接或失败。

– PavelŠimerda
2015年11月11日14:39

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

– Mantriur
16-3-6在22:17



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

– PavelŠimerda
16 Mar 23 '16 at 21:30

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

– Mantriur
16 Mar 24 '16 at 15:21

#2 楼

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

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


评论


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

–金锁
14-4-22在18:23



删除BindsTo

–糟糕
2014年4月22日在18:24

如果您只想在NetworkManager运行服务时运行,则可以添加一些内容来替换BindsTo,例如Requires。之后实际上并没有执行此操作-仅表示NM是否也在运行,然后再运行。如果不打算运行NM,则该服务将在任意点运行。

–金锁
2014年4月22日在18:25



After = network.target比After = NetworkManager.service更好,因为它更通用。

– PavelŠimerda
2014年4月23日15:32

请注意,指定After = foo不会启动foo单元(如果尚未启动),它只会告诉systemd如果两个单元同时启动,则如何订购它们。如果没有启动,则同时使用After = foo和Wants = foo或Requires = foo将具有拉入foo的效果,并且还可以使systemd正确地对单元进行排序。

–埃米尔·伦德伯格(Emil Lundberg)
2014年8月12日在7:19

#3 楼

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

[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-networked,NetworkManager或等效功能是一项独立的任务。 DHCP(用于IPv4)和NDP(用于IPv6)往往开箱即用,但是您应该对其进行配置,以便您对“网络正常运行”的精确定义可以触发network-online.target

文档:


network.target
network-online.target
网络启动后运行服务


评论


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

– PavelŠimerda
2014-12-26 22:33

前两个文档链接当前已失效。

– Peter Hansen
15年3月2日在22:55

为什么使用Requires而不是Want?

–卡尔·莫里森(Karl Morrison)
17年8月9日在10:58

#4 楼


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


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


WantedBy =,RequiredBy =

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


基于此,我们可以看到正确的单位选项是“想要”还是“需要”;根据这些描述,“ Requires”可能是正确的,加上“ After”以确保不仅可以运行网络服务,而且可以确保它在此单元之前运行。

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

评论


WantedBy和RequiredBy都不影响订购。

– PavelŠimerda
2014年4月23日在15:31

@PavelŠimerda:这里没有人声称他们这样做。排序是为什么我与Requires一起明确提到After之后,“不仅确保运行网络服务,而且确保它在此单元之前运行”。

–金锁
2014年4月24日12:45



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

– PavelŠimerda
2014年12月16日在12:07

#5 楼

使用After部分中的[Unit]来指定在您自己的服务之前应启动的内容。 (以上大部分答案是正确的。)要在网络建立后启动服务,请使用网络目标,无论您使用的是conf.d / netctl系统中的NetworkManager,都应使用网络目标。 Arch或systemd知道的其他服务。

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


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

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


启动网络连接的服务(例如Arch的脚本或您自己的脚本)应请在各自的单位文件中指定。

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


评论


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

– PavelŠimerda
2014年4月23日在15:41

刚刚意识到,在network.target上旺旺是个好主意。

– PavelŠimerda
2014年4月23日在15:52

您确实要使用network-online.target。参考

–爱德华·托瓦尔兹
15年10月31日在15:31

#6 楼

我想在本文中加一点。当前(2015年夏季)在RHEL7 / CentOS 7中,在IPv6网络启动之前,network-online.target设置不正确,因此,在服务定义中具有
明确绑定到IPv6地址的操作可能会在IPv6启动并运行之前启动,从而导致它们失败。

评论


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

– PavelŠimerda
16年4月18日在18:21

#7 楼

[Unit]
After=systemd-networkd.service


为我工作。

评论


不确定在某些特殊情况下是否可以使用,但出于几个原因它是错误的。其中之一是联网提供了自己的/ wait-online /服务。在network-online.target之后引入和排序是支持该服务的任何正确方法。

– PavelŠimerda
16年4月18日在18:17