我有一个临时案例,作为用户,我希望启动一些服务进程,并且能够将它们全部中断,以实现干净、轻松的启动停止。 “docker-compose up”的行为接近我想要的,所有 stdout/stderr feed 都到达我调用 shell 的 stdout/stderr,并且 sigint 一起关闭所有进程。
我尝试过supervisord和circus,但是两者都有点过于以生产为中心,需要解决方法来加入标准流,留在前台,通常表现得不像前台进程。我确信有不错的工具可以做到这一点,我已经看到它是在普通的外壳中完成的,我宁愿避免这种情况,但如果样板不是太极端的话,它是一个选择。
这个结果出现在谷歌“霸主”上https://github.com/dpedu/overlord其中谈到了同样的目标和麻烦,但我在这里没有看到任何程序
对于通用语言,假设我想运行 foo、bar 和 baz,合并它们的 stdout/error,然后休眠直到出现 sigint,该 sigint 应该向这三个程序中的每一个程序发送 sigint,然后等待每个程序退出。再说一遍,如果我必须在 shell 中执行此操作,那很好,但我真的很想了解开发人员流程组合工具(除了 docker-compose、docker、init 或以容器为中心的工具之外)是否有专为此类任务构建的工具
额外的奖励功能是保留 tty 信息,以便子进程可以启用自动颜色,但没什么大不了的
#!/bin/sh
./foo &
./bar &
./baz &
在写这篇文章时,我遇到了
https://github.com/Yelp/dumb-init
哑初始化实际上几乎正是我希望找到的,它已经打包在 debian 中,并且它的配置文件是一个轻量级 shell 文件
#!/usr/bin/dumb-init /bin/sh ./foo & # launch a process in the background ./bar & ./baz # launch another process in the foreground
答案1
哑初始化
https://github.com/Yelp/dumb-init
- 在 debian 中打包(apt install dump-init)
配置示例,创建“./start”并为其指定内容:
#!/usr/bin/dumb-init /bin/sh
./foo & # launch a process in the background
./bar &
./baz # launch another process in the foreground
不要忘记像平常一样使用 ^Cchmod +x ./start
运行/退出./start
答案2
您也许可以使用一个systemd
解决方案,其中foo.service
、bar.service
和baz.service
,全部由更大的事物启动super.service
并由同一事物停止。
这样做的一些优点:
- 您可以选择该组单元如何响应故障。
- 您不必为此专门设置一个终端窗口(您可以关闭终端而不影响进程)
- 可以保存日志记录,因此您可以使用工具来解析感兴趣的部分,而不是手动滚动终端。
它不会像您想要的那样将这些进程保留在前台,但除非这些进程是交互式进程,否则将它们保留在前台没有太大价值。
这是完成此操作的一组文件:
# ~/.config/systemd/user/super.service
[Unit]
Description=running everything
[Service]
Type=oneshot
ExecStart=/bin/true
RemainAfterExit=yes
--------------------------------------------
# ~/.config/systemd/user/foo.service
[Unit]
PartOf=super.service
[Service]
ExecStart=%h/bin/foo
[Install]
WantedBy=super.service
--------------------------------------------
# ~/.config/systemd/user/bar.service
[Unit]
PartOf=super.service
[Service]
ExecStart=%h/bin/bar
[Install]
WantedBy=super.service
--------------------------------------------
# ~/.config/systemd/user/baz.service
[Unit]
PartOf=super.service
[Service]
ExecStart=%h/bin/baz
[Install]
WantedBy=super.service
解释:
WantedBy=super.service
意味着什么时候super.service
开始,这也会开始。PartOf=super.service
意味着当super.service
停止时,这也会停止。
控制:
- 将每个单元添加到
super
组中systemctl --user enable foo bar baz
- 启动所有进程
systemctl --user start super
- 停止所有进程
systemctl --user stop super
- 使用以下命令在同一窗口中查看所有进程的标准输出
journalctl -u foo -u bar -u baz
:添加-f
以持续关注屏幕上的标准输出。
其他注意事项:
- 添加
KillSignal=SIGINT
到仅优雅停止的任何服务SIGINT
(否则他们会得到SIGTERM
) - 如果
foo
崩溃或无法启动,您可以强制其他进程停止。通过更改WantedBy=
为来做到这一点RequiredBy=
。如果无法启动,则会导致super.service
停止,从而导致停止。foo
bar
baz
- 您还可以添加
BindsTo=
关系以导致super.service
停止,如果foo
bar
或baz
因任何原因停止(例如自然结束或失败)。 - 使用的一个好处
journalctl
是它可以告诉您元数据,例如单元何时启动/停止以及哪个进程打印了消息。但是,如果您不喜欢此详细信息,请添加StandardOutput=append:%h/log
到每个[Service]
部分。这会将所有日志放入~/log
.然后您就可以tail -f ~/log
观看它。我认为这样做时颜色也可以得到更好的保留。
答案3
您提到您更喜欢避免使用 shell,但这正是 shell 的用途,不是吗?
在 bash 中,要启动许多后台进程,你只需这样做
./job1 & ./job2 & ./job3 &
向所有这些发送 INT 信号:
kill -INT $(jobs -p)
等待所有这些都完成:
wait
如果问题是您想要重复启动同一组作业,您可以设置
alias start="./job1 & ./job2 & ./job3 &"
alias stop='kill -INT $(jobs -p); wait'
然后,如果你想杀死他们,只需输入start
即可将他们全部解雇。stop