修复 WSL2 Arch Linux 里 Podman Build 的 Newuidmap 报错

在 Windows 上的 WSL2 Arch Linux 里跑 rootless Podman,构建镜像时可能直接卡在 user namespace 初始化阶段:

podman build . -t game-crawler:latest

报错类似这样:

WARN[0000] "/" is not a shared mount, this could cause issues or missing mounts with rootless containers
ERRO[0000] running `/usr/sbin/newuidmap 61029 0 1000 1 1 100000 65536`: newuidmap: Could not set caps
Error: cannot set up namespace using "/usr/sbin/newuidmap": should have setuid or have filecaps setuid: exit status 1

"/" is not a shared mount 只是 warning。这里真正让 build 失败的是 newuidmap: Could not set caps

触发条件

这是 rootless Podman 的问题,不是 Dockerfile 本身的问题。

Podman 官方的 rootless tutorial 里写到,rootless Podman 需要 /etc/subuid/etc/subgid 里的 subordinate UID/GID 范围。newuidmap(1) 的手册也说明,它负责设置 user namespace 的 UID 映射,并会检查调用者是否被 /etc/subuid 授权。

也就是说,rootless Podman 创建容器命名空间时,需要这两个辅助程序:

/usr/bin/newuidmap
/usr/bin/newgidmap

在 Arch Linux 里它们来自 shadow 包。如果二进制没有 setuid,也没有对应 file capability,普通用户就没有权限完成 UID/GID 映射,Podman build 会在创建 namespace 时失败。

检查当前状态

先看文件权限和 capability:

stat -c '%A %U:%G %a %n' /usr/bin/newuidmap /usr/bin/newgidmap
getcap /usr/bin/newuidmap /usr/bin/newgidmap

出问题时可能是这样:

-rwxr-xr-x root:root 755 /usr/bin/newuidmap
-rwxr-xr-x root:root 755 /usr/bin/newgidmap

getcap 没有任何输出。

再确认当前用户有 subordinate ID:

grep "^$USER:" /etc/subuid /etc/subgid

正常应该有类似输出:

/etc/subuid:nite:100000:65536
/etc/subgid:nite:100000:65536

如果这里没有当前用户的记录,需要先补 /etc/subuid/etc/subgid。如果这里已经有记录,但 newuidmap/newgidmap 没有 setuid 或 capability,那就继续修权限。

用 file capability 修复

优先给两个辅助程序加最小 capability:

sudo setcap cap_setuid=ep /usr/bin/newuidmap
sudo setcap cap_setgid=ep /usr/bin/newgidmap

检查结果:

getcap /usr/bin/newuidmap /usr/bin/newgidmap

应该看到:

/usr/bin/newuidmap cap_setuid=ep
/usr/bin/newgidmap cap_setgid=ep

Arch 里 /usr/sbin 通常是指向 bin 的链接,所以报错路径即使写的是 /usr/sbin/newuidmap,修 /usr/bin/newuidmap 也是同一个文件。

验证 rootless namespace

不用完整 build。先用 podman unshare 验证 UID/GID 映射能不能建起来:

podman unshare sh -c 'echo uid_map:; cat /proc/self/uid_map; echo gid_map:; cat /proc/self/gid_map'

修好后会看到类似:

uid_map:
         0       1000          1
         1     100000      65536
gid_map:
         0       1000          1
         1     100000      65536

这里的 1000 是当前 WSL 用户的 UID,100000 65536 来自 /etc/subuid/etc/subgid

然后重新 build:

podman build . -t game-crawler:latest

如果 setcap 不可用

先确认 setcap/getcap 是否存在:

command -v setcap getcap

如果没有,安装提供它们的包:

sudo pacman -S libcap

还有一种传统做法是给 newuidmap/newgidmap 加 setuid:

sudo chmod u+s /usr/bin/newuidmap /usr/bin/newgidmap

检查:

stat -c '%A %U:%G %n' /usr/bin/newuidmap /usr/bin/newgidmap

期望看到 -rwsr-xr-x。如果 file capability 可用,优先用 setcap,权限范围更窄。