如何将后台进程附加到 systemctl 服务的 CGroup

如何将后台进程附加到 systemctl 服务的 CGroup

让我再解释一下。我在 CentOS 7 上有一个服务,它启动了一个 sh 脚本。然后该脚本会分叉为其他 4 个子进程。如果一个进程挂了,我想从另一个服务启动它,但我希望它附加到其他 3 个进程的 CGroups。

因此,systemctl status myService 显示 4 个进程(在主脚本完成分叉为 4 个子进程之后)。然后,如果一个子进程被终止,systemctl status myService 只会显示 3 个进程进入 CGroup。那么,如何启动缺失的进程,然后将其附加到其他 3 个 CGroup,以便 systemctl status myService 再次显示 4 个子进程?

例子:

Active: active (running) CGroup: /system.slice/myService.service - 1234 process1 - 1235 process2 - 1237 process4

Active: active (running) CGroup: /system.slice/myService.service - 1234 process1 - 1235 process2 - 1236 process3 - 1237 process4 谢谢!

答案1

如果您cat "/proc/$pid/cgroup"在其中$pid表示属于的进程的 PID myService.service,您将看到类似的内容:

10:memory:/
9:blkio:/
8:pids:/system.slice/myService.service
7:perf_event:/
6:net_cls,net_prio:/
5:freezer:/
4:devices:/system.slice/myService.service
3:cpuset:/
2:cpu,cpuacct:/
1:name=systemd:/system.slice/myService.service

该条目name=systemd:/system.slice/myService.service至关重要。要将systemd另一个流程“同化”到服务中,您需要复制此条目。

通常会使用cgclassifycgexec。例如,这些可以正常工作:

cgexec -g memory:/ -g pids:/system.slice/myService.service sleep 60 &
cgclassify -g cpuset:/ "$pid"

但是我还没有找到让它工作的方法name=systemd:。以下命令在我的 Debian 9 中失败:

cgexec -g  name=systemd:/system.slice/myService.service sleep 60
cgexec -g  systemd:/system.slice/myService.service      sleep 60
cgexec -g '*systemd:/system.slice/myService.service'    sleep 60
cgexec -g '*:/system.slice/myService.service'           sleep 60

类似的尝试cgclassify(针对已启动的进程)也会失败。但是cgclassify您可以这样做:

回显“$pid”> /sys/fs/cgroup/systemd/system.slice/myService.service/tasks

或者如果你需要sudo

echo "$pid" | sudo tee /sys/fs/cgroup/systemd/system.slice/myService.service/tasks

此后,$pid将会在的输出中出现systemctl status myService.service并将systemd该过程视为服务的一部分(例如,如果您调用,它将终止它systemctl stop myService.service)。

为了模拟原始过程,您可能需要复制其他条目。例如,pids:/system.slice/myService.service以下两个命令中的任何一个都应该有效:

cgclassify -g pids:/system.slice/myService.service "$pid"
# or
echo "$pid" > /sys/fs/cgroup/pids/system.slice/myService.service/tasks

有时生成一个进程并稍后更改其 cgroup 可能不是最佳选择。您可能希望该进程开始在适当的 cgroups 中。通常你会用 来做这件事,cgexec但(如上所述)这似乎不适用于name=systemd:。可能的方法:

sh -c '
  echo "$$" > /sys/fs/cgroup/systemd/system.slice/myService.service/tasks || exit 1
  cgclassify -g cpuset:/ -g devices:/system.slice/myService.service "$$" || exit 1
  # add more -g arguments if you need
  exec your_command with arguments
'

诀窍在于当 shellexec连接到sleep它时,它已经在正确的 cgroups 中。或者甚至:

sh -c '
  echo "$$" > /sys/fs/cgroup/systemd/system.slice/myService.service/tasks || exit 1
  exec cgexec -g cpuset:/ -g devices:/system.slice/myService.service your_command with arguments
  # add more -g arguments if you need
'

在脚本中你可能想这样做:

nohup sh -c ' … ' &

相关内容