Linux cgroup 实现 SSH 用户资源与 GPU 访问限制

Linux cgroup 实现 SSH 用户资源与 GPU 访问限制

概述

在多用户共享的 Linux 服务器上,需要解决两个问题:

  1. 资源限制:防止单个用户过度占用 CPU、内存,影响其他用户
  2. GPU 隔离:普通用户不能直接访问 GPU,只能通过 Slurm 等调度系统申请使用

通过 systemd 的 slice 机制 + DevicePolicy,可以用极简的配置同时解决这两个问题。

原理

systemd 用户 slice 层级

用户通过 SSH 登录时,systemd 会自动为该用户创建 slice,层级如下:

1
2
3
4
5
user.slice
├── user-0.slice ← root 用户 (UID=0)
├── user-1003.slice ← 普通用户 (UID=1003)
├── user-1011.slice ← 普通用户 (UID=1011)
└── ...

关键机制是 模板继承user-.slice.d/ 中的配置会自动应用到所有 user-*.slice。而为特定 UID 创建的 user-0.slice.d/ 则可以覆盖模板配置,实现对 root 的豁免。

DevicePolicy 策略

策略 行为
auto 默认值,不限制设备访问
closed 只允许标准设备(/dev/null、/dev/tty 等),阻止 nvidia 等非标准设备
strict 仅允许 DeviceAllow 中显式列出的设备

closed 正好满足需求:普通用户的 SSH 会话看不到 GPU,但正常终端操作不受影响。

Slurm 作业不受影响

Slurm 作业运行在独立的 cgroup 中,由 Slurm 的 task/cgroup 插件管理设备权限。用户通过 srun/sbatch 提交的 GPU 作业不受 DevicePolicy=closed 限制,因为 Slurm 在作业 cgroup 中会放行分配到的 GPU 设备。

完整配置脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
# 1. 清理现有配置
sudo rm -rf /etc/systemd/system/user.slice.d/
sudo rm -rf /etc/systemd/system/user-*.slice.d/
sudo rm -rf /etc/systemd/system/user@.service.d/

# 2. 普通用户 slice:限制 CPU/内存 + DevicePolicy=closed 阻止 GPU 访问
# closed 策略允许标准设备(/dev/null, /dev/tty 等),
# 但禁止访问 GPU 设备(/dev/nvidia*),从而防止普通用户使用 GPU 资源。
sudo mkdir -p /etc/systemd/system/user-.slice.d

sudo tee /etc/systemd/system/user-.slice.d/limits.conf <<'EOF'
[Slice]
CPUQuota=200%
MemoryMax=8G
DevicePolicy=closed
EOF

# 给 root 的 slice 覆盖掉限制,DevicePolicy=auto 恢复 GPU 访问
sudo mkdir -p /etc/systemd/system/user-0.slice.d

sudo tee /etc/systemd/system/user-0.slice.d/override.conf <<'EOF'
[Slice]
CPUQuota=
MemoryMax=
DevicePolicy=auto
EOF

# 3. 重载配置
sudo systemctl daemon-reload
sudo systemctl restart systemd-logind

配置详解

1. 清理旧配置

删除所有残留的 slice 配置,确保干净的状态:

1
2
3
sudo rm -rf /etc/systemd/system/user.slice.d/
sudo rm -rf /etc/systemd/system/user-*.slice.d/
sudo rm -rf /etc/systemd/system/user@.service.d/

2. 普通用户模板 (user-.slice.d)

1
2
3
4
[Slice]
CPUQuota=200% # 最多使用 2 个 CPU 核心
MemoryMax=8G # 内存硬限制 8GB
DevicePolicy=closed # 阻止 GPU 等非标准设备访问
  • CPUQuota=200%:该用户所有进程合计最多占用 2 个 CPU 核心的算力
  • MemoryMax=8G:内存硬限制,超限触发 OOM Killer
  • DevicePolicy=closed:允许 /dev/null、/dev/tty 等标准设备,阻止 /dev/nvidia* 等 GPU 设备

3. root 豁免 (user-0.slice.d)

1
2
3
4
[Slice]
CPUQuota= # 空值 = 取消限制
MemoryMax= # 空值 = 取消限制
DevicePolicy=auto # 不限制设备访问

空值表示取消从模板继承的限制。root 用户不受任何约束。

4. 生效

1
2
sudo systemctl daemon-reload
sudo systemctl restart systemd-logind

注意restart systemd-logind 会断开所有 SSH 会话(包括当前的),请在 console 或 IPMI 上操作,或改用 sudo reboot 重启系统。

验证

检查用户的 cgroup 配置

1
2
3
# 查看某用户 slice 的 CPU 和内存限制
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/cpu.max
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/memory.max

验证 GPU 不可见(普通用户)

1
2
3
# 普通用户直接运行:
nvidia-smi
# 预期输出:Failed to initialize NVML: Unknown Error

验证 GPU 通过 Slurm 可用

1
2
3
# 通过 Slurm 申请 GPU 后可以正常使用:
srun --gres=gpu:V100:1 --mem=1G nvidia-smi
# 预期输出:正常显示 GPU 信息

查询用户 UID

slice 名称中的数字是 UID,可通过以下命令查询:

1
2
id hwen          # 输出: uid=1011(hwen) → 对应 user-1011.slice
getent passwd 1003 # 反向查询 UID 对应的用户名

注意事项

  1. Slurm 前提:需要 Slurm 配置 ConstrainDevices=yes(在 cgroup.conf 中),否则 Slurm 作业也无法访问 GPU
  2. 已有会话:配置生效后,已登录用户需要重新登录才会应用新限制
  3. 参数调整:CPUQuota 和 MemoryMax 根据实际硬件资源调整
  4. 持久化:配置写入 /etc/systemd/system,重启后自动生效

操作前请备份重要数据,建议在测试环境验证后再部署到生产系统。


Linux cgroup 实现 SSH 用户资源与 GPU 访问限制
https://zhazhajust.github.io/2025/12/21/linux-cgroup-ssh-limit/
作者
JayZz
发布于
2025年12月21日
许可协议