背景
最近在 WSL2 的 Arch Linux 环境中搭建开发环境,想用 Podman 完全替代 Docker,实现 rootless 容器管理(更安全、更轻量),并通过 podman compose 运行现有的 docker-compose.yml 文件。
一开始以为只是简单 pacman -S podman 就能用,结果连续踩了几个经典坑:
- newuidmap / newgidmap 缺少 setuid 或 capabilities,导致 namespace 建立失败
- netavark nftables 在 WSL2 内核下报错
- podman compose 优先调用了 docker-compose 插件,却连不上 socket
- 用户级 systemd(systemctl --user)连接 bus 失败,
$XDG_RUNTIME_DIR / $DBUS_SESSION_BUS_ADDRESS看似设置了却无效 - 用 sudo systemctl --user 导致环境变量不继承
整个过程花了小半天时间,但最终成功实现了零 sudo、rootless、代码路径原地使用、podman compose 正常运行的开发体验。下面把所有问题、思路、命令和最终方案整理成一篇完整指南,希望帮到同样在 WSL2 + Arch 上折腾 Podman 的朋友。
环境信息
- WSL2(Windows 11)
- 发行版:Arch Linux
- Podman 版本:(建议用最新版,过程中用的是 5.x 系列)
- 内核:Linux x.x.x-microsoft-standard-WSL2
目标:rootless 模式下运行 podman compose up -d,代码和 volume 直接挂载当前目录,无需 Podman Desktop 的独立 machine。
问题 1:newuidmap 权限缺失
现象:
newuidmap: Could not set caps
Error: cannot set up namespace using "/usr/bin/newuidmap": should have setuid or have filecaps setuid
原因:Arch 的 shadow 包安装的 newuidmap / newgidmap 默认没有 setuid 位,也没有 file capabilities,而 WSL2 内核对 setuid 支持不完美。
解决:
# 检查当前权限
getcap /usr/bin/newuidmap
ls -l /usr/bin/newuidmap # 看到 -rwxr-xr-x,没有 s 位
# 赋予 capabilities(推荐,WSL2 兼容性更好)
sudo setcap cap_setuid+ep /usr/bin/newuidmap
sudo setcap cap_setgid+ep /usr/bin/newgidmap
# 验证
getcap /usr/bin/newuidmap # 应显示 cap_setuid+ep
如果 setcap 失败,可尝试重装 shadow 并重启 WSL:
sudo pacman -S --overwrite '*' shadow
# Windows PowerShell: wsl --shutdown
额外检查:确保 subuid/subgid 已配置
grep '^$(whoami):' /etc/subuid /etc/subgid
# 没有的话添加:
echo "$(whoami):100000:65536" | sudo tee -a /etc/subuid /etc/subgid
问题 2:netavark nftables 失败
现象:
nftables error: "nft" did not return successfully while applying ruleset
原因:WSL2 内核对 nftables 支持不完整,Podman 5.x 默认用 nftables 后端。
解决:
编辑 ~/.config/containers/containers.conf(没有就创建):
[network]
firewall_driver = "iptables"
或者临时环境变量:
export NETAVARK_FW=iptables
问题 3:podman compose 连不上 socket
现象:
Cannot connect to the Docker daemon at unix:///run/user/1000/podman/podman.sock
原因:podman compose(包装器)检测到 docker-compose 插件,优先执行它,但 rootless Podman 的 socket 没启动。
解决:
-
启用用户级 podman.socket(注意:不要加 sudo)
systemctl --user enable --now podman.socket -
设置环境变量(让 docker-compose 插件兼容 Podman)
export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock # 建议加到 ~/.bashrc -
推荐替代方案:安装 podman-compose(Python 实现,不依赖 socket)
sudo pacman -S python-podman-compose # 然后用 podman-compose up -d 代替 podman compose
问题 4:systemctl --user 连接 bus 失败
现象:
Failed to connect to user scope bus via local transport: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined
原因:用了 sudo systemctl --user,sudo 切换到 root,用户变量丢失;或者 WSL2 下用户 systemd 实例没正确启动。
解决:
-
永远不要用 sudo systemctl --user,直接用普通用户运行:
systemctl --user enable --now podman.socket -
确保环境变量(WSL2 经常丢失):
export XDG_RUNTIME_DIR=/run/user/$(id -u) export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus永久加到
~/.bashrc:if [[ -z "$XDG_RUNTIME_DIR" ]]; then export XDG_RUNTIME_DIR=/run/user/$(id -u) mkdir -p "$XDG_RUNTIME_DIR" chmod 0700 "$XDG_RUNTIME_DIR" fi if [[ -z "$DBUS_SESSION_BUS_ADDRESS" ]]; then export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus fi -
启用 linger(让用户 systemd 持久运行):
loginctl enable-linger $(whoami) # 然后 wsl --shutdown 重启 WSL
最终验证
# 检查 socket
ls /run/user/1000/podman/podman.sock
# 测试简单容器
podman run --rm hello-world
# 启动 compose(根据你选择的方式)
podman compose --env-file .env -f docker/docker-compose.yml up -d
# 或
podman-compose --env-file .env -f docker/docker-compose.yml up -d
小结与建议
- 优先 rootless:安全性高,WSL2 开发路径原地使用最方便
- 优先 podman-compose:比 podman compose + docker-compose 插件更稳定
- WSL2 特性:经常需要手动设置 XDG/DBUS、enable-linger、重启 WSL
- 官方推荐 vs 实际:Podman 官方推 Podman Desktop + machine,但对于“在已有 WSL 发行版里开发”的场景,rootless 直装是更灵活的选择
整个过程虽然坑多,但调通后体验非常好:代码无需同步、CLI 零延迟、Podman 命令原生使用。
欢迎大家在评论区分享你的 WSL2 + Podman 经验,也欢迎指出文章中的不足~
(完)