LabHub

博客

Podman 6.0 — 移除 slirp4netns、CNI 和 cgroups v1;macOS 默认 provider 换成了 libkrun

한국어English日本語中文

引言 — 时隔27个月的大版本,以及悄悄变更的归属

Podman 6.0.0 于 2026 年 6 月 24 日发布。5.0.0 是 2024 年 3 月 19 日发布的,所以这是时隔 27 个月的大版本。紧随其后,7 月 8 日 6.0.1 与 —— 同一天 —— 5.8 分支的 5.8.5 一起发布了。老一代分支在大版本发布后不久仍在收到补丁,这件事本身就是本文后半部分「什么时候升级」判断的重要素材。

比版本号更先引起注意的是仓库地址。发行说明里的 issue 链接全部指向 github.com/podman-container-tools/podman。Podman 与 Buildah、Skopeo 等一起,以「Podman Container Tools」的名义于 2025 年 1 月 21 日获批进入 CNCF Sandbox(CNCF 项目页面Red Hat 的公告),而 6.0 正是 GitHub 组织迁移真正落地的版本。Go 的导入路径也从 github.com/containers/podman/v5 变成了 go.podman.io/podman/v6。对于把 Podman 作为库来引用的项目而言,光这一点就是一项迁移工作。

本博客此前已经写过从 Docker 迁移到 Podman 的故事。那篇文章写下「Podman 还处在 5.x 世代」还不到十天,6.0 就发布了,所以本文算是它的续篇 —— 只依据发行说明原文,梳理 6.0 里删除了什么、桌面端(尤其是 macOS)发生了什么变化。容器镜像层方面的最新动态,我在containerd 的 EROFS 原生层一文中另行讨论过;本文专注于运行时和桌面这两层。

先看移除清单 — 升级前检查自己的环境

6.0 是一个删除、而非新增功能唱主角的版本。把发行说明里的 Breaking Changes 原样搬过来:

随之而来的还有配套技术栈的要求。6.0.0 必须搭配 Buildah v1.44.0、Skopeo v1.23、Netavark/Aardvark v2.0.0 一起使用,配置文件的解析逻辑被整体重写,为此还专门发布了一份设计文档。用发行版打包版本的人,发行版会替你配好这套组合;但自己编译或者只升级一部分的人,就得自己核对版本组合。

升级前,可以用下面的方法检查自己的环境是否落在移除清单里:

# 如果网络后端是 cni,在 6.0 上不会工作(必须是 netavark)
podman info --format '{{.Host.NetworkBackend}}'

# 检查 rootless 网络是否固定在 slirp4netns 上 —— 检查 containers.conf
grep -r "slirp4netns" ~/.config/containers/ /etc/containers/ 2>/dev/null

# DB 后端 —— 如果是 boltdb,6.0 首次运行时会尝试迁移到 sqlite
podman info --format '{{.Host.DatabaseBackend}}'

# cgroups 版本 —— 如果是 v1,得先从主机开始迁移
podman info --format '{{.Host.CgroupsVersion}}'

BoltDB → SQLite 虽然有自动迁移,但光凭「自动」两个字就不备份直接升级大版本,是另外一回事。先清理一下容器再升级会更安心。

macOS — 默认 provider 变成了 libkrun

先交代一下 macOS 这段故事的背景: 在 5.0(2024-03)里,QEMU provider 被移除,基于 Apple 原生虚拟化技术的 applehv(内部是 vfkit + Virtualization.framework)成为默认项,而 5.2(2024-08) 又新增了 libkrun 后端。当时的发行说明明确指出,libkrun 的优势在于可以把 GPU 挂载进 VM 来加速工作,但默认值仍然保留为 applehv。

6.0 把这个默认值翻转了过来。发行说明原文是这样写的: "The default podman machine provider on Macs has been changed to libkrun." 这个选择看起来和「想在 VM 里用 GPU」这类需求(比如本地 LLM 推理)的增长脱不了关系(这不是我的猜测 —— 5.2 的发行说明本身就把 GPU 挂载写成了 libkrun 存在的理由)。

