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


12

我计划为使用的客户托管同一个Web应用程序的多个实例systemd。我希望能够stop和使用start每个客户实例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

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

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

[Service]
PartOf=app.service
ExecStart=/home/mark/bin/app-poc.sh %i
StandardOutput=journal

我的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

为了进行概念验证,我在中获取了systemd单位文件~/.config/systemd/user

然后,我基于模板(在之后systemctl --user daemon-reload)启动父对象和实例:

systemctl --user start app
systemctl --user start app@customer.service

通过使用,journalctl -f我可以看到已经启动并且客户实例继续运行。现在,我希望关闭父母会停止孩子(因为我曾经使用过PartOf),但事实并非如此。另外,启动父级也不会像预期的那样启动子级。

systemctl --user stop app

谢谢!

(我正在将Ubuntu 16.04与systemd 229配合使用)。


1
“ PartOf =配置与Requires =类似的依赖关系,但仅限于停止和重新启动单元。” 如果您想开始工作,就不需要使用Requires=吗?
sourcejedi

Answers:


10

您需要移动线

PartOf=app.service

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

Wants=app@customer1.service app@customer2.service

或正如sourcejedi在评论中所说,Requires=也是一样。您可以保留PartOf上面列表中未列出的停止手动启动的服务systemctl --user start app@customer3.service


我确认你是对的PartOf。谢谢。我将通过符号链接来处理“需求”,这成为我使用systemd激活新客户所需执行的唯一操作。对于我的测试用例:`ln -s /home/mark/.config/systemd/user/app@.service / home / mark / .config / systemd / user / app.service.wants / unity @ foo.service`
马克·斯托斯伯格(Mark Stosberg)2016年

14

我了解到这是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

然后,每个客户的情况下应包括PartOf[Unit]部分(由@meuh指出的),也应该有一个[Install]让部分enabledisable具体的服务将工作:

# 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

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

 systemctl enable app

现在,在这一点上我可以使用stop,并startapp@customer为特定的实例,或者我可以使用start app,并stop app停止所有的应用程序一起。


地位如何?我找不到一种简单的方法来获取App想要的所有服务的状态。我知道如何编写脚本,但是……
Tommi Kyntola

1
我的意思是想获得该目标组中应用程序的状态,而不列出其中的所有内容(是否使用通配符),最好使用该组名,甚至不关心其组成。
Tommi Kyntola

2
这不是那么简单。该脚本属于哪个数据包?每次添加新组件时都必须对其进行修改。忘记了这一点,部署/维护就成了麻烦。我显然想要的只是添加一个带有partOf设置的新数据包,该数据包指示它存在于该组中,而不是修改一些缠绵的脚本。然后停止和启动该目标,就像以前一样。这行得通,但地位似乎不在该范围之内。我什至找不到一种方法来获取目标中存在的运行时单元的列表。此用例不在systemd涵盖范围内。
Tommi Kyntola

2
@TommiKyntola这是一个bash单行代码,您不需要在目标依赖项更改时进行更新:systemctl status $(systemctl list-dependencies --plain otp.target)
Mark Stosberg

2
@TommiKyntola我同意systemd可以改善此处的可用性。我已打开功能请求,以建议改善目标状态。
Mark Stosberg '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.