在 systemd 中,我需要设置一些服务,这些服务依赖于一个公共的“初始化”服务,这些服务必须在启动之前完成。此外,我想确保工作服务和“初始化”服务能够任何时候都不会同时运行:
manual
BOOT --. "restart svc" ---.
V V
svc-init |-----| |---------|
svc-a |--------------------------------| |----- - - -
svc-b |--------------------------------| |----- - - -
我想确保服务已“启用”(在系统启动时运行);此外,我希望能够在需要时随时手动重新启动整个系统。
我怎样才能做到这一点?
我尝试了包含如下重要字段的设置:
/etc/systemd/system/svc-init.service:
[Service] Type=oneshot ExecStart=/opt/svc/init-svc.sh [Install] WantedBy=multi-user.target
.../svc-a.服务,.../svc-b.服务:
[Unit] Wants=svc-init.service After=svc-init.service Conflicts=svc-init.service [Service] Restart=always ExecStart=/opt/svc/svc.sh [Install] WantedBy=multi-user.target
但是当我尝试运行它们时,它无法实现我想要的效果:
sudo systemctl start svc-init
- 它正确地停止了 svc-a 和 svc-b
- 但它没有开始svc-init 完成后再次执行 svc-a & svc-b
sudo systemctl start svc-a
- 它不会强制 svc-init 预先运行
sudo systemctl start svc-a svc-b svc-init
- 效果似乎与上面的 (1) 相同(即
... start svc-init
)
- 效果似乎与上面的 (1) 相同(即
sudo systemctl start svc-init svc-a svc-b
- 不运行 svc-init
- 印刷:
Job for svc-init.service canceled.
有什么神奇的 systemd 命令可以让系统按照我需要的方式运行?或者我应该以某种方式以不同的方式构建单元?
编辑:根据评论中的建议:澄清一下,在我看来,svc-a 和 svc-b 实际上是一个服务的实例,可能需要动态启动/停止(它们实际上是:svc@1
,,,等等)。svc@2
svc@3
答案1
Systemd 可能很难推理,但这似乎是一个值得尝试的好实验:
服务初始化
[Unit]
[email protected]
Before
告诉 systemd svc-init 需要先完成所有操作,然后才能启动任何命名服务。这应该会为您提供明确的必须完成顺序。
[电子邮件保护]
[Unit]
After=svc-init.service
BindsTo=svc-init.service
After
模仿Before
svc-init 服务中的,可能对您来说更方便。在两个地方声明它不是错误,也不是必需的。它只是明确了您的意图。
BindsTo
告诉 systemd,如果指定的服务因任何原因停止,则此服务也会停止。将其与After
或Before
声明一起使用可确保此停止以正确的顺序进行。根据您的需要,您可能希望使用Requires
而不是BindsTo
,因为Requires
表示仅当指定服务明确地已停止。如果BindsTo
使用,则每当svc-init
重新启动时,此服务也将重新启动。这两个版本都是Wants
您在例子中列出。
按照这样的配置,当svc-init
从停止状态启动时,它将等待svc
直到启动完成后才触发任何实例svc-init
(Before/After),并且只有在成功完成启动(BindsTo)后才会触发svc-init
。完成后,svc
将启动任何实例。如果svc-init
给定停止命令,所有svc
实例将同时停止svc-init
(BindsTo)。如果svc-init
给定重新开始命令后,svc-init 及其相关服务将停止然后启动。
如果svc-init
打算启动然后退出,您可能需要SuccessExitStatus=
在其Unit
部分中进行声明以告诉 systemd 在成功启动时需要哪些退出代码。
答案2
假设你不能摆脱脚本,让 systemd 自己完成所有的设置(你几乎肯定可以,但编写脚本的人可能不知道怎么做;向供应商/开发商大喊大叫,直到他们学会为止),我认为你应该只使用一为此的单元文件。
在单个单元文件中,你将在ExecStartPre=
选项。如果此处调用的程序无法成功退出,则单元将无法启动。例如,在[email protected]
:
[Service]
Restart=always
ExecStartPre=/opt/svc/init-svc.sh %I
ExecStart=/opt/svc/svc.sh %I
[Install]
WantedBy=multi-user.target