实务上重要的几点:

还有一点需要诚实面对。libkrun 是否已经成熟到可以做默认值,证据其实并不一致。6.0.1 和 5.8.5 在同一天修复的那个 bug 是: 「主机上的端口扫描进程会无意中向 libkrun VM 发送关机命令,导致 VM 周期性关闭」 —— 也就是说,默认值升级仅仅两周后,第一个补丁就是修这个的。此外,2025 年 12 月的一次 discussion 报告过,在课堂环境里用 libkrun 时出现了绑定挂载权限问题(按报告者自己的统计,约四分之一的学员必须把宿主目录权限放宽到 777,挂载才能生效),而据称在 applehv 上没有复现。这只是个别用户的报告,不能一概而论,但如果你的工作方式以 -v 绑定挂载为主,那在跟随默认值之前,用自己的工作流验证一下是有理由的。

顺带说一下 Windows 那边: Windows 10 支持被移除的同时,hyperv provider 的 VM 启动、停止不再需要管理员权限了(创建仍然需要,且只适用于新建的 VM),还新增了一个 podman system hyperv-prep 命令,供管理员提前准备好主机。

pasta 独当一面的时代 —— 以及 Pesto 这个实验

移除 slirp4netns 并不突然。早在 5.0,rootless 的默认网络就已经从 slirp4netns 换成了 pasta("for improved performance" —— 5.0 的发行说明原话),6.0 只是删掉了两年多来一直不是默认值的代码。即便如此,containers.conf 或脚本里固化了 slirp4netns 的环境应该还存在,所以前面那行 grep 值得跑一下。

pasta 独当一面的时代,有一个行为特性值得了解: 正如 Podman 网络教程 明确指出的,pasta 模式下的容器默认互相隔离。它不像网桥那样有一张虚拟网络,所以容器之间通信要么走主机端口映射,要么放进同一个 Pod 共享网络命名空间。如果 rootless 场景下容器之间需要直接通信,标准做法是创建一个 rootless netavark 网桥网络。

不过 rootless 网桥有一个由来已久的痛点 —— 负责端口转发的 rootlessport 会作为代理插进来,导致容器看到的客户端源 IP 不再是真实地址。见过连接日志清一色打印网关地址的人对此深有体会。6.0 在这里加入了一个实验性的替代方案: 在 containers.conf 里这样配置,

[network]
rootless_port_forwarder = "pasta"

rootless 网桥网络的端口转发就不再由 rootlessport 处理,而是由一个叫 Pesto 的工具,利用 pasta 的内核级转发来完成。据源码里的说明,rootless 命名空间里共享的 pasta 实例会接管主机侧转发,本地(localhost)流量走内核 splice,外部流量走 TAP,并在这个过程中保留源 IP —— 容器看到的会是真实的客户端地址,而不是代理或网关地址。

这是个值得期待的能力,但预期要放低一些。默认值仍然是 rootlessport,发行说明自己也写着「等稳定性更有把握后再考虑切换」,而且它需要包含 pesto 二进制的 passt 版本(passt-0^20260507.g1afd4ed 及以上)。而 6.0.1 已经修复了一个 Pesto 规则清理的 bug(容器重启、网络重新加载时规则没有被清理,导致转发失败)。「实验性」这个标签不是摆设。这是一个适合在真正在意源 IP 的场景(fail2ban 类工具、访问控制、审计日志)里以 opt-in 方式验证的阶段,还不是拿来当生产默认值用的阶段。

再补充一个附录级别的实验: 在内核 6.18 及以上版本中,加入了用 nsfs 文件句柄替代原本用于保持 rootless 用户命名空间存活的 pause 进程的功能。这是个藏在 drop-pause-process 环境变量后面的实验性功能,但它是一个信号 —— rootless Podman 里一个存在已久的结构性组件,有可能会消失。

