3

如何使用 systemd-run 创建临时 Cgroup 来限制ad-hoc(临时命令)的资源消耗

 1 year ago
source link: https://liruilongs.github.io/2022/10/29/%E5%BE%85%E5%8F%91%E5%B8%83/%E5%85%B3%E4%BA%8ELinux%E4%B8%AD%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8-systemd-run-cgroup-%E6%9D%A5%E9%99%90%E5%88%B6%E4%B8%B4%E6%97%B6%E5%91%BD%E4%BB%A4%E7%9A%84%E8%B5%84%E6%BA%90%E6%B6%88%E8%80%97/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如何使用 systemd-run 创建临时 Cgroup 来限制ad-hoc(临时命令)的资源消耗

地球上人的博爱将只可能以媚俗作态为基础——–《生命中不能承受之轻》


  • 分享一些临时命令资源限制的笔记
  • 博文内容涉及:
    • systemd-run 限制 ad-hoc 资源消耗基本原理
    • 前后台ad-hoc资源限制demo
  • 理解不足小伙伴帮忙指正

地球上人的博爱将只可能以媚俗作态为基础——–《生命中不能承受之轻》


通过 systemd-run 命令我们可以创建一个临时的cgroup并且可以在这个cgroup中运行临时命令。从而达到对资源的限制。

这里其实是把临时命令封装为一个service 或者 scope 单元(systemd 的资源单位类型为:service、scope、slice),然后单元放到了 创建的 cgroup层级下(slice)用于资源管理。

  • service : 一个或一组进程,由 systemd 依据单位配置文件启动。service 对指定进程进行封装,这样进程可以作为一个整体被启动或终止。
  • scope : 一组外部创建的进程。由强制进程通过 fork() 函数启动和终止、之后被 systemd 在运行时注册的进程,scope 会将其封装。例如:用户会话、 容器和虚拟机被认为是 scope。
  • slice : 一组按层级排列的单位。slice 并不包含进程,但会组建一个层级,并将 scope 和 service 都放置其中。真正的进程包含在 scope 或 service 中。在这一被划分层级的树中,每一个 slice 单位的名字对应通向层级中一个位置的路径。小横线(”-“)起分离路径组件的作用。

Servicescope 单元做资源限制,也就是我们的临时命令,是通过指定单元中的属性来实现的。通过 -p 来传递

systemd-run -p MemoryLimit=5M --unit=name --scope --slice=slice_name command

当指定为 scope 的时候,作为前台进程存在的。命令如果有输出,会直接打印出来,即换句话讲,它是同步的,直接从 systemd-run 进程中启动。

systemd-run -p MemoryLimit=5M --unit=name --slice=slice_name command

当不指定为 scope ,默认是作为 service 存在。即后台非同步启动进程。它们从 systemd 进程中被调用

  • --unit=name 为单元生成的名字
  • --slice=slice_name: 为生成的 cgroup 层级的名字

-p MemoryLimit=5M 即向对应单元传递一个内存限制的参数,它等价于下面的操作

# 如需使用命令列来限定 httpd.service 的 CPU 和内存占用量,请输入:
systemctl set-property httpd.service CPUShares=600 MemoryLimit=500M
# 如希望此更改为临时更改,请添加 --runtime 选项:
systemctl set-property --runtime httpd.service CPUShares=600 MemoryLimit=500M

其他的参数可以通过帮忙文档 查看 man systemd-run

因为是临时生成,所以 通过上面的方式生成的 单元文件,默认在 API文件系统 /run 下, 生命周期和临时的进程周期相同。

前台进程一种是需要设置 --scope,指定为一个scope资源,除非命令运行结束或者强制执行,否则会一直挂在前台

┌──[[email protected]]-[~]
└─$ systemd-run -p MemoryLimit=5M -p CPUShares=100 --unit=sleep-10 --scope --slice=test sleep 10
Running scope as unit sleep-10.scope.
┌──[[email protected]]-[~]
└─$

上面为 执行一个 sleep 10 的临时命令。对内存限制为5M。CPU限制为100m.,当前的 scope 资源单元为
sleep-10.scope. ,分配的 slice 为 test

上面 的命令会这10秒后结束 ,对应的他的单元文件也会随之消失

允许被运行的命令访问终端

另一种是通过-t 命令将当前 bash 放到 service 单元中,

以临时服务的方式运行 /bin/bash 命令, 并将其标准输入、标准输出、标准错误连接到当前的 TTY 设备上:

┌──[[email protected]]-[~]
└─$ systemd-run -p MemoryLimit=5M -p CPUShares=100 --unit=bash-limit --slice=bash-test -t /bin/bash
Running as unit bash-limit.service.
Press ^] three times within 1s to disconnect TTY.

在生成的 bash Service 中我们可以运行交互命令,查看当前 Service 的单元文件

┌──[[email protected]]-[/]
└─$ systemctl cat bash-limit.service
# /run/systemd/system/bash-limit.service
# Transient stub

