systemd Killmode:向子进程发送SIGTERM?

systemd Killmode:向子进程发送SIGTERM?

我正在尝试systemctl stop运行一些子命令的 shell 脚本。但是,由于 shell 脚本捕获了多个信号,因此脚本本身不会在 SIGTERM 上停止,并且 systemd 将在 90 秒的等待期后使用 SIGKILL 停止进程。我可以理解:trap只有在孩子退出后才执行。

现在我试图理解为什么systemctl stop不发送SIGTERM给孩子们。man systemd.kill告诉我该单元控制组中的所有剩余进程将在单元停止时被终止(对于服务:执行停止命令后,如 ExecStop= 配置)

我的问题的一个基本示例如下:一个 systemd 单元文件,我们称之为unitdemo

[Unit]
Description=test
After=graphical.target systemd-user-sessions.service

[Service]
User=ubuntu
WorkingDirectory=~

PAMName=login
UnsetEnvironment=TERM

StandardOutput=journal
ExecStart=/tmp/mainscript
Restart=always

[Install]
WantedBy=graphical.target

主要脚本:

#!/bin/bash
function trapme() {
echo SIGTERM sent to main script, trapped but exiting now...
exit 0
}
echo starting main script
trap trapme SIGTERM
echo now starting child script /tmp/childscript
/tmp/childscript
echo child script exited...

还有一个子脚本:

#!/bin/bash
function trapme() {
echo childscript has been killed by SIGTERM...
exit 0
}
trap trapme SIGTERM
while true; do sleep 1; done

发布systemctl stop unitdemo只会在 90 秒等待时间后停止,不会SIGTERM发送到 childscript - 日志中没有消息说“childscript 已被杀死......”。

编辑 man systemd.exec有更多信息。下面PAMName有一个条目讲述:

           Note that when this option is used for a unit it is very likely
           (depending on PAM configuration) that the main unit process will be
           migrated to its own session scope unit when it is activated. This
           process will hence be associated with two units: the unit it was
           originally started from (and for which PAMName= was configured),
           and the session scope unit. Any child processes of that process
           will however be associated with the session scope unit only.

这就解释了为什么孩子们没有收到SIGTERM.现在的问题是:如何终止这个会话?即我正在开始服务,但它变成了会议并且停止服务不会停止会话。

顺便说一句,我找到了通过使用来停止子脚本的方法

trap "kill \`cat $xkillerfile\`; ..... "
/tmp/childscript &
echo $! > $killerfile
wait

……但这样做感觉不对。当主进程停止时,有没有办法systemd停止会话中的 PID - 从而结束会话?如果是这样,怎么办?

答案1

如果 Systemd 单元具有以下设置,则会出现此行为

KillMode=mixed

或者

KillMode=process

这很奇怪,因为您在问题中显示的代码不包含这样的条目,默认值是

KillMode=control-group

不过,您可以将此默认设置添加到该[Service]部分。在执行此操作(以及显而易见的操作systemctl daemon-reload)之前,您可以检查此设置的状态:

systemctl show unitdemo | grep -i KillMode

相关内容