userns-remap是唯一能真正解耦容器内root与宿主机root权限的机制,需在daemon.json中配置"userns-remap":"default"并重启Docker服务,启用后容器UID 0映射至宿主机非特权UID(如100000),且绑定挂载前须同步调整宿主机目录属主为映射起始UID。

userns-remap 是唯一能真正解耦容器内 root 与宿主机 root 权限的机制,不启用它,容器里 UID 0 就等于宿主机 UID 0——这不是“隔离”,是裸奔。
启用 userns-remap 必须改 /etc/docker/daemon.json
别试 docker run --userns=auto 或命令行参数,Docker 1.12+ 已废弃运行时指定,只支持 daemon 级全局开关。
- 编辑
/etc/docker/daemon.json,加入"userns-remap": "default"(注意逗号,JSON 格式要合法) - 执行
sudo systemctl restart docker,否则配置不生效 - 验证是否成功:
docker info | grep "userns"应输出类似userns: default;再看Docker Root Dir路径末尾是否带数字(如/var/lib/docker/100000.100000),有则说明映射已激活
/etc/subuid 和 /etc/subgid 决定映射起点和范围
Docker 启用 userns-remap 后会自动创建用户 dockremap,并往 /etc/subuid 和 /etc/subgid 写入一行(如 dockremap:100000:65536)。这行的意思是:从宿主机 UID 100000 开始,分配连续 65536 个 ID 给容器内使用。
- 容器内 UID 0 → 宿主机 UID 100000
- 容器内 UID 1001 → 宿主机 UID 101001
- 容器内 GID 0 → 宿主机 GID 100000(同理)
- 若你手动指定
"userns-remap": "myuser",必须提前确保myuser在两个文件中都有对应条目,否则容器启动直接报错subuid range not found
绑定挂载(-v)前必须同步调整宿主机目录属主
这是最常踩坑的地方:容器内进程以映射后 UID 写文件,宿主机上对应路径的属主会变成 100000 这类数字 UID,而非人类可读用户名——导致你 ls -l 看到 100000:100000,且原用户无法读写。
- 挂载前先执行:
sudo chown -R 100000:100000 /host/path(数值需与/etc/subuid中起始值一致) - 若应用需访问宿主机
/etc/passwd或/var/run/docker.sock,不能直接挂载,得用--group-add或重映射 socket 所在组(如把docker组 GID 映射进容器) -
--privileged与userns-remap互斥,启用后者后所有--privileged容器启动失败,错误信息是privileged mode is incompatible with user namespaces
镜像内硬编码 UID 不会失效,但需注意偏移逻辑
很多基础镜像(如 nginx:alpine)用 USER 101 启动,这没问题——userns-remap 是整体偏移,101 会被映射为宿主机上的 100101,仍保持非 root 语义。
- 真正危险的是镜像里写死
chown 0:0 /tmp或chmod 777 /var/run这类操作,它们在容器内看似安全,实则对宿主机上100000范围内的文件生效 - 若应用必须用 root 启动(比如旧版 MySQL),不要禁用
userns-remap,而应检查它是否真需要宿主机级 root 权限;多数情况只需加--cap-add=CHOWN或--cap-add=SETUID即可满足需求
docker.sock 挂载变得极其危险——因为 socket 文件属组(通常是 docker)不会自动映射进容器,强行挂载会导致容器内进程无权通信,或更糟:你为了“修好”而把 socket 属组改成 100000,结果暴露了整个 Docker 引擎。


















