如何创建一个虚拟的 systemd 服务来一起停止/启动多个实例?

Mar*_*erg 13 ubuntu systemd

我计划为使用systemd. 我希望能够stopstart每个客户实例使用systemd,以及将整个客户实例集合视为可以一起停止和启动的单个服务。

systemd似乎提供了我需要使用的构建块PartOf和模板单元文件,但是我停止了父服务,子客户服务并未停止。如何使用 systemd 进行此操作?这是我到目前为止所拥有的。

父单元文件,app.service

[Unit]
Description=App Web Service

[Service]
# Don't run as a deamon (because we've got nothing to do directly)
Type=oneshot
# Just print something, because ExecStart is required
ExecStart=/bin/echo "App Service exists only to collectively start and stop App instances"
# Keep running after Exit start finished, because we want the instances that depend on this to keep running
RemainAfterExit=yes
StandardOutput=journal
Run Code Online (Sandbox Code Playgroud)

一个名为 的单元模板文件app@.service,用于创建客户实例:

[Unit]
Description=%I Instance of App Web Service

[Service]
PartOf=app.service
ExecStart=/home/mark/bin/app-poc.sh %i
StandardOutput=journal
Run Code Online (Sandbox Code Playgroud)

我的app-poc.sh脚本(只是循环打印到日志文件的概念证明):

#!/bin/bash
# Just a temporary code to fake a full daemon.
while :
do
  echo "The App PoC loop for $@"
  sleep 2;
done
Run Code Online (Sandbox Code Playgroud)

为了概念验证,我将 systemd 单元文件放在~/.config/systemd/user.

然后我启动了父级和一个基于模板的实例(之后systemctl --user daemon-reload):

systemctl --user start app
systemctl --user start app@customer.service
Run Code Online (Sandbox Code Playgroud)

从使用中journalctl -f我可以看到两者都已启动并且客户实例继续运行。现在我希望关闭父母会停止孩子(因为我使用了PartOf),但事实并非如此。此外,启动父项也不会按预期启动子项。

systemctl --user stop app
Run Code Online (Sandbox Code Playgroud)

谢谢!

(我使用 Ubuntu 16.04 和 systemd 229)。

Mar*_*erg 16

我了解到这就是 systemd“目标单位”的用途。通过使用目标单元,我可以获得我想要的好处,而无需创建[Service]我上面的虚假部分。一个工作示例“目标单元”文件如下所示:

# named like app.target
[Unit]
Description=App Web Service

# This collection of apps should be started at boot time.
[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)

然后每个客户实例都应该包含PartOf在该[Unit]部分中(如@meuh 所指出的),并且还应该有一个[Install]部分,以便enable并且disable将在特定服务上工作:

# In a file name like app@.service
[Unit]
Description=%I Instance of App Web Service
PartOf=app.target

[Service]
ExecStart=/home/mark/bin/app-poc.sh %i
Restart=on-failure
StandardOutput=journal

# When the service runs globally, make it run as a particular user for added security
#User=myapp
#Group=myapp

# When systemctl enable is used, make this start when the App service starts
[Install]
WantedBy=app.target
Run Code Online (Sandbox Code Playgroud)

要启动客户实例并在目标启动时启动它,请使用此一次性启用命令:

 systemctl enable app
Run Code Online (Sandbox Code Playgroud)

现在,我可以针对特定实例使用stopand starton app@customer,或者我可以使用start appandstop app一起停止所有应用程序。

  • 没那么简单。该脚本属于哪个数据包?每次添加新组件时都必须对其进行修改。忘记这一点,部署/维护就会陷入困境。我显然想要的是添加一个带有 partOf 设置的新数据包,表明它存在于该组中,然后_not_ 修改一些挥之不去的脚本。然后像以前一样停止和启动该目标。这有效,但状态似乎不在该范围内。我什至找不到一种方法来获取目标中存在的运行时单元列表。systemd 不涵盖此用例。 (2认同)
  • @TommiKyntola 这是一个 bash one-liner,您不需要随着目标依赖项的变化而更新:`systemctl status $(systemctl list-dependencies --plain otp.target)` (2认同)
  • @TommiKyntola 我同意 `systemd` 可以提高这里的可用性。我已经 [open a feature request](https://github.com/systemd/systemd/issues/9273) 建议改进目标的状态。 (2认同)

meu*_*euh 10

你需要移动线

PartOf=app.service
Run Code Online (Sandbox Code Playgroud)

[Service]和入[Unit]段,并添加到[Unit]app.service客户名单开始,如

Wants=app@customer1.service app@customer2.service
Run Code Online (Sandbox Code Playgroud)

或者正如 sourcejedi 在评论中所说,Requires=同样的事情。您可以保留PartOf不在上面列表中的手动启动的停止服务,例如systemctl --user start app@customer3.service.