Quadlet —— 从 .app 文件到子目录

用 systemd unit 管理容器的 Quadlet 那一侧,也发生了结构性变化。以前用 podman quadlet install 安装的 Quadlet 及其附属文件,是以 .app 文件的形式被跟踪的;从 6.0 开始,改成放进一个子目录里。发行说明的解释是这样能减少 bug、让手动管理更轻松 —— 反过来说,依赖 .app 方式的脚本或文档就成了需要修改的对象。

其他 Quadlet 方面的变化:

podman generate systemd 过时、Quadlet 成为正解的这条脉络,正是迁移指南里讲过的那样;6.0 是把这个 Quadlet 进一步推向「发行版可以打包分发的东西」这个方向。读起来像是一个信号 —— 把容器部署成 systemd 服务这种模式,正在变成一等公民。

Docker 兼容性改进 = 脚本行为的变化

6.0 里相当一部分 Breaking Changes 都是「向 Docker 看齐」。兼容性改进固然值得高兴,但反过来看,也意味着按老版本 Podman 行为写的脚本,会悄悄地表现出不同的行为。容易踩坑的几个:

「Docker 兼容性变好了」这句话读过去很轻松,但在 CI 或者清理用的定时任务里,volume prune 和过滤条件语义的变化,是实实在在改变了数据被删除的方式。升级之后,第一次运行值得盯紧一点。

CVE-2026-57231 —— 如果你还在 5.8.3 及以下,光这一条就够升级了

随 6.0.0 一起公开的安全修复有一项。GHSA-4hq8-gpf5-8p68(CVE-2026-57231,GitHub 严重级别 high): 恶意镜像可以通过构造过的 Env 条目,把主机的环境变量泄露进容器里,配合通配符 glob,甚至可以在不知道变量名的情况下批量泄露。受影响范围是 v1.8.1 到 v5.8.3 —— 事实上覆盖了近几年几乎所有版本。修复分别落在了 v5.8.4(2026-06-26)和 v6.0.0 里。

「光是 pull 镜像、run 一下,主机环境变量就泄露了」这类漏洞,对桌面用户来说尤其伤。因为开发机正是那种把 API key、token 常年 export 在 shell 环境里的地方。哪怕你没打算升级到 6.0,只要还在 5.8.3 及以下,也应该升到 5.8.4 及以上。

那么,什么时候升级

现在就可以升级的情况:

需要等一等、或者应该留在 5.8.x 的情况:

再补充一点: podman machine os apply 在 6.0 里被重写成基于 bootc switch 的实现,这也是一个悄悄发生的变化。这意味着 machine VM 的 OS 更新,现在是通过切换到一个可启动的容器镜像来处理的 —— 不可变 OS 这条思路,已经一路下沉到了桌面端的 VM(服务器侧不可变 OS 的话题,可以参见Talos 1.13 一文)。

结语

Podman 6.0 不是一个靠新功能来吸引人的版本,而是一个清偿债务的版本。slirp4netns、CNI、iptables、cgroups v1、BoltDB —— 这些早在数年前就已经确定了继任者,6.0 只是宣告这段宽限期结束了。在此之上,还叠加了 CNCF 迁移这样的治理层变化、macOS 上 libkrun 切换这样的桌面层变化,以及 Pesto 这个 rootless 网络的下一步实验。

升级的判断其实很简单。先用上面那三行 podman info 检查自己是否落在移除清单里,中招就先解决那一项;如果是 macOS,就有意识地选定 provider;自动化多的话,先审计一遍 Docker 兼容性变化清单再升级。而不管怎样,都别继续停留在 5.8.3 及以下 —— 光 CVE-2026-57231 这一条,理由就已经足够。

参考资料

评论

还没有评论。

登录后即可发表评论