本节摘要:Podman 4.x 起用 Netavark 配置网络、Aardvark 提供容器名解析,替代了早期的 CNI 插件栈。rootful 模式下形态与 Docker 桥接近(真网桥加 iptables);rootless 模式没有 root 权限创建内核网桥,由用户态网络进程(slirp4netns 或 pasta)模拟网络栈。本节用实际输出对比两种模式,讲清端口发布、容器名解析与性能特征的机制根源。
rootful Podman 创建网络时,内核里出现的东西和 Docker 基本同构:
# 创建一个自定义网络(rootful) sudo podman network create appnet # appnet # 看内核里多了什么 ip addr | grep -A2 appnet # 12: appnet: ... state UP # inet 10.89.0.1/24 ... # 一个真实的 Linux 网桥,与 docker0 同类 # 容器接入后,网桥上挂着 veth 设备 sudo podman run --rm --net appnet alpine:3.19 ip addr show eth0 # inet 10.89.0.2/24 —— 从网桥子网分配
差异都是工程细节级的:Podman 的网络配置由 Netavark(一个独立的 Rust 程序)计算并落到 netavark 目录下的配置文件,Docker 的网络配置内嵌在 daemon 里;Podman 的 DNS 解析由 Aardvark 承担,Docker 的内嵌 resolver 在 daemon 的 iptables 规则里。对使用者而言 rootful 侧的心智模型可以完全复用 Docker 的:网络是隔离的广播域,端口发布做 NAT,容器名可互访。
rootless 模式没有 root 权限,创建不了内核网桥与 iptables 规则。Podman 的解法是引入用户态网络栈:早期默认 slirp4netns,4.x 之后逐步转向 pasta(性能更好、代码更精简)。它们本质上是"翻译器进程"——把容器网络命名空间里的以太网帧翻译成宿主机用户进程的 socket 收发:
# rootless 模式下看容器里的网络(默认网络叫 podman) podman run --rm alpine:3.19 ip addr show eth0 # eth0: ... inet 10.0.2.100/24 # 注意网段:10.0.2.x 是用户态网络栈的经典默认(继承自 QEMU 传统) # 一个关键的行为差异:容器内 ping 网关 podman run --rm alpine:3.19 ping -c2 10.0.2.2 # (可能超时或丢包) # 但 TCP 连接正常: podman run --rm alpine:3.19 wget -qO- http://10.0.2.2:8080 || echo "TCP 正常路径" # 解读:网关是模拟设备,ICMP 的模拟不完整是已知特性, # "ping 不通但 curl 通"在 rootless 下不是故障信号

-p 8080:80 在两边都能用,但实现路径不同。rootful 下与 Docker 相同:iptables 做目标地址转换,流量在内核态直达容器。rootless 下分两种情况: pasta 模式里由 pasta 进程监听宿主端口再转发进容器;另有 rootful 端口代理方案(rootlessport)在特定版本间过渡。对用户的影响主要有两点:其一,rootless 下绑定 1024 以下特权端口受限(除非内核允许或做了 capability 调整,见第 6.2 节);其二,发布端口的属主是用户进程,lsof 里能看到它属于你而不是 root——审计时别误判成可疑进程。
容器名互访在两种引擎里都可用,机制不同。Docker 的内置 resolver 由 daemon 维护;Podman 4.x 里 Aardvark 监听在网桥地址上应答容器发出的 DNS 查询。能力边界要记住三条:解析只在同一网络内有效(跨网络必须用 IP 或注册到系统级 DNS);DNS 依赖网络栈正常工作,rootless 下若网络进程异常,先查的是它而不是"DNS 服务";外部域名解析走宿主配置,宿主换了 resolver(比如 systemd-resolved 调整)容器内会跟着变——别在容器里硬编码上游 DNS 去对冲,那是把问题藏起来。
把本节内容折叠成一份可在迁移前跑的检查单:确认应用是否监听特权端口(是则评估 rootful 或内核参数);确认是否依赖 ICMP 做健康检查(是则换成 TCP 探测);确认容器间是否用容器名通信(是则确认同网络部署,或改用 Pod 内回环,见第 2.3 节);确认是否有性能敏感的大流量路径(吞吐敏感则考虑 rootful Netavark 或调整 pasta 参数)。四条都过,网络侧的迁移风险就收敛到版本差异级别了。
检查单之外,还有一个"版本差异级别"的典型样本值得认识,因为它在升级窗口期出现得毫无征兆:Podman 从 3.x 的 CNI 插件栈切到 4.x 的 Netavark 时,旧网络(CNI 时代的容器与配置)与新网络栈不互通,升级后第一次启动会看到旧网络被重建的提示,IP 段可能变化。形态与 Docker 升级时 bridge 网段变化引发的"容器互访突然失败"如出一辙——机制上的教训是通用的:任何引擎的大版本升级后,第一批验证项就该是"容器间通信与端口发布",这是网络配置最脆的两根弦。把这条写进变更手册,比记住任何具体版本号都耐用。