必须通过cgroup v2或systemd slice创建租户级控制组,使多个容器共享CPU/内存硬限额,防止抱团突破;推荐用tenant-a.slice定义CPUQuota=200%、MemoryMax=4G,并以--cgroup-parent=tenant-a.slice启动容器,再启用userns-remap加固权限。

要实现多租户环境下的计算资源强隔离,不能只靠单容器限流(如--cpus或--memory),必须从宿主机资源控制层入手,让多个容器归属同一租户级控制组,形成“硬性总量封顶”。Docker本身不直接管理租户粒度的配额,需借助cgroup v2或systemd slice机制协同实现。
用 systemd slice 统一管控租户资源
这是生产环境中最稳定、可持久化的方式。每个租户对应一个.slice单元,天然支持层级cgroup和资源继承:
- 在
/etc/systemd/system/tenant-a.slice中定义:[Slice] CPUQuota=200% MemoryMax=4G IOWeight=50
- 启用后所有绑定该 slice 的容器共享此配额,即使启动10个容器,总CPU也不超2核、内存不超4GB
- 启动容器时显式指定:
--cgroup-parent=tenant-a.slice
手动创建 cgroup v2 控制组(无 systemd 场景)
适用于轻量部署或容器运行时直连cgroup的环境(如containerd):
- 创建租户目录:
sudo mkdir -p /sys/fs/cgroup/tenant-b - 设总限额:
echo 150000 | sudo tee /sys/fs/cgroup/tenant-b/cpu.max(1.5核)、echo 2147483648 | sudo tee /sys/fs/cgroup/tenant-b/memory.max(2GB) - 容器启动时用
--cgroup-parent=/tenant-b挂入(注意路径前缀是否含/,取决于Docker版本)
结合用户命名空间加固权限边界
仅控资源不够,还需防越权操作。启用用户命名空间后,容器内root映射为宿主机普通UID,无法修改cgroup参数或访问其他租户进程:
- 配置Docker daemon启用重映射:
"userns-remap": "default"(写入/etc/docker/daemon.json) - 重启Docker:
sudo systemctl restart docker - 此时容器内
/proc、/sys/fs/cgroup等路径自动受限,租户无法逃逸篡改自身或他人cgroup设置
避免常见弱隔离陷阱
以下做法看似隔离,实则无法防止抱团突破:
- 对每个容器单独加
--cpus 1 --memory 2g:若租户启5个容器,理论可占5核+10GB,远超租户总配额 - 仅用网络命名空间或命名卷:解决数据和通信隔离,但CPU/内存仍全局竞争
- 未启用cgroup v2:v1中cpu、memory是分离子系统,无法做联合限额;v2统一控制器才支持
cpu.max + memory.max原子约束











