systemd-run --scope 可快速创建带资源限制的临时沙箱,支持 cpu、内存、进程数等 cgroup v2 限制,无需编写 service 文件,执行完自动清理。

可以使用 systemd-run 快速为临时脚本创建带资源限制的轻量级沙箱环境,无需写完整 service 文件。核心是通过 --scope 或 --scope --scope-property=xxx 组合参数,在 cgroup v2 下对 CPU、内存、IO、进程数等施加实时限制。
用 --scope 创建带资源限制的临时执行上下文
systemd-run --scope 会将命令放入一个新 scope 单元(如 run-rabc123.scope),该单元可被 systemd 管理并应用资源控制策略。与直接运行相比,它天然支持 cgroup v2 的细粒度限制,且退出后自动清理。
- 必须启用 cgroup v2(现代发行版默认开启;可通过
mount | grep cgroup确认挂载类型为cgroup2) - 普通用户需有
Delegate=yes权限(通常需在/etc/systemd/logind.conf中设置RestrictSessions=yes并重启systemd-logind;或直接用 root 执行) - scope 单元生命周期绑定于命令执行过程,不驻留,适合一次性任务
常用资源限制参数与示例
所有限制参数均以 --scope-property= 形式传入,对应 systemd resource control 属性名。注意:属性值语法严格,单位需明确(如 500M、2G、50%)。
-
CPU 限制:
--scope-property=CPUQuota=30%—— 限制最多使用 30% 的单核等效时间(即软上限,非硬隔离) -
内存上限:
--scope-property=MemoryMax=500M—— 超过时触发 OOM killer 杀掉该 scope 内任一进程 -
最大进程数:
--scope-property=TasksMax=20—— 防止 fork 炸弹类行为 -
IO 带宽限制(需 blkio controller 启用):
--scope-property=IOWeight=10(相对权重)或--scope-property=IOReadBandwidthMax="/dev/sda 10M" -
禁止网络访问(需 systemd v249+ & unshare support):
--scope-property=NetworkNamespacePath=/proc/self/ns/net --property=IPAddressDeny=any(更可靠方式是配合unshare -r -n封装)
组合使用 + 脚本封装技巧
直接运行复杂脚本时,建议用 sh -c 包裹,并确保路径、环境变量明确。若需读取当前 shell 环境,加 --scope-property=Environment="KEY=VAL" 显式传递。
- 示例:运行一个可能吃内存的 Python 脚本,限制 300MB 内存、2 个进程、CPU 不超 25%
systemd-run --scope \ --scope-property=MemoryMax=300M \ --scope-property=TasksMax=2 \ --scope-property=CPUQuota=25% \ --scope-property=WorkingDirectory=/tmp \ sh -c 'python3 /tmp/heavy_script.py > /tmp/out.log 2>&1'- 执行后立即返回 job ID 和 scope 名(如
Running as unit: run-rf8a2b3c.scope),可用systemctl status run-rf8a2b3c.scope查看实时资源使用(需systemd-cgtop或systemd-cgls辅助)
验证与调试要点
限制是否生效不能只看命令是否运行,要检查 cgroup 层面的实际约束。
- 查 scope 所属 cgroup 路径:
systemctl show run-*.scope -p ControlGroup - 查看内存限制是否写入:
cat /sys/fs/cgroup/$(systemctl show -p ControlGroup run-*.scope | cut -d= -f2)/memory.max - 监控实时用量:
systemd-cgtop -P(按 scope 分组)或systemd-cgls查层级 - 若限制未触发(如内存超限未 OOM),检查内核是否启用
CONFIG_MEMCG_KMEM,以及/proc/sys/vm/overcommit_memory是否为0或1











