Systemd 和进程生成:当主进程退出时,子进程将被终止

Systemd 和进程生成:当主进程退出时,子进程将被终止

通常不会在这里发帖,但我正在为这个发帖。我有一个 Python 脚本,它在启动时会分叉,并负责启动一堆其他进程。该脚本过去是在启动时通过 启动的sysvinit,但最近我升级到 Debian Jessie,因此将其调整为通过 启动systemd

不幸的是,我遇到了一个无法解决的问题。当您直接在用户 shell 中启动脚本时,它会正确启动其子进程,并且当脚本退出时,子进程将被孤立并继续运行。

当通过 systemd 启动时,如果父进程退出,子进程也会退出(好吧,screen它们启动的 s 会死亡并显示为 Dead)。

理想情况下,我需要能够重新启动父脚本而不终止所有子进程,是否有我遗漏的东西?

谢谢!

[Unit]
Description=Server commander
After=network.target

[Service]
User=serveruser
Type=forking
PIDFile=/var/Server/Server.pid

ExecStart=/var/Server/Server.py
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

编辑:

对于我来说,指出 Python 脚本本质上是其子进程的“控制器”可能是相关的。它screen根据中央服务器的请求启动和停止 GNU 中的服务器。它通常始终运行,不会生成服务并退出。

然而,在某些情况下,我希望能够在不终止子进程的情况下重新加载脚本,即使这意味着进程被孤立到 pid 1。事实上,如果 Python 脚本以如下方式启动进程,那甚至都没有关系:父进程(如果可能的话)。

关于其工作原理的更好的解释:

  • systemd产生Server.py
  • Server.pyforks 并写入 pid 文件systemd
  • Server.py然后根据其指令在 gnu screen 中生成服务器进程
  • Server.py继续运行以执行服务器请求的任何重新启动

启动时没有 systemdServer.py可以重新启动并且它启动的GNUscreens不受影响。当使用 启动时systemd,当Server.py关闭时,这些屏幕进程不是被孤立到 pid 1,而是被杀死。

答案1

KillMode我设法通过设置为process而不是control-group(默认)来解决这个问题。谢谢大家!

答案2

我有一个 Python 脚本,它在启动时会分叉,并负责启动一堆其他进程。

这表明你做错了。稍后会详细介绍。

当脚本退出时,子进程将被孤立并继续运行。

这不是正确的守护进程行为。如果“主”进程(在本例中是您指定的子进程Type=forking)退出,systemd 会认为该服务已停用并终止任何其他仍在运行的进程(在控制组中)以进行清理。

有时,从 System 5 脚本到 systemd 的转换rc并不简单,因为在 systemd 下执行操作的正确方法有很大不同。在 systemd 中执行(例如)OpenVPN、OpenStack 或 OSSEC HIDS 的正确方法与使用脚本执行此操作不同rc。事实上,您有一个正在分叉的脚本,然后生成一整堆孙子进程,然后退出并期望这些孙子进程继续运行,这表明您正在犯下与 相同的恐怖行为ossec-control,尽管分叉的级别少了两个。如果您发现自己编写了一个“主”脚本来检查“启用”标志并为系统的“启用”部分运行子进程,那么您就犯了与可怕的ossec-control.

systemd 不需要这样的本土机制。它已经是服务经理。每https://unix.stackexchange.com/a/200365/5132,在 systemd 中解决此问题的正确方法不是让一项服务产生一些古怪且令人困惑的“子服务”尝试。它将每个子进程本身作为一个成熟的 systemd 服务。然后,使用正常的 systemd 控件启用和禁用、启动和停止系统的各个部分。正如您在 OSSEC HIDS 案例中所看到的,一个简单的模板服务单元几乎涵盖了所有内容(一个例外是 https://askubuntu.com/a/624871/43344)服务,允许人们做诸如启用可选服务之类的事情,而根本不需要 System 5 所需的可怕的“主脚本”机制。systemctl enable [email protected]agentlessdrc

在很多情况下,这种重新思考是必要的,也许不像 OSSEC HIDS 那么极端。像 exim 和 sendmail 这样的 MTS 就是其中的两个。人们可能有一个rc脚本来生成一个队列运行程序、一个 SMTP 提交守护进程和一个 SMTP 中继守护进程,并在配置文件中使用一堆临时 shell 变量来精确控制哪些运行。但使用 systemd 执行此操作的正确方法是三个适当的服务单位(其中两个已关联插座单元)并且根本没有临时的东西,只是服务管理器的常规机制。

答案3

你可以让父进程休眠,然后等待 systemd 在停止时间杀死它。

相关内容