# /run/systemd/system/bash-limit.service.d/50-CPUShares.conf
[Service]
CPUShares=100
# /run/systemd/system/bash-limit.service.d/50-Description.conf
[Unit]
Description=/bin/bash
# /run/systemd/system/bash-limit.service.d/50-Environment.conf
[Service]
Environment="TERM=xterm-256color"
# /run/systemd/system/bash-limit.service.d/50-ExecStart.conf
[Service]
ExecStart=
ExecStart=@/bin/bash "/bin/bash"
# /run/systemd/system/bash-limit.service.d/50-MemoryLimit.conf
[Service]
MemoryLimit=5242880
# /run/systemd/system/bash-limit.service.d/50-Slice.conf
[Service]
Slice=bash-test.slice
# /run/systemd/system/bash-limit.service.d/50-StandardError.conf
[Service]
StandardError=tty
# /run/systemd/system/bash-limit.service.d/50-StandardInput.conf
[Service]
StandardInput=tty
# /run/systemd/system/bash-limit.service.d/50-StandardOutput.conf
[Service]
StandardOutput=tty
# /run/systemd/system/bash-limit.service.d/50-TTYPath.conf
[Service]
TTYPath=/dev/pts/2

通过 systemctl status bash-limit.service 我们可以看到cgroup的相关信息

┌──[[email protected]]-[/]
└─$ systemctl status bash-limit.service
● bash-limit.service - /bin/bash
Loaded: loaded (/run/systemd/system/bash-limit.service; static; vendor preset: disabled)
Drop-In: /run/systemd/system/bash-limit.service.d
└─50-CPUShares.conf, 50-Description.conf, 50-Environment.conf, 50-ExecStart.conf, 50-MemoryLimit.conf, 50-Slice.conf, 50-StandardError.conf, 50-StandardInput.conf, 50-StandardOutput.conf, 50-TTYPath.conf
Active: active (running) since 六 2022-10-29 13:40:19 CST; 31s ago
Main PID: 136529 (bash)
Memory: 1.7M (limit: 5.0M)
CGroup: /bash.slice/bash-test.slice/bash-limit.service
├─136529 /bin/bash
└─136607 systemctl status bash-limit.service

10月 29 13:40:19 liruilongs.github.io systemd[1]: Started /bin/bash.
┌──[[email protected]]-[/]
└─$ bash
┌──[[email protected]]-[/]
└─$ bash
┌──[[email protected]]-[/]
└─$ systemctl status bash-limit.service
● bash-limit.service - /bin/bash
Loaded: loaded (/run/systemd/system/bash-limit.service; static; vendor preset: disabled)
Drop-In: /run/systemd/system/bash-limit.service.d
└─50-CPUShares.conf, 50-Description.conf, 50-Environment.conf, 50-ExecStart.conf, 50-MemoryLimit.conf, 50-Slice.conf, 50-StandardError.conf, 50-StandardInput.conf, 50-StandardOutput.conf, 50-TTYPath.conf
Active: active (running) since 六 2022-10-29 13:40:19 CST; 48s ago
Main PID: 136529 (bash)
Memory: 4.3M (limit: 5.0M)
CGroup: /bash.slice/bash-test.slice/bash-limit.service
├─136529 /bin/bash
├─136613 bash
├─136630 bash
└─136667 systemctl status bash-limit.service

10月 29 13:40:19 liruilongs.github.io systemd[1]: Started /bin/bash.

当单位被禁用并且其配置文件通过运行(下列行)被删除,永久 cgroup 会被释放:

┌──[[email protected]]-[/]
└─$ systemctl disable bash-limit.service --now
已终止

后台非守护进程

后台非守护进程不需要 --scope 参数,在后台执行,默认是一个 service

┌──[[email protected]]-[~]
└─$ systemd-run -p MemoryLimit=5M -p CPUShares=100 --unit=sleep-50 --slice=test sleep 50
Running as unit sleep-50.service.
┌──[[email protected]]-[~]
└─$

我们可以通过命令查看状态

┌──[[email protected]]-[~]
└─$ systemctl status sleep-50.service
● sleep-50.service - /usr/bin/sleep 50
Loaded: loaded (/run/systemd/system/sleep-50.service; static; vendor preset: disabled)
Drop-In: /run/systemd/system/sleep-50.service.d
└─50-CPUShares.conf, 50-Description.conf, 50-ExecStart.conf, 50-MemoryLimit.conf, 50-Slice.conf
Active: active (running) since 六 2022-10-29 01:29:29 CST; 10s ago
Main PID: 33234 (sleep)
Memory: 92.0K (limit: 5.0M)
CGroup: /test.slice/sleep-50.service
└─33234 /usr/bin/sleep 50

10月 29 01:29:29 liruilongs.github.io systemd[1]: Started /usr/bin/sleep 50.

通过 systemdctl cat 命令可以看到当前资源的配置文件,

