了解 systemd 的“Requires=”选项

joh*_*inp 6 systemd

systemd.unit(5),该选项Requires=意味着:

配置对其他单元的需求依赖。如果该单位被激活,此处列出的单位也将被激活。如果其他单元之一被停用或激活失败,则该单元将被停用。

我对此做了一个小实验。我创建了 2 个服务:a.serviceb.service

# cat a.service
[Service]
ExecStart=/bin/false

# cat b.service
[Unit]
Requires=a.service

[Service]
ExecStart=/bin/sleep 1000
Run Code Online (Sandbox Code Playgroud)

我做了之后

systemctl start b.service

我期望看到双方a.serviceb.service失败,因为a.service失败/bin/falseb.service失败,a.service失败。

但是,b.service正在运行:

root@john-ubuntu:/etc/systemd/system# systemctl status a.service b.service
? a.service
   Loaded: loaded (/etc/systemd/system/a.service; static; vendor preset: enabled)
   Active: failed (Result: exit-code) since Thu 2017-09-07 16:38:39 CST; 2s ago
  Process: 1245 ExecStart=/bin/false (code=exited, status=1/FAILURE)
 Main PID: 1245 (code=exited, status=1/FAILURE)

Sep 07 16:38:39 john-ubuntu systemd[1]: Started a.service.
Sep 07 16:38:39 john-ubuntu systemd[1]: a.service: Main process exited, code=exited, status=1/FAILURE
Sep 07 16:38:39 john-ubuntu systemd[1]: a.service: Unit entered failed state.
Sep 07 16:38:39 john-ubuntu systemd[1]: a.service: Failed with result 'exit-code'.

? b.service
   Loaded: loaded (/etc/systemd/system/b.service; static; vendor preset: enabled)
   Active: active (running) since Thu 2017-09-07 16:38:39 CST; 2s ago
 Main PID: 1244 (sleep)
    Tasks: 1
   Memory: 88.0K
      CPU: 696us
   CGroup: /system.slice/b.service
           ??1244 /bin/sleep 1000

Sep 07 16:38:39 john-ubuntu systemd[1]: Started b.service.
Run Code Online (Sandbox Code Playgroud)

我错过了什么?谢谢。

ger*_*che 3

这很棘手。需要理解的主要一点是,systemd 会并行启动所有事情,除非被告知不要这样做。这实际上在手册页的“要求”部分中有说明:

需求依赖性不影响服务启动或停止的顺序

你想要实现的是“在启动b.service之前等待a.service启动”。为此,您需要在 b.service 文件中添加“Requires”和“After”选项:

[Unit]
Requires=a.service
After=a.service

[Service]
ExecStart=/bin/sleep 1000
Run Code Online (Sandbox Code Playgroud)

= 更新 =

好的,我明白出了什么问题:在 a.service 文件中,您放置了 ExecStart 命令,但没有指定类型。这意味着类型将默认为“简单”。您需要“分叉”类型才能使其工作。来自 systemd.service 手册页:

如果设置为 simple(如果既没有指定 Type= 也没有指定 BusName=,但指定了 ExecStart=,则为默认值),则预计使用 ExecStart= 配置的进程是服务的主进程。在此模式下,如果进程向系统上的其他进程提供功能,则应在守护进程启动之前安装其通信通道(例如,由 systemd 通过套接字激活设置套接字),因为systemd 将立即开始后续操作单位

如果设置为 forking,则预计使用 ExecStart= 配置的进程将调用 fork() 作为其启动的一部分。当启动完成并且所有通信通道都建立后,父进程预计将退出。子进程继续作为主守护进程运行。这是传统 UNIX 守护程序的行为。如果使用此设置,建议同时使用 PIDFile= 选项,以便 systemd 可以识别守护进程的主进程。 一旦父进程退出,systemd 将继续启动后续单元。

因此,您应该更新 a.service 文件以包含“Type=Forking”:

[Service]
Type=forking
ExecStart=/bin/false
Run Code Online (Sandbox Code Playgroud)

这会起作用。:)