核心是让容器内UID 0(root)在宿主机上变成无特权普通UID(如100000),需配置daemon.json启用"userns-remap":"default"并重启Docker,自动创建dockremap用户及subuid/subgid映射,再同步挂载目录属主为映射起始UID,并配合Dockerfile中USER指令实现双重降权。

核心是让容器内 UID 0(root)在宿主机上变成一个无特权的普通数字,比如 100000。它在容器里仍是 root,能执行常规管理操作;但在宿主机上没有 root 权限,无法修改系统文件、加载内核模块或影响其他进程。
配置 Docker 守护进程启用映射
这是整个机制的起点,必须全局开启:
- 编辑 /etc/docker/daemon.json,加入:
{"userns-remap": "default"} - 保存后执行 sudo systemctl restart docker(注意:reload 不生效,必须完整重启)
- Docker 会自动创建系统用户 dockremap,并在 /etc/subuid 和 /etc/subgid 中分配一段子 ID 范围,例如:
dockremap:100000:65536
表示容器内 uid 0 → 宿主机 uid 100000,uid 1 → 100001,依此类推 - 若系统最小化导致自动创建失败,可手动添加:
sudo useradd -r -u 100000 dockremap
echo 'dockremap:100000:65536' | sudo tee -a /etc/subuid /etc/subgid
同步挂载目录的属主权限
User Namespace 启用后,容器内进程访问宿主机文件时,实际使用的是映射后的 UID/GID。如果挂载目录属主没对齐,就会出现 Permission denied:
- 查映射起始 UID:
awk -F':' '/dockremap/ {print $2}' /etc/subuid(通常为 100000) - 将绑定挂载的宿主机目录属主设为该 UID:
sudo chown -R 100000:100000 /host/data - 即使镜像中用了 USER 1001,该 UID 也会被整体偏移成 101001,不影响应用逻辑,但属主仍需按映射基址调整
验证映射效果与运行时行为
启用后,容器内外用户身份呈现“一致又不一致”的状态:
- 容器内执行 id -u 仍显示 0,说明它对自己仍是 root
- 回到宿主机执行 ps aux | grep yourcmd,对应进程 UID 已是 100000+,不再是 0
- 进入运行中容器,执行 capsh --print 可确认 capabilities 是否被合理裁剪(避免残留 CAP_SYS_ADMIN 等高危能力)
- 尝试 --privileged 或 --cap-add=CAP_SYS_ADMIN 会失败,因为这些操作要求真实 root 权限,与 UserNS 互斥
配合 Dockerfile 的 USER 指令做双重加固
UserNS 是运行时隔离,而 USER 是构建时加固,二者叠加更安全:
- 在 Dockerfile 中显式创建非 root 用户并切换:
RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -D appuser
USER appuser - 这样即使 UserNS 未启用,应用也已脱离 root 上下文;若已启用,UID 1001 还会被进一步偏移(如 101001),形成双重限制
- 注意:构建阶段(docker build)不运行在 UserNS 下,仅容器运行时生效


















