使用 `dockerd-rootless-setuptool.sh` 创建多租户环境

解读

面试官抛出此题,并非单纯考察一条命令的拼写,而是想验证候选人是否真正理解 “Rootless 模式” 在国内多租户场景下的落地边界与工程细节。国内企业内部常出现“一台高配物理机多部门共用”的诉求,却又受限于 等保 2.0 对容器运行用户的强制要求(禁止容器进程以宿主机 root 身份运行),因此 Rootless Docker 成为合规与隔离的折中方案。候选人必须说明:

  1. Rootless 的隔离强度到底在哪一层;
  2. 如何借助 dockerd-rootless-setuptool.sh 完成 uidmap、subuid、subgid、fuse-overlayfs 等系统级依赖的自动化注入;
  3. 多租户之间如何做到 “进程、网络、存储” 三维度的可见性隔离;
  4. 国内常见发行版(麒麟 V10、统信 UOS、CentOS 7.9)的内核与 systemd 版本缺口如何补齐;
  5. 最终交付物是一个 可脚本化、可审计、可回滚 的租户模板,而非简单地把 dockerd 跑起来。

知识点

  • /etc/subuid、/etc/subgid 的映射规则与 65,536 个 UIDS 上限对大规模租户的扩容影响
  • user_namespaces、mount_namespaces、network_namespaces 三件套在 Rootless 模式下的 capability 白名单
  • fuse-overlayfs 对比原生 overlay2 的 5%~15% 性能衰减及国内云主机 IO 限速场景下的可接受阈值
  • slirp4netnsvpnkit 两种用户态网络方案的 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 规则防止磁盘泄漏

答案

  1. 前置合规检查

    1. 内核 ≥ 5.2(麒麟 V10 SP2 需手动安装 kernel-ml 5.4)并开启 CONFIG_USER_NS;
    2. 系统级 shadow-utils 支持 65,536 长度 subuid;
    3. 关闭 selinux 或设置 setsebool -P container_use_cephfs on 避免 overlayfs 拒绝挂载。
  2. 租户账号与映射
    为每个租户创建独立 Linux 用户:

    useradd -m -s /bin/bash tenant01
    echo "tenant01:200000:65536" >> /etc/subuid
    echo "tenant01:200000:65536" >> /etc/subgid
    

    注意起始 UID 必须跳开系统预留区间,国内等保测评要求审计员能直接 cat /etc/subuid 读出映射关系。

  3. 依赖注入与一键初始化
    切换到租户身份,执行官方脚本:

    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-mirrorsinsecure-registries 白名单
  4. 网络隔离加固
    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 限速,防止租户打满上联带宽。

  5. 存储配额与审计
    利用 cgroup v2memory.maxio.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 审计溯源 要求。

  6. 交付模板
    将 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-overlayfspage cache 一致性 bug,表现为 docker build 随机报 file not found,需回退到 native overlay2 并开启 shiftfs 补丁,这就打破了纯 Rootless 的封闭性,面试时可作为“权衡案例”展示深度。
  • 当 Rootless Docker 作为 CI 流水线 的执行器时,GitLab Runnerclone_urldocker.sock 挂载模型需要改为 DOCKER_HOST=unix:///home/gitlab-runner/.docker/run/docker.sock,同时把 cgroup v2cpu.max 动态绑定到 .gitlab-ci.ymlCPU_QUOTA 变量,实现 秒级弹性限流,该方案已在 B 站、小红书 的 ARM 集群落地,可引用作为最佳实践。