工单标题写着 rootless,评论区却在争 --privileged 还能不能留。有人把这件事理解成「镜像里写个 USER 就行」,有人以为 rootless 一开,--privileged 也可以照旧。官方 Rootless mode 说的是:守护进程和容器都跑在用户命名空间里,daemon 本身也不用 root。这和「容器进程是不是 uid 0」不是同一层开关。
站里以前聊过:宿主机上的 www 用户迁进容器后,镜像没写 USER 时进程会变成 root——那是镜像内用户。这篇只谈 daemon 是不是 rootless。旧帖的站内编号这里不瞎链,避免链错。两件事可以一起做,但不能互相替代。
官方怎么定义 rootless
Rootless mode 写得很清楚:daemon 与容器在 user namespace 里跑。和 userns-remap 的差别是,后者 daemon 仍是 root,rootless 则两边都不是。满足前置条件时,安装阶段也可以不需要 root(要有 newuidmap / newgidmap,以及 /etc/subuid、/etc/subgid 里足够的从属 ID,文档示例是至少 65536 个)。装好后 docker info 的 Security Options 里应能看到 rootless。
包安装可用 dockerd-rootless-setuptool.sh install。没权限用包管理器时,官方提供 get.docker.com/rootless 脚本路径。引擎文档示例里的客户端版本号会随发行版变动,正文不钉死某个小版本。以你机器上 docker info 为准即可。
限制比口号长一截
Troubleshooting · Known limitations 列了常见边界,生产切不切之前先过一遍:
- 存储驱动只认有限几家:
overlay2(内核 5.11+)、fuse-overlayfs(4.18+ 且已装)、btrfs(有内核 / 挂载条件)、以及vfs。 - cgroup 相关的
--cpus/--memory/--pids-limit只有在 cgroup v2 + systemd 下才真正生效,否则这些旗标会被忽略。Tips · Limiting resources 写了委托 cpu/cpuset/io 等控制器的做法,以及没有 cgroup 时用ulimit/cpulimit的退路(粒度是进程级,容器里还能自行拆掉,只能当权宜)。 - AppArmor、Checkpoint、Overlay 网络、暴露 SCTP 端口:文档写明不支持。
ping、小于 1024 的特权端口要额外配(tips 里有ping_group_range、CAP_NET_BIND_SERVICE或ip_unprivileged_port_start)。docker inspect里的IPAddress在 RootlessKit 网络命名空间内,宿主机不能直接当可达地址用。-p默认还不传播源 IP(同页有开关说明)。- data-root 放 NFS 不行(这条不单是 rootless)。tips 也写数据目录默认在
~/.local/share/docker,别往 NFS 上甩。
网络侧 troubleshoot 还表列了 slirp4netns / pasta / gvisor-tap-vsock 等组合,吞吐和源 IP 行为不一样。业务强依赖 host 网络、overlay、或复杂 cgroup 限额时,先对照这张表,别假设和 rootful daemon 行为一字不差。Docker Engine v29.5 之前,--net=host 在 rootless 下端口可达性还有历史限制,文档 Historical limitations 一节写过,升级时单独核对。
还有一层容易混:镜像里写了非 root 的 USER,宿主机 daemon 仍可能是 rootful。反过来,daemon 已经 rootless,镜像却仍默认 uid 0,容器「里面」看起来还是 root,只是映射到宿主机上是普通用户的从属 UID。扫描项如果只查其一,会漏掉另一半。官方 rootless 页和 tips、troubleshoot 是一套文档,装完以后把 Known limitations 当验收清单勾一遍,比只看安装成功那几行 INFO 靠谱。
决策顺序:先 CI / 开发
更稳的顺序通常是:
- 开发机和 CI runner 先开 rootless,把构建、单测、组合编排跑通,把存储驱动和内核版本有没有落在支持列表里先验证掉。
- 需要限额就确认 cgroup v2 委托。
docker info里 Cgroup Driver 若是none,别指望--memory真生效。 - 业务容器继续避免
--privileged和无脑--cap-add。rootless 降低的是 daemon 被打穿后的宿主机损失面,不自动把「容器里还要特权」变成合理默认。--cap-add在 rootless 下也只作用于容器用户命名空间里的资源,文档写明对宿主初始命名空间那类能力帮不上忙。 - 生产再按网络插件、端口、监控能不能读懂 namespaced IP 做验收。过不了就留在 rootful + 镜像非 root + 少挂 docker.sock,而不是假装已经 rootless。
--privileged 和 rootless 解决的不是同一类问题。前者放大容器能力,后者收窄 daemon 身份。两边可以同时收紧,但不能互相替代。你们现网是已经在 CI 试过 rootless,还是扫描一催就想直接改生产 daemon?