(systemd 版本 229,仅供参考)
我有一个主服务 A 和一个辅助服务 B。主服务 A 可以自行运行。但服务 B 无法自行正确运行:它需要 A 运行(从技术上讲 B 可以运行,但我希望 systemd 阻止这种情况发生)。我的目标:如果 A 没有运行,B 也不应该运行。假设 A 和 B 正在运行,当 A 停止或死亡/崩溃时,B 也应该停止。
我如何实现这个目标?
我通过将 [Unit] 项目添加到 b.service 来接近,使用
Requisite=A.service
After=A.service
上述结果是
1) B won't start unless A is running (good).
2) B is stopped when A is stopped (good).
3) However, if I kill A, service B continues to run (bad).
我该如何修复最后的行为#3?我尝试使用 BindsTo 而不是 Requisite,就像在 B 的服务文件中这样:
BindsTo=A.service
After=A.service
我得到:
1) If A is not running and I start B, then A is also started
(I want an error, I don't want A started)
2) B is stopped when A is stopped (good).
3) B is stopped when A is killed (good)
所以现在 #3 不错,但 #1 不是所需的行为。PartOf 和 BindsTo 似乎都不能解决问题,但也许我没有正确使用选项组合?从手册页中我不清楚哪些选项可以组合。
使用 BindsTo 时,我还尝试使用 ExecStartPre 使 B 的启动失败,但这当然不起作用,因为在启动 B 之前,B 的启动已经确定它需要运行 A(并启动了它)。
有没有办法在 Requisite 和 BindsTo 之间获得行为?我上面列出的 1-2-3?
提前感谢!
答案1
我也在寻找更优雅的解决方案。这里有一个开放的 systemd 票证,用于请求增强:https://github.com/systemd/systemd/issues/5966
目前我的解决方法如下:B.service
Requisite=A.service
After=A.service
A.服务
OnFailure=Stop-B.service
停止-B.服务
[Service]
Type=oneshot
TimeoutSec=0
ExecStart=/bin/systemctl stop B.service
答案2
我遇到了类似的情况需要解决。我想到的方法是创建一个目标单元作为障碍两种服务之间。
a.服务:
[Unit]
Wants=a.target
目标:
[Unit]
Requisite=a.service
After=a.service
PartOf=a.service
RefuseManualStart=true
RefuseManualStop=true
b.服务:
[Unit]
BindsTo=a.target
After=a.target
此设置产生了 OP 所需的行为,因为 a.target 始终与 a.service 一起处于活动状态(当 a.service 停止时,PartOf 会停止 a.target,RefuseManual* 避免在 a.target 上执行 systemctl start/stop 命令),并且 b.service 无法通过 a.target 启动 a.service。
答案3
我采用了与 Chris 类似的方法,但不需要创建单独的服务来停止 B:
B.服务:
[Unit]
Requisite=A.service
After=A.service
A.服务:
[Service]
ExecStopPost=/bin/systemctl stop B.service
B.service 中的那一Requisite
行确保如果 A.service 尚未运行,则无法启动 B.service,而ExecStopPost
A.service 中的那一行确保当 A.service 停止或处于非活动状态时,B.service 也会停止。