定义
无根容器指非特权用户无需 root 权限即可创建、运行和管理容器的能力[4]。这里的关键在于整条进程链都不依赖 root:守护进程若存在、容器运行时以及容器内的进程,三者都必须在无特权状态下工作;仅仅把非 root 用户加入 docker 用户组,或者为守护进程启用用户命名空间重映射,都不构成真正的无根方案,因为底层守护进程仍然以 root 身份运行[1]。
它不同于在容器内以普通用户身份运行程序的做法。以 Docker 的 --user 参数或配置文件中的 USER 指令降低容器内进程权限时,容器引擎与运行时本身仍以 root 运行,宿主机上的攻击面并未减少[4]。
原理
无根容器的关键机制是 Linux 用户命名空间。用户命名空间允许进程在容器外部拥有普通的非特权用户标识,同时在命名空间内部持有用户标识 0,即所谓的 root,并具备该命名空间内近乎完整的权能[1]。这种映射关系可以写成如下形式:
$$
\text{容器内 UID } 0 \longrightarrow \text{宿主机 UID } 1000 \
\text{容器内 UID } 1..65536 \longrightarrow \text{宿主机子 UID 区间}
$$
映射由用户命名空间内核设施维护,记录在 /proc/[pid]/uid_map 与 /proc/[pid]/gid_map 中。普通用户直接写入这些文件时受内核严格限制,只能映射一个用户标识,且宿主机标识必须与写入进程的有效标识一致[1]。
要实现多用户映射,通常借助 shadow-utils 提供的 newuidmap 与 newgidmap 这两个 setuid 辅助程序,它们按 /etc/subuid 和 /etc/subgid 中管理员预先分配的区间代写映射表[4]。在单映射模式下,工具链不需要这两个 setuid 程序,代价是命名空间内只有一个可用的用户标识,无法解压包含多种属主的常规镜像[1]。
网络方面,非特权用户无法创建 veth 与网桥对,也无法直接操作宿主机 iptables,因此无根方案普遍改用用户态网络栈。slirp4netns 是最广泛采用的驱动,它基于 QEMU 的 Slirp 实现,通过 TAP 设备与文件描述符传递在命名空间之间转发数据包,另有实验性的 bypass4netns 提供更高性能[5]。存储方面,OverlayFS 在用户命名空间中长期不可用,实践中改用 FUSE-OverlayFS 或 XFS 重链接实现镜像层[6]。
flowchart LR
A[普通用户进程] --> B[RootlessKit 建立用户命名空间]
B --> C[映射 UID/GID 与子 UID 区间]
C --> D[建立网络命名空间]
D --> E[slirp4netns 用户态网络]
C --> F[FUSE-OverlayFS 存储]
E --> G[容器进程以 UID 0 运行]
F --> G
发展历程
用户命名空间早在 2008 年前后即已进入 Linux 内核主线,为后来把 root 权限限制在命名空间内部提供了基础。2013 年 Docker 发布,最初基于 LXC,2014 年改用自研的 libcontainer。这一时期的容器工具普遍以 root 权限运行后台守护进程,高性能计算中心等多用户环境因此对其持谨慎态度[2]。
无根容器生态的成型与非特权构建工具的发展同步。Charliecloud 由 洛斯阿拉莫斯国家实验室 团队开发,采用用户命名空间运行容器,不依赖任何特权操作或守护进程,全程不使用 root、sudo 以及 setuid 或 setcap 辅助程序[7]。该项目的首次无特权运行与构建在业界属于较早的实践,相关论文发表于 2017 年[7]。
2018 年前后,RootlessKit 等以 fake root 为核心的实现出现,它基于用户命名空间在用户、挂载与网络三个维度上编排命名空间,并与 newuidmap、newgidmap 及子标识配置对接[8]。同一时期,Kubernetes 社区推进将整个控制平面以非 root 方式运行,2018 年出现了名为 Usernetes 的无根 Kubernetes 概念验证,随后相关提案演化为 KEP-2033[9]。
Podman 由 红帽公司 主导开发,从设计上即把无根运行作为默认取向,并取消了常驻守护进程,容器进程直接作为调用用户的子进程存在[2]。Docker 随后也提供了无根模式,将守护进程本身放入按用户划分的命名空间中[10]。至 2020 年代中期,无根架构已被用于把 AI 智能体 运行环境封装进容器的方案中,以限制宿主系统权限被滥用[11]。
应用
高性能计算是多用户共享场景中最直接的应用领域。Charliecloud 等实现面向 HPC 应用提供轻量级、完全无特权的软件栈,使科研人员能在不修改中心资源配置的前提下打包与复现计算环境[12]。
在云原生与开发环境中,无根模式用于在共享主机上安全运行容器编排组件。Kubernetes 的无根方案通过 RootlessKit 以非 root 身份运行 kubelet、kube-proxy 以及容器网络接口守护进程,从而在出现容器逃逸时限制影响范围[9]。开发平台方面,也有把容器运行时以无根方式嵌入工作空间的实践,以便在无 sudo 权限的托管环境中提供容器能力[13]。
桌面与工具链同样受益。bubblewrap 利用用户命名空间加载非特权容器,用于沙箱化半可信应用,例如 Flatpak 应用、图像或视频缩略图生成器以及浏览器组件,也可用于在不同库栈或不同发行版版本中运行程序。
安全基准文件亦把无根运行列为推荐配置,认为它消除了以 root 运行守护进程以及随意把用户加入 docker 用户组所带来的提权通路。
局限
无根容器并不构成完整的隔离边界。容器仍与宿主机共享内核,内核级别的漏洞,例如用户命名空间相关的提权缺陷,依然可能穿透命名空间;它缩小的是默认攻击面,不能替代 seccomp、AppArmor 或 SELinux 等强制访问控制配置。即使在无根环境中,容器内进程若仍以命名空间内的 UID 0 运行,其在该命名空间内拥有的权能仍多于一个已正确降权的进程。
权限配置与子标识管理带来运维负担。无根运行依赖 /etc/subuid 与 /etc/subgid 中为各用户划分的不重叠区间,区间重叠会破坏同一主机上不同用户之间的隔离;在 LDAP 或活动目录等集中账户体系下维护这些区间更为困难[6]。用于写入映射的 newuidmap 与 newgidmap 属于 setuid 程序,本身曾出现整数溢出与附加组标识相关漏洞[6]。
功能与性能存在取舍。无根进程无法直接绑定 1024 以下的特权端口,需要借助权能委派或反向代理。用户态网络栈的吞吐量长期低于内核网桥,早期测评中 slirp4netns 的带宽明显低于有根模式下的 veth 方案,较新的实现缩小了这一差距[5]。资源限制方面,基于 cgroup 的运行参数只有在使用 cgroup v2 并配合 systemd 时才生效,条件不满足时相关参数会被忽略[3]。此外,在根目录文件系统中观察绑定挂载时,文件属主会显示为子标识区间内的大号标识,而非 root,这属于预期行为。
部分发行版出于安全考虑收紧了对非特权用户命名空间的开放策略,这会同时导致普通用户无法使用无根 Podman 或 Docker,需要在系统策略中为受信账户显式放行。
参见
参考资料
- Rootless [引用日期2026-10-14]
- paper-313db0b(PDF) [引用日期2026-10-14]
- 無根模式 [引用日期2026-10-14]
- Rootless Containers [引用日期2026-10-14]
- Attendance [引用日期2026-10-14]
- Rootless Containers [引用日期2026-10-14]
- charliecloud(7) — charliecloud-common — Debian testing [引用日期2026-10-14]
- rootlesskit [引用日期2026-10-14]
- Dokument [引用日期2026-10-14]
- How to Run Rootless Docker Containers - Skip to content [引用日期2026-10-14]
- Red Hat 红帽推出 Tank OS 开源项目,将 OpenClaw 运行环境封装为专用容器以提升安全 [引用日期2026-10-14]
- charliecloud [引用日期2026-10-14]
- Rootless Containers in Citpod [引用日期2026-10-14]