我systemd
目前正在从事服务工作。例如,当执行init 6
或reboot
或 时,所有服务进行的状态更改的顺序是什么?init 0
这是我产生这个问题的场景:
A
我有一项在关闭和重新启动时激活的服务。它的目的是调用从另一个服务 service 检索信息B
。B
意味着在启动时激活并连续运行。
当reboot
或init 0
被执行时,可以在哪个状态A
下找到B
?
我发现关于该主题的这段很有趣,但没有详细说明。
ActiveState 包含反映单元当前是否处于活动状态的状态值。当前定义了以下状态:活动、重新加载、非活动、失败、激活、停用。 active 表示该单元处于活动状态(显然......)。重新加载表示该单元处于活动状态并且当前正在重新加载其配置。 inactive 表示它处于非活动状态并且先前的运行已成功或尚未发生先前的运行。 failed 表示它处于非活动状态并且之前的运行不成功(有关此原因的更多信息可在单元类型特定接口上找到,例如 Result 属性中的服务,请参见下文)。激活表示该单元之前处于非活动状态,但当前正在进入活动状态。相反,停用表示该单元当前处于停用过程中。
答案1
在 systemd 设置中,reboot
、poweroff
和allhalt
都init N
转换为以下的各种子命令systemctl
。我systemctl
将从现在开始谈论。
那么,当您发出(例如)systemctl reboot
命令时会发生什么?除非polkit/logind 抽象层(当 root 权限可用时无论如何不会使用),此命令转换为systemctl isolate reboot.target
,而这又相当于systemctl start --job-mode=isolate reboot.target
。
用 systemd 的话说,“隔离”一个单元(无论是目标、服务还是其他任何东西)意味着启动(激活)给定单元及其所有依赖项,并停止(停用)所有其他单元,除非它们已IgnoreOnIsolate=yes
指定。因此,当您发出重新启动命令时,reboot.target
(及其依赖项)将排队等待启动,而所有其他单元则排队等待停止。
我们不会手动检查这些目标的依赖关系(尽管可以使用systemctl list-dependencies
命令)。让我们看看启动(7),一个手册页,描述了 systemd 控制的系统启动/关闭时发生的情况。
相应的 ASCII 图表复制粘贴到此处(FTR,它反映了 systemd 221)。
(conflicts with (conflicts with
all system all file system
services) mounts, swaps,
| cryptsetup
| devices, ...)
| |
v v
shutdown.target umount.target
| |
\_______ ______/
\ /
v
(various low-level
services)
|
v
final.target
|
_____________________________________/ \_________________________________
/ | | \
| | | |
v v v v
systemd-reboot.service systemd-poweroff.service systemd-halt.service systemd-kexec.service
| | | |
v v v v
reboot.target poweroff.target halt.target kexec.target
该计划非常不言自明。默认情况下,特殊shutdown.target
目标与所有服务单位冲突(除非它们已DefaultDependencies=no
设置)。
因此,第一种方法是使您的A
服务成为 的依赖项shutdown.target
,以便它在所有关闭时都会被激活。 (请注意,这也需要制作它DefaultDependencies=no
。)
然而,默认情况下,systemd 中的所有事情都是并行完成的,因此您的A
服务也需要进行排序B
- 延迟关闭,B
直到A
启动并完成其数据检索。在系统单元(5)我们可以读到:
如果一个单元与另一个单元有顺序依赖性,而后者在启动时被关闭,则关闭将在启动之前进行,无论顺序依赖性实际上是 After= 还是 Before= 类型。
这是不幸的:无论我们做AAfter=B.service
还是做Before=B.service
B,都会被阻止前A开始了。
所以,我们必须走另一条路。我们可以创建一个普通的 服务Type=oneshot
,它在激活时不执行任何操作 ( /bin/true
),但在停用时执行所需的任何操作。 (这也需要进行设置RemainsAfterExit=yes
,否则服务一旦/bin/true
退出就会自动标记为非活动状态。)可以根据B.service
需要订购此类服务:
请注意,当两个具有顺序依赖性的单元被关闭时,将应用启动顺序的相反顺序。即,如果一个单元在另一个单元上配置了 After=,则如果两个单元都关闭,则前者会先于后者停止。
将所有这些放在一起,一个单元文件A.service
将如下所示:
[Unit]
Description=Collect information about B
# we want to deactivate together with B
Requisite=B.service
# we want to deactivate before B deactivates
After=B.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/true
ExecStop=/path/to/B
[Install]
# replace with whatever is needed
WantedBy=B.service
另请注意,如果使用了最新(≥ 217)版本的 systemd,则ExecStart=/bin/true
可能被完全排除在外。
进一步阅读
- 系统(1)手册页,“概念”部分。
- 系统单元(5)手册页,“[Unit] 部分选项”部分。
- 启动(7)手册页。
- systemd.特殊(5)手册页。