我有一个一次性服务,可以调用 /usr/ 中的脚本
这是我的 .service 文件:
[Unit]
Description = Start apps
After = network.target
[Service]
Type=simple
ExecStart=/usr/start_apps.sh
[Install]
WantedBy=multi-user.target
我的脚本做了类似的事情:
cd /home/user/apps
# Run apps one at a time in background
./app1 &
./app2 &
现在,这似乎尝试运行这些应用程序,但当我这样做时,pgrep app
没有任何东西在运行。
所以,我认为这是因为服务已经结束。所以我尝试了一种不同的方法:
cd /home/user/apps
# Run app1 in back ground
./app1 &
# Run app2 in forground so the service does not stop
./app2
现在这可以工作了(pgrep 显示应用程序正在运行)-但是当我启动服务时它永远不会返回,我必须执行 ctrl+c,然后我可以返回到 bash 提示符并且应用程序都仍在运行。
我想要的是启动服务,运行两个应用程序,然后返回命令行,只需执行以下操作:
systemctl start my-service.service
做这个的最好方式是什么?
更新我正在像这样安装我的服务:
systemctl stop my-service.service
... copy the service/script files in place...
systemctl daemon-reload
systemctl enable my-service.service
systemctl start my-service.service
不确定...但它可能相关吗?
答案1
在后台启动所有进程应该可以,但是您需要使用Type=forking
并且您可能想要使用更多选项,特别RemainAfterExit=yes
是可能很重要。
该用例类似于rc.local
脚本的处理,它是在 systemd 中通过以下方式处理的:本单元模板,所以也许使用所有这些选项是一个好主意:
[Service]
Type=forking
ExecStart=/usr/start_apps.sh
TimeoutSec=0
RemainAfterExit=yes
GuessMainPID=no
我不知道为什么你会被阻止,并且在前台有最后一个进程的情况下必须按 Ctrl+C...你必须在命令systemctl start
本身上按 Ctrl+C 吗?我想说这有点奇怪...
请注意,以这种方式启动应用程序(其中许多在后台,从脚本)并不是 systemd 的真正用途,您将错过一些功能。例如systemctl stop
或systemctl restart
很可能在该设备上根本不起作用。
如今,在后台运行应用程序被视为一种“黑客行为”(不仅是 systemd,而且它的许多前身和大多数其他现代服务管理器也如此。)虽然 systemd 仍然能够做到这一点,但这种支持主要是为了向后兼容当存在更好的替代方案时不打算使用。
我的建议是为每个应用程序创建单独的服务,或者如果您要启动同一流程的多个实例,则可以使用模板单元。还要查看指令来指定单元之间的依赖关系,以便它们以正确的顺序启动和停止。特别是,看看PartOf=
指令,它允许您将一组服务作为一个单元进行管理,允许您使用单个命令来启动、停止或重新启动它们。
答案2
如果这些应用程序可能崩溃并且需要重新启动,或者如果它们需要单独停止或重新启动,请考虑检查主管控制。
您可以supervisorctl
从 systemd 作为一流的服务开始,然后能够让它启动任意数量的依赖进程并管理它们,为您提供一个启动或停止服务的地方 ( supervisorctl stop all
、supervisorctl start all
) 以及与 systemd ( supervisorctl status myapp
) 类似的审核功能。
Supervisorctl 的文档非常好,听起来您的用例可能是这样的,像您发布的那样,一个简单的 shell 脚本可能不足以在没有明显头痛的情况下完成此任务。