如何在系统控制组之外启动一个进程

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

为了debugging的目的,更新过程只是睡觉,我发送杀手。

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 

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

UpdateSystem是一个bash脚本(虽然我可以很容易地把它做成一个C程序,如果这将有所帮助)。 从https://stackoverflow.com/a/29107686/771073获取守护进程代码后,有趣的是:

 ############################################# trap "echo Ignoring SIGTERM" SIGTERM sleep 10000 echo Awoken from sleep - presumably by the SIGTERM exit 0 

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

 Terminating Ignoring SIGTERM Awoken from sleep - presumably by the SIGTERM 

我真的想阻止SIGTERM被发送到sleep过程。

(其实,我真的想阻止它被发送到apt-get upgrade ,这是通过systemctl stop ttm.service的道德等价物来systemctl stop ttm.service ,而ExecStop被指定为/bin/kill $MAINPID – 以防万一,回答。)

这个问题是类似的,但接受的答案(使用KillMode=process )不适合我 – 我想杀死一些subprocess,而不是更新进程: 主进程启动时不能分离subprocess从systemd

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

 echo $$ > /sys/fs/cgroup/systemd/tasks 

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

你确定它不是systemd发送TERM信号到子进程吗?

根据服务类型的不同,如果你的主进程死了,systemd将会进行清理并终止同一个cgroup下的所有子进程。

这是由默认设置为控制组的KillMode =属性定义的。 您可以将其设置为“无”或“处理”。 https://www.freedesktop.org/software/systemd/man/systemd.kill.html

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

这虽然有一个皱纹。 该软件包安装ttm.servicettm.template.update.service 。 要运行更新程序,我们将ttm.template.update.service复制到ttm.update.service ,运行systemctl daemon-reload ,然后运行systemctl start ttm.update.service 。 为什么要复制? 因为更新程序安装新版本的ttm.template.update.service ,它将强制终止作为该服务运行的所有进程。 KillMode=None似乎提供了一个方法,但是,虽然它似乎工作,随后调用apt-get产生一个关于dpkg被中断的令人讨厌的错误。