┌──[[email protected]]-[~]
└─$ systemctl cat sleep-50.service
# /run/systemd/system/sleep-50.service
# Transient stub

# /run/systemd/system/sleep-50.service.d/50-CPUShares.conf
[Service]
CPUShares=100
# /run/systemd/system/sleep-50.service.d/50-Description.conf
[Unit]
Description=/usr/bin/sleep 50
# /run/systemd/system/sleep-50.service.d/50-ExecStart.conf
[Service]
ExecStart=
ExecStart=@/usr/bin/sleep "/usr/bin/sleep" "50"
# /run/systemd/system/sleep-50.service.d/50-MemoryLimit.conf
[Service]
MemoryLimit=5242880
# /run/systemd/system/sleep-50.service.d/50-Slice.conf
[Service]
Slice=test.slice

超过50秒。Service 正常退出

┌──[[email protected]]-[~]
└─$ systemctl status sleep-50.service
Unit sleep-50.service could not be found.
┌──[[email protected]]-[~]
└─$

后台守护进程

后台守护进程,需要一个一直运行的临时命令。不会死掉

┌──[[email protected]]-[~]
└─$ systemd-run -p MemoryLimit=5M -p CPUShares=100 --unit=top-print --slice=test top -b
┌──[[email protected]]-[~]
└─$ systemctl status top-print.service
● top-print.service - /usr/bin/top -b
Loaded: loaded (/run/systemd/system/top-print.service; static; vendor preset: disabled)
Drop-In: /run/systemd/system/top-print.service.d
└─50-CPUShares.conf, 50-Description.conf, 50-ExecStart.conf, 50-MemoryLimit.conf, 50-Slice.conf
Active: active (running) since 六 2022-10-29 00:48:54 CST; 1min 28s ago
Main PID: 27206 (top)
Memory: 824.0K (limit: 5.0M)
CGroup: /test.slice/top-print.service
└─27206 /usr/bin/top -b

10月 29 00:50:15 liruilongs.github.io top[27206]: 20108 etcd 20 0 57692 7352 4444 S...res
10月 29 00:50:15 liruilongs.github.io top[27206]: 21323 pcp 20 0 96024 4220 2592 S...ger
10月 29 00:50:15 liruilongs.github.io top[27206]: 22386 postfix 20 0 89892 4116 3092 S...kup
10月 29 00:50:15 liruilongs.github.io top[27206]: 23131 root 20 0 0 0 0 S.../5+
10月 29 00:50:15 liruilongs.github.io top[27206]: 23139 root 20 0 0 0 0 S.../0+
10月 29 00:50:15 liruilongs.github.io top[27206]: 23158 root 20 0 4492 644 560 S...lo+
10月 29 00:50:15 liruilongs.github.io top[27206]: 24193 etcd 20 0 60024 10420 5532 S...res
10月 29 00:50:15 liruilongs.github.io top[27206]: 24938 root 20 0 4364 360 292 S...eep
10月 29 00:50:15 liruilongs.github.io top[27206]: 25475 root 20 0 0 0 0 S.../2+
10月 29 00:50:15 liruilongs.github.io top[27206]: 25853 root 20 0 0 0 0 S.../1+
Hint: Some lines were ellipsized, use -l to show in full.

对应的资源文件

┌──[[email protected]]-[~]
└─$ systemctl cat top-print.service
# /run/systemd/system/top-print.service
# Transient stub

# /run/systemd/system/top-print.service.d/50-CPUShares.conf
[Service]
CPUShares=100
# /run/systemd/system/top-print.service.d/50-Description.conf
[Unit]
Description=/usr/bin/top -b
# /run/systemd/system/top-print.service.d/50-ExecStart.conf
[Service]
ExecStart=
ExecStart=@/usr/bin/top "/usr/bin/top" "-b"
# /run/systemd/system/top-print.service.d/50-MemoryLimit.conf
[Service]
MemoryLimit=5242880
# /run/systemd/system/top-print.service.d/50-Slice.conf
[Service]
Slice=test.slice

查看归属,不同的Service。但是在一个同一个slice

┌──[[email protected]]-[~]
└─$ systemd-cgls | head -n 7
├─1 /usr/lib/systemd/systemd --system --deserialize 13
├─test.slice
│ ├─sleep-50.service
│ │ └─67803 /usr/bin/sleep 50
│ └─top-print.service
│ └─27206 /usr/bin/top -b
├─docker

关于 如何使用 systemd-run 创建临时 Cgroup 来限制ad-hoc(临时命令)的资源消耗就和小伙伴分享到这里,更多参数特性请查看手册了解

man systemd-run | cat

博文引用资源

http://www.jinbuguo.com/systemd/systemd-run.html#

https://access.redhat.com/documentation/zh-cn/red_hat_enterprise_linux/7/html-single/resource_management_guide/index

https://liruilong.blog.csdn.net/article/details/120735766

https://liruilong.blog.csdn.net/article/details/123941400


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK