本节摘要:Podman 与 Docker 的性能差异集中在三个可测维度:容器启动延迟(Fork-Exec 架构的天然强项)、rootless 网络吞吐(用户态网络栈的代价)、存储 IO(挂载方式的选择)。本节不讲别人的 benchmark 结论,讲可复现的实验方法与三个维度的调优清单——你的场景该信你自己的数据。
网上关于"Podman 和 Docker 谁快"的结论互相打架,原因多数出在实验设计。四条原则:同机同内核(跨机器对比测的是硬件);同镜像同命令(镜像大小差异会污染启动数据);多次取分布而不是取均值(容器启动时间是长尾分布,中位数与 P99 讲的是两个故事);预热后测(首次启动含镜像拉取与缓存冷启动,日常性能看的是稳态)。
# 一个合格的启动延迟实验模板 for engine in podman docker; do for i in $(seq 1 20); do # --rm 保证每轮干净;测的是"启动到可退出"全链路 /usr/bin/time -f "%e" $engine run --rm alpine:3.19 true 2>> timing-$engine.txt done done sort -n timing-podman.txt | awk '{a[NR]=$1} END{print "median:", a[int(NR/2)]}' # 解读:取中位数与最大值(近似 P99)两栏做结论; # 冷启动另测一轮不预热的,分开报告 # 更贴近业务的口径:测"应用就绪"而不是"容器启动" # 用健康检查通过的时刻做终点(配合第 7.2 节的探针)
在典型 Linux 环境下的量级预期(供校验你的实验是否离谱):稳态启动两者都在几百毫秒量级,Podman 因省去守护进程往返通常持平或略快;rootless 首次启动要创建用户命名空间与网络,冷启动差距明显但稳态收敛。真正的性能分水岭不在启动,在下面两节。
第 5.1 节讲过 rootless 网络是用户态翻译(pasta 或 slirp4netns),每个包要过一次用户态。对吞吐敏感的负载(大文件传输、数据库批量导入),这层代价是真实的。调优按顺序:
# 第一档:确认当前网络栈(4.x 后 pasta 是优选) podman info --format '{{.Host.NetworkBackend}} {{.Host.NetworkBackend}}' 2>/dev/null \ || podman network info podman | grep -i backend # 第二档:吞吐敏感的容器单独走 rootful 网络 # (操作允许的前提下)用 sudo podman 跑该容器, # 内核态 Netavark 桥的性能与 Docker 同级(第 5.1 节) # 第三档:大批量本地数据不走网络 # 容器间共享数据改用共享卷(第 5.2 节), # 网络只传控制流,翻译层的代价被绕开
容器读写宿主文件系统的性能由挂载方式决定,规律对两个引擎一致但选项有别:命名卷(镜像存储同层的 graph 位置,读写在 overlay 引擎的管理路径上)、bind mount(直通宿主文件系统,少一层)、以及 rootless 特有的 overlay 挂载选项。实践建议按负载分层:数据库这类重 IO 用命名卷或专用 bind mount;源码目录的挂载在 rootless 下注意 inode 与缓存参数,大仓库场景(几万文件)的初载耗时是已知的工程痛点,缓解手段是让构建缓存走命名卷而不是跟着源码挂载。
# 存储占用与回收(迁移后磁盘排查的常用三连) podman system df -v # Images 12 1.2GB(含可回收细节) podman image prune --filter until=168h # 清理一周前的悬空镜像层 podman system prune # 全套清理:停止容器、悬空层、无用网络 # 对比提示:docker system prune 的肌肉记忆可以直接平移
无守护进程架构在大规模并发下的特征值得知道:同时启动几百个容器时,Fork-Exec 模型意味着几百个并发的 conmon 与运行时进程——没有 daemon 做队列与节流,瞬时进程数高于 Docker(后者在 daemon 内排队)。单机开发与一般服务器无感;跑高密度容器(单机数百)的场景要把这个特征纳入容量规划。反过来,daemon 队列在故障时的表现是"全部一起卡住",Fork-Exec 的表现是"各自独立、坏的只是自己"——性能特征与故障特征同源,选型时一起考虑。
背景:迁移后一个夜间数据导入任务(向容器里的 PostgreSQL 灌 40GB 数据)耗时翻倍,从 90 分钟涨到 180 分钟。操作:先定位维度——任务走 rootless 网络的端口连接(应用容器经 127.0.0.1 连数据库容器),大流量全过用户态翻译层;再实验验证——同任务改用 rootful 模式跑数据库容器,耗时回落到 95 分钟;最终方案:数据库容器改为 Quadlet 服务以 rootful 运行(第 7 章的服务化让这个切换只是一份单元文件),数据目录按第 5.2 节配置卷与标签。结果:耗时恢复且更稳。解读:这个案例的教训不是"rootless 慢",而是"吞吐敏感型负载与控制流型负载要分开对待"——该任务里 40GB 是数据流,几 KB 是控制流,网络形态按数据流选。变式:若安全要求不允许任何 rootful 容器,方案改为导入任务也进容器、与数据库共享 Pod(第 2.3 节),大流量走 Pod 内回环,绕开用户态网络。