使用 `dockerd-rootless-setuptool.sh` 创建多租户环境
解读
面试官抛出此题,并非单纯考察一条命令的拼写,而是想验证候选人是否真正理解 “Rootless 模式” 在国内多租户场景下的落地边界与工程细节。国内企业内部常出现“一台高配物理机多部门共用”的诉求,却又受限于 等保 2.0 对容器运行用户的强制要求(禁止容器进程以宿主机 root 身份运行),因此 Rootless Docker 成为合规与隔离的折中方案。候选人必须说明:
- Rootless 的隔离强度到底在哪一层;
- 如何借助
dockerd-rootless-setuptool.sh完成 uidmap、subuid、subgid、fuse-overlayfs 等系统级依赖的自动化注入; - 多租户之间如何做到 “进程、网络、存储” 三维度的可见性隔离;
- 国内常见发行版(麒麟 V10、统信 UOS、CentOS 7.9)的内核与 systemd 版本缺口如何补齐;
- 最终交付物是一个 可脚本化、可审计、可回滚 的租户模板,而非简单地把 dockerd 跑起来。
知识点
- /etc/subuid、/etc/subgid 的映射规则与 65,536 个 UIDS 上限对大规模租户的扩容影响
- user_namespaces、mount_namespaces、network_namespaces 三件套在 Rootless 模式下的 capability 白名单
- fuse-overlayfs 对比原生 overlay2 的 5%~15% 性能衰减及国内云主机 IO 限速场景下的可接受阈值
- slirp4netns 与 vpnkit 两种用户态网络方案的 NAT 性能差异,以及在 阿里云、腾讯云 内网环境中最优 MTU 设置
- dockerd-rootless-setuptool.sh 生成的 systemd --user 单元文件如何与 堡垒机、JumpServer 的会话审计钩子对接
- 等保 2.0 控制点“容器运行时安全” 对非 root 启动容器的强制要求及测评机构现场核查方法
- 多租户 cgroups v2 的 subtree 委托机制,确保租户 A 无法在宿主机层面通过 --cgroup-parent 越权占用租户 B 的 CPU 池
- 镜像加速:国内使用
registry-mirrors指向 阿里云 ACR、DaoCloud 加速器 时,Rootless 模式下的证书信任链配置差异 - 故障排查:
docker info出现WARNING: No cpuset support时,如何确认宿主机是否已开启 cgroup v2 cpuset controller - 回滚策略:
dockerd-rootless-setuptool.sh uninstall不会自动清理/home/<tenant>/.local/share/docker,需手动写 systemd-tmpfiles 规则防止磁盘泄漏
答案
-
前置合规检查
- 内核 ≥ 5.2(麒麟 V10 SP2 需手动安装 kernel-ml 5.4)并开启 CONFIG_USER_NS;
- 系统级 shadow-utils 支持 65,536 长度 subuid;
- 关闭 selinux 或设置
setsebool -P container_use_cephfs on避免 overlayfs 拒绝挂载。
-
租户账号与映射
为每个租户创建独立 Linux 用户:useradd -m -s /bin/bash tenant01 echo "tenant01:200000:65536" >> /etc/subuid echo "tenant01:200000:65536" >> /etc/subgid注意起始 UID 必须跳开系统预留区间,国内等保测评要求审计员能直接
cat /etc/subuid读出映射关系。 -
依赖注入与一键初始化
切换到租户身份,执行官方脚本:su - tenant01 curl -fsSL https://get.docker.com/rootless | sh脚本内部会调用
dockerd-rootless-setuptool.sh install,自动完成:- 写入
$HOME/.config/systemd/user/docker.service - 加载 fuse-overlayfs 内核模块并设置
mountopt=metacopy=on降低元数据拷贝开销 - 生成
$HOME/.docker/config.json并注入国内镜像加速器地址,DaoCloud 加速器需额外写入registry-mirrors与insecure-registries白名单
- 写入
-
网络隔离加固
Rootless 默认使用 slirp4netns,NAT 性能瓶颈在 1 Gbps 左右;若租户需要 5 Gbps+ 内网吞吐,可让运维在宿主机预建 macvlan 子接口并授予租户CAP_NET_ADMIN:sudo ip link add macvlan0 link eth0 type macvlan mode bridge sudo ip link set macvlan0 netns $(pgrep -u tenant01 slirp4netns)同时通过 iptables-nft 在宿主机层面对
200000-265535的 uid map 出向流量做 QoS 限速,防止租户打满上联带宽。 -
存储配额与审计
利用 cgroup v2 的memory.max与io.max对$HOME/.local/share/docker挂载点做 subtree 委托:echo "+memory +io" | sudo tee /sys/fs/cgroup/tenant01/cgroup.subtree_control echo "8:16 wbps=104857600" | sudo tee /sys/fs/cgroup/tenant01/io.max通过 auditd 规则
-w /home/tenant01/.local/share/docker -p wa -k docker_rootless把镜像拉取、容器启动事件送到 JumpServer 的 syslog 审计中心,满足 等保 2.0 审计溯源 要求。 -
交付模板
将 2-5 步写成 Ansible Role,一键创建新租户:ansible-playbook -i inventory/tenant.yml rootless-docker.yml -e tenant_name=tenant02输出物包括:
- systemd --user 单元文件
- 预签名的 kubeconfig(若后续要接入 Rootless Kubernetes)
- 磁盘配额、网络限速、镜像加速 三份 conf 片段
交付后由 安全团队 运行cis-docker-rootless-benchmark扫描,得分 ≥ 90 方可上线。
拓展思考
- 如果租户需要 privileged 容器 跑自定义内核模块,Rootless 模式天然拒绝,此时应引导业务改用 sysbox 运行时,或直接在 Kata Containers 里起轻量虚拟机,而非放宽 user_namespace 映射。
- 国内部分 ARM64 服务器(鲲鹏 920)在 5.10 内核下存在 fuse-overlayfs 与 page cache 一致性 bug,表现为
docker build随机报file not found,需回退到 native overlay2 并开启 shiftfs 补丁,这就打破了纯 Rootless 的封闭性,面试时可作为“权衡案例”展示深度。 - 当 Rootless Docker 作为 CI 流水线 的执行器时,GitLab Runner 的
clone_url与docker.sock挂载模型需要改为DOCKER_HOST=unix:///home/gitlab-runner/.docker/run/docker.sock,同时把 cgroup v2 的cpu.max动态绑定到.gitlab-ci.yml的CPU_QUOTA变量,实现 秒级弹性限流,该方案已在 B 站、小红书 的 ARM 集群落地,可引用作为最佳实践。