
Podman Pod 用户命名空间完全指南--userns 模式详解与 Quadlet UserNS 配置【免费下载链接】podmanPodman: A tool for managing OCI containers and pods.项目地址: https://gitcode.com/gh_mirrors/po/podman导读本文围绕 Podman 仓库中 userns.pod.md 选项文档展开系统讲解podman pod create/podman pod clone的--userns选项以及 Quadlet pod 单元文件中的UserNS键包括其默认值来源、Rootless 模式下的 UID/GID 映射关系、auto/host/keep-id/nomap四种模式的语义与参数并深入对应源码pkg/specgen/namespaces.go、pkg/specgenutil/specgen.go、pkg/namespaces/namespaces.go说明底层实现原理。读完本文你将能根据主机权限模型准确选择用户命名空间模式正确书写可运行命令与 Quadlet 配置。一、选项定位一个模板文件三种使用场景userns.pod.md并非普通独立文档而是一个文档模板片段。其文件头部的注释明确声明#### This option file is used in: #### podman pod clone, pod create, podman-pod.unit.5.md.in #### If file is edited, make sure the changes #### are applicable to all of those.这意味着该内容在生成文档时会被同时注入到三类位置podman pod clone命令的 man pagepodman pod create命令的 man pageQuadlet 的podman-pod.unit.5.md.inpod 单元文件参考文档。因此在文档内部使用了模板变量切换标题形态场景选项写法CLI 命令#### **--userns***mode*Quadlet 单元文件### \UserNSmode这也解释了为什么本文标题同时覆盖两种形态命令行参数--userns与 Quadlet 键UserNS本质上是同一套用户命名空间语义的两种表达。二、选项语义与默认值来源该选项的作用是为 pod 中的所有容器统一设置用户命名空间模式Set the user namespace mode for all the containers in a pod.这是 pod 级选项意味着 pod 内所有容器共享同一套用户命名空间配置无需为每个容器单独指定。默认值解析遵循明确的优先级链路。从 pkg/specgenutil/specgen.go 的源码可以看到userns : c.UserNS // caller must make sure s.Pod is set before calling this function. if userns s.Pod { if ns, ok : os.LookupEnv(PODMAN_USERNS); ok { userns ns } else { userns rtc.Containers.UserNS } }即当用户未显式指定时依次回退命令行显式传入的--userns值环境变量PODMAN_USERNScontainers.conf配置文件中的containers.userns项。空值的语义需要特别注意文档明确说明 An empty value () means user namespaces are disabled即空值表示禁用用户命名空间容器直接运行在主机用户命名空间中。同时从 pkg/specgen/namespaces.go 的ParseUserNamespace实现可以看到空字符串会被解析为Host模式case : toReturn.NSMode Host return toReturn, nil三、Rootless 模式下的用户映射关系表文档给出了 Rootless 场景下各 Key 对应的主机用户与容器用户映射关系这是理解整个选项的核心表格KeyHost UserContainer User$UID0默认用户账号映射为容器内 root 用户host$UID0默认用户账号映射为容器内 root 用户keep-id$UID$UID主机用户账号映射为容器内相同 UIDauto$UIDnil主机用户 UID 不映射进容器nomap$UIDnil主机用户 UID 不映射进容器解读这张表的关键点与host行为一致rootless 用户默认获得容器内rootUID 0的身份这与 pkg/specgen/namespaces.go 中SetupUserNS对Host模式的处理吻合——直接从 spec 生成器中移除用户命名空间配置g.RemoveLinuxNamespace使容器进程与调用者共享同一用户命名空间keep-id是同名映射主机上$UID的用户在容器内仍然是$UID便于文件权限的自然对应auto与nomap是不映射主机用户 UID 不会出现在容器内部容器内看到的是一套全新的、与主机无关的 ID 空间。需要特别强调的是keep-id和nomap两种模式仅允许 rootless 用户使用This option is not allowed for containers created by the root user.这与 pkg/specgen/namespaces.go 中SetupUserNS对KeepID分支的校验一致——当非 rootless 运行时设置max size会直接报错if opts.MaxSize ! nil !rootless.IsRootless() { return user, fmt.Errorf(cannot set max size for user namespace when not running rootless) }四、四种有效 mode 逐一详解4.1host与调用者共享用户命名空间默认--usernshost容器内的进程运行在调用者的用户命名空间中容器内进程在主机上的权限与调用用户启动的其他普通进程完全相同。这是默认行为对应文档中 The processes running in the container have the same privileges on the host as any other process launched by the calling user (default) 的描述。4.2keep-id保持 UID/GID 一致--usernskeep-id创建用户命名空间时将当前 rootless 用户的 UID:GID 映射到容器内的相同数值。从源码看pkg/specgen/namespaces.go 的SetupUserNS会调用util.GetKeepIDMapping(opts)计算映射并显式设置容器进程的 UID、GID 与附加 GIDcase KeepID: opts, err : namespaces.UsernsMode(userns.String()).GetKeepIDOptions() ... mappings, uid, gid, err : util.GetKeepIDMapping(opts) idmappings mappings g.SetProcessUID(uint32(uid)) g.SetProcessGID(uint32(gid)) g.AddProcessAdditionalGid(uint32(gid))keep-id还支持精细参数keep-id:uidUID,gidGID,sizeSIZE其解析逻辑位于 pkg/namespaces/namespaces.go对应结构体KeepIDUserNsOptions的三个字段uid命名空间内目标 UIDgid命名空间内目标 GIDsize用户命名空间的最大尺寸MaxSize仅在 rootless 下有效。典型使用场景是挂载主机目录时希望容器内文件属主与主机用户一致避免权限错乱。4.3nomap不映射主机用户 ID--usernsnomap创建用户命名空间但不把当前 rootless 用户的 UID:GID 映射进容器映射表中对应 nil。源码中 pkg/specgen/namespaces.go 的NoMap分支调用util.GetNoMapMapping()计算映射并同样设置进程 UID/GID。此模式适合希望容器内完全脱离主机用户身份的隔离场景同样禁止 root 用户使用。4.4auto自动创建用户命名空间--usernsauto由 Podman 自动创建用户命名空间并根据需要自动估算其大小。auto支持三个子选项以逗号分隔子选项格式作用sizesizeSIZE显式指定自动用户命名空间的大小uidmappinguidmappingCONTAINER_UID:HOST_UID:SIZE强制在用户命名空间中添加一条 UID 映射gidmappinggidmappingCONTAINER_GID:HOST_GID:SIZE强制在用户命名空间中添加一条 GID 映射文档给出的完整示例--usernsauto:size8192注如果未指定sizeauto会自行估算用户命名空间的大小Ifsizeis not specified,autoestimates the size for the user namespace。三个子选项的解析入口同样在 pkg/specgen/namespaces.go 的ParseUserNamespace凡是auto:前缀的字符串都会被解析为Auto模式并携带选项字符串Value例如--usernsauto:uidmapping0:1000:1,size65536。从 pkg/specgenutil/specgen.go 可以看到auto模式下 ID 映射的构建细节当解析出的 UID/GID 映射为空时会设置IDMappings.AutoUserNs true并把auto:选项中携带的AdditionalGIDMappings/AdditionalUIDMappings与Size填入自动用户命名空间选项结构体。五、底层解析与校验源码级证据5.1 模式解析函数ParseUserNamespaceParseUserNamespace 是整个选项的入口解析器其分支逻辑与文档定义严格一一对应func ParseUserNamespace(ns string) (Namespace, error) { toReturn : Namespace{} switch ns { case auto: toReturn.NSMode Auto case keep-id: toReturn.NSMode KeepID case nomap: toReturn.NSMode NoMap case : toReturn.NSMode Host default: if value, ok : strings.CutPrefix(ns, auto:); ok { toReturn.NSMode Auto toReturn.Value value } else if value, ok : strings.CutPrefix(ns, keep-id:); ok { toReturn.NSMode KeepID toReturn.Value value } else { return ParseNamespace(ns) } } return toReturn, nil }值得注意的两点实现细节空字符串显式映射为Host与文档 空值表示禁用用户命名空间 的语义完全一致nomap不支持携带选项只有auto:和keep-id:允许带参数后缀与文档中auto[:OPTIONS,...]的语法定义相符。模式常量定义于 pkg/specgen/namespaces.goKeepID、NoMap字符串值为no-map、Auto并配套IsKeepID()/IsNoMap()/IsAuto()判断方法pkg/namespaces/namespaces.go。5.2 与显式 ID 映射选项的互斥关系--userns与细粒度 ID 映射选项不能同时使用。在 cmd/podman/containers/create.go 中可见if c.Flag(userns).Changed { return vals, errors.New(--userns and --uidmap/--gidmap/--subuidname/--subgidname are mutually exclusive) }对应地docs/source/markdown/options/uidmap.pod.md、docs/source/markdown/options/gidmap.pod.md、docs/source/markdown/options/subuidname.md、docs/source/markdown/options/subgidname.md 中也互相声明了冲突关系。若需要完全自定义的逐段映射应放弃--userns改用--uidmap/--gidmap/--subuidname/--subgidname若只需四档模式之一则使用--userns更简洁。六、Quadlet 场景UserNSmode键在 Quadlet pod 单元文件*.pod文件中同样的功能通过UserNS键配置。对应源码位于 pkg/systemd/quadlet/quadlet.go键名常量KeyUserNS UserNS实际转发逻辑见 pkg/systemd/quadlet/quadlet.goif userns, ok : unitFile.Lookup(groupName, KeyUserNS); ok len(userns) 0 { podman.add(--userns, userns) mappingsDefined true }Quadlet 单元文件示例[Pod] UserNSkeep-idQuadlet 还提供更高层的RemapUsers键取值auto/keep-id/manual来间接生成--userns参数pkg/systemd/quadlet/quadlet.goRemapUsersauto结合UidMap/GidMap/UidSize生成--usernsauto:uidmapping...,gidmapping...,size...RemapUserskeep-id生成--usernskeep-id:uid...,gid...各只允许单个映射值。七、综合实践示例7.1 创建使用自动用户命名空间的 podpodman pod create --name webpod --usernsauto:size655367.2 保持主机 UID/GID 的 rootless podpodman pod create --name devpod --usernskeep-id7.3 克隆已有 pod 并切换用户命名空间模式podman pod clone --usernsnomap webpod webpod-nomap7.4 通过环境变量设置默认模式export PODMAN_USERNSkeep-id podman pod create --name mypod # 继承 PODMAN_USERNS 的默认值7.5 Quadlet pod 单元文件[Pod] UserNSkeep-id八、小结与选型建议需要容器内 root 权限且信任调用者环境时使用默认值/host需要容器与主机文件属主一致、避免权限错位时rootless 下优先keep-id可配合keep-id:uid...,gid...,size...微调需要最强 ID 隔离、完全不暴露主机用户 ID 时rootless 下使用nomap需要按需自动分配 ID 空间、或强制注入特定 UID/GID 映射段时使用auto配合size、uidmapping、gidmapping需要精细逐段映射且不愿走四档模式时改用--uidmap/--gidmap/--subuidname/--subgidname与--userns互斥。进一步阅读userns.pod.md选项原文、namespaces.go模式解析与 setup 实现、specgen.go默认值链路与 ID 映射构建、quadlet.goQuadlet 用户映射处理。【免费下载链接】podmanPodman: A tool for managing OCI containers and pods.项目地址: https://gitcode.com/gh_mirrors/po/podman创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考