如何在Systemd控制组之外启动进程

Mar*_*ica 5 linux signals systemd

我有一个服务器进程(从systemd启动),可以启动更新进程。更新过程自我自我守护,然后(理论上)使用SIGTERM杀死服务器。我的问题是SIGTERM传播到更新过程,它是子进程。

出于调试目的,更新过程只是休眠,我手动发送了kill。

杀死之前的示例PS输出:

    1  1869  1869  1869 ?           -1 Ss       0   0:00 /usr/local/bin/state_controller --start
 1869  1873  1869  1869 ?           -1 Sl       0   0:00  \_ ProcessWebController --start
 1869  1886  1869  1869 ?           -1 Z        0   0:00  \_ [UpdateSystem] <defunct>
    1  1900  1900  1900 ?           -1 Ss       0   0:00 /bin/bash /usr/local/bin/UpdateSystem refork /var/ttm/update.bin
 1900  1905  1900  1900 ?           -1 S        0   0:00  \_ sleep 10000
Run Code Online (Sandbox Code Playgroud)

请注意,UpdateSystem在单独的PGID和TPGID中。(该<defunct>过程是守护进程的结果,而不是(我认为)问题。)

UpdateSystem是一个bash脚本(尽管如果有帮助的话,我可以轻松地使其成为C程序)。从/sf/answers/2037538051/获得的守护程序代码之后,有趣的是:

#############################################
trap "echo Ignoring SIGTERM" SIGTERM
sleep 10000
echo Awoken from sleep - presumably by the SIGTERM
exit 0
Run Code Online (Sandbox Code Playgroud)

当我kill 1869(将SIGTERM发送到state_controller服务器进程)时,我的日志文件包含:

Terminating
Ignoring SIGTERM
Awoken from sleep - presumably by the SIGTERM
Run Code Online (Sandbox Code Playgroud)

我真的想防止SIGTERM发送到该sleep进程。


(实际上,我真的想阻止它apt-get upgrade通过道德上等同于systemctl stop ttm.service和的ExecStop方式停止发送给该系统/bin/kill $MAINPID,以防万一更改任何人的答案。)

这个问题是相似的,但是可接受的答案(使用KillMode=process)对我来说效果不佳-我想杀死一些子进程,而不是更新进程: 从systemd启动主进程时无法分离子进程

tsa*_*ein 8

我们遇到了完全相同的问题。我们最终做的是使用 systemd-run 作为瞬态 cgroup启动更新过程:

systemd-run --unit=my_system_upgrade --scope --slice=my_system_upgrade_slice -E  setsid nohup start-the-upgrade &> /tmp/some-logs.log &
Run Code Online (Sandbox Code Playgroud)

这样,更新进程将在不同的 cgroup 中运行并且不会被终止。此外,我们使用setsid+nohup来确保进程有自己的组和会话,并且父进程是 init 进程。


Mar*_*ica 5

一种完全不同的方法是升级过程通过更新/sys/fs/cgroup/systemd文件系统将自身从服务组中删除。具体在 bash 中:

echo $$ > /sys/fs/cgroup/systemd/tasks
Run Code Online (Sandbox Code Playgroud)

一个进程恰好属于一个控制组。将其 PID 写入根tasks文件会将其添加到其他控制组,并将其从服务控制组中删除。


Mar*_*ica 3

我们决定采取的方法是在单独的(单次)服务中启动更新过程。因此,它自动属于一个单独的控制组,因此终止主服务并不会终止它。

但这有一个问题。该软件包安装ttm.servicettm.template.update.service. 要运行更新程序,我们复制ttm.template.update.servicettm.update.service,运行systemctl daemon-reload,然后运行systemctl start ttm.update.service​​。为什么是副本?因为当更新程序安装新版本的 时ttm.template.update.service,它将强制终止作为该服务运行的任何进程。 KillMode=None似乎提供了一种解决方法,但尽管它似乎有效,但随后对 apt-get 的调用会产生一个关于 dpkg 已被中断的令人讨厌的错误。