【问题标题】:How to launch a process outside a systemd control group如何在 systemd 控制组之外启动进程
【发布时间】:2016-05-14 00:26:31
【问题描述】:

我有一个可以启动更新进程的服务器进程(从 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

请注意,UpdateSystem 位于单独的 PGID 和 TPGID 中。 (&lt;defunct&gt; 进程是守护进程的结果,并且(我认为)不是问题。)

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 的道德等价物来停止系统,ExecStop 被指定为/bin/kill $MAINPID - 以防万一这会改变任何人的答案。)

这个问题很相似,但接受的答案(使用KillMode=process)对我来说效果不佳 - 我想杀死一些子进程,而不是更新进程: Can't detach child process when main process is started from systemd

【问题讨论】:

    标签: linux signals systemd


    【解决方案1】:

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

    不过,这有一个问题。该软件包安装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 已被中断的严重错误。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 某些发行版已仅切换到 cgroupsv2。这些缺少tasks 文件,而应使用cgroup.procs。见man.archlinux.org/man/…
      【解决方案3】:

      您确定不是 systemd 向子进程发送 TERM 信号吗?

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

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

      【讨论】:

      • "我想杀死一些子进程,而不是更新进程"
      【解决方案4】:

      我和你有同样的情况。

      升级进程是父进程的子进程。父进程由服务调用。

      重点不是Cgroup,是MAINPID。

      如果使用PIDFILE来指定MAINPID,当service type=forking时,情况就解决了。

      [Service]
      Type=forking
      PIDFile=/run/test.pid
      

      【讨论】:

        【解决方案5】:

        我们遇到了完全相同的问题。我们最终以transient cgroup with systemd-run 身份启动更新过程:

        systemd-run --unit=my_system_upgrade --scope --slice=my_system_upgrade_slice -E  setsid nohup start-the-upgrade &> /tmp/some-logs.log &
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-08-21
          • 1970-01-01
          • 2020-11-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-19
          相关资源
          最近更新 更多