我正在尝试使用 systemd 管理 qemu。如果qemu崩溃了,它可以自动重启。我有以下单元文件:
[Unit]
Description=vm manager
After=network.target
Before=shutdown.target reboot.target poweroff.target halt.target
[Service]
Type=forking
ExecStart=/root/vm/vm-manager.sh start-vm
ExecStop=/root/vm/vm-manager.sh stop-vm
KillSignal=SIGCONT
PIDFile=/root/vm/run/pid
WatchdogSec=30s
Restart=on-failure
[Install]
WantedBy=multi-user.target
我没有在应用程序中调用 sd_notify(0, "WATCHDOG=1"),但服务在 30 秒后没有转入“失败”状态。我有两个问题:
- 在我看来,这个服务应该在30秒后重新启动,为什么它一直运行直到我杀死或停止它?
- 当我手动杀死qemu时(我将qemu进程作为主进程),服务立即重新启动,无需等待。
除了这两个问题之外,如果单元文件有什么错误或者建议,欢迎提出。
谢谢!
答案1
“守护进程”失败和“服务”处于失败状态之间是有区别的。
守护进程失败仅仅意味着程序是否以某种方式退出,而不是返回 0 作为退出代码。这就是Restart=on-failure
指“如果失败则重新启动守护进程”此外,您可以在其他条件下重新启动,请参阅下面的表格重新启动=这也解释了“失败”的确切含义。
根据您的服务文件,没有“服务”失败的定义,我认为默认定义基本上是“守护进程以某种方式退出,除了返回 0 作为退出代码并且当前没有运行”,但是您的服务文件有守护进程立即重新启动。所以它可能确实进入了“失败”状态,但时间很短,您没有注意到它。您可以使用 检查日志journalctl -u foo.service
。
另外,您应该检查主进程的 PID 是否仍然与 30 秒前相同。如果 PID 不同,则意味着 systemd 正在终止守护进程,因为它从未调用过sd_notify
,然后 systemd 会很快重新启动守护进程,因为您的服务文件说在失败时重新启动它,并且不会告诉它在重新启动之间等待(请参阅以下)。
如果您希望您的服务有失败的定义,您需要使用如下内容:
StartLimitInterval=5min
StartLimitBurst=4
这些选项都有详细记录这里,但是,在这个示例中,这两者的基本含义是“在 5 分钟的时间间隔内启动守护进程不超过 4 次。如果启动后失败,那么在该时间间隔内启动该守护进程的次数不超过 4 次,则认为该服务处于失败状态”。如果发生这种情况,则StartLimitAction=
采用,默认情况下为无。
另一个可配置值是RestartSec=
。来自文档:
配置重新启动服务之前的睡眠时间(使用 Restart= 配置)。采用以秒为单位的无单位值,或时间跨度值,例如“5min >20s”。默认为 100 毫秒。
这基本上意味着 systemd 至少必须等待RestartSec=
才能再次启动守护进程。
因此,您可以组合所有这些选项,但假设您使用这些值:
StartLimitInterval=5min
StartLimitBurst=4
RestartSec=2min
那么服务永远不会进入失败状态,因为失败的定义是:
如果在给定的 5 分钟间隔内,服务已启动,然后失败 4 次。
但 systemd 在上次失败后两分钟内不会重新启动服务,因此它永远不会StartLimitBurst
到达StartLimitInterval
.