- 容器运行时
- 云原生
- CLI
【免费下载链接】podman
Podman: A tool for managing OCI containers and pods.
本指南以 Podman 官方基础网络教程(docs/tutorials/basic_networking.md)为骨架,系统讲解 rootful 与 rootless 容器在网络上的本质差异、防火墙对容器流量的影响,以及 Bridge、Macvlan、Pasta 三种最常用网络模式的原理、配置与完整可复现示例,并深入解析容器与 Pod 之间共享网络命名空间的通信方式。读完本文,你将掌握为不同运行身份(root/非 root)选择正确网络模式、配置端口映射、创建 macvlan 网络并启用 DHCP、以及解决容器间互访问题的完整实战能力。
rootful 与 rootless 容器网络的根本差异
决定 Podman 容器采用哪种网络路径的首要因素是容器由 root 用户还是非特权用户运行。其根本原因在于:非特权用户无法在宿主机上创建网络接口(这需要 root 权限),因此两者的默认网络模式截然不同:
- rootful 容器:默认网络模式为netavark(桥接网络),容器能够获得一个可路由(routable)的 IP 地址,直接参与宿主所在网络的通信;
- rootless 容器:默认网络模式为pasta,通过用户态网络栈实现无特权联网。
从源码角度可以印证这一设计:在 libpod/define/info.go 中,RootlessNetworkCmd字段明确指出默认 rootless 网络命令为pasta,而RootlessPortForwarder字段则记录了 rootless 桥接网络的端口转发机制(默认rootlessport,可选实验性的pasta)。你可以在任意机器上通过podman info查看这两项的实际取值。
此外,当 rootless 容器运行时,其网络操作会发生在额外的网络命名空间(network namespace)中。要加入该命名空间排查问题,使用:
$ podman unshare --rootless-netns防火墙:不改变网络配置,但决定流量是否可达
防火墙的角色不是影响网络本身的搭建与配置,而是影响这些网络上的流量,尤其是从外部(宿主机外)进入容器宿主、再通过端口映射转发给容器的入站流量。要点如下:
- 部分防火墙实现(如 firewalld 等)在检测到容器发布端口映射时,会自动打开对应端口;
- 如果容器流量表现异常,应首先检查防火墙,放行容器正在使用的端口;
- 一个非常常见的问题:重新加载防火墙会删除 netavark 生成的 iptables 规则,导致 rootful 容器立即失去网络连通性。Podman v3 起提供的
podman network reload命令可以在不重启容器的情况下恢复这些规则。
三种基础网络模式概览
大多数 Podman 容器与 Pod 只遵循几种简单场景,对应的三种模式分别为:
| 网络模式 | 默认适用身份 | 核心机制 |
|---|---|---|
| Bridge(桥接) | rootful(默认) | 容器与宿主挂接在内部桥接网络上,通过 NAT 访问外部网络 |
| Macvlan | 仅 root | 将宿主机整块物理网络接口"透传"给容器,容器直接接入宿主所在网络 |
| Pasta | rootless(默认) | 用户态网络,非特权用户无需在宿主上创建接口即可联网 |
Bridge 桥接网络
桥接网络的定义是:创建一个内部网络,容器与宿主机都挂接其上,随后该网络允许容器与宿主机外部通信。
如上图所示:笔记本用户运行了 web 与 db 两个容器,它们与宿主机处于同一虚拟网络中;默认情况下容器可以主动发起对外通信(例如访问互联网);虚拟网络上的容器通常持有不可路由的私有 IP 地址。
当外部客户端需要访问容器时,通常必须访问宿主机的外部网络接口与指定端口号:宿主机在允许入站流量后,通过为容器请求转发的端口添加防火墙转发规则,将入站流量转发给特定容器。
默认网络与自定义网络
- 桥接网络是root 身份创建容器的默认网络,Podman 提供一个默认桥接网络(名为
podman),也可以使用podman network create创建更多网络; - 容器在创建时可通过
--network标志加入网络,创建后可使用podman network connect/podman network disconnect动态挂接或摘除网络; - 创建网络时不指定子网,Podman 会从10.89.0.0/24 到 10.255.255.0/24的池中自动挑选空闲子网(见 podman-network.1.md),可通过
containers.conf的[network]节default_subnet_pools修改默认分配范围与大小。
rootless 用户使用 netavark 桥接
rootless 用户同样可以使用 netavark 桥接网络,体验与 rootful 高度相似,唯一区别是没有默认网络配置——只需手动创建一个网络,它即会按桥接网络方式建立:
$ podman network create默认网络 podman 的特殊性
netavark 下的默认网络podman是纯内存(memory-only)的:出于与 Docker 的向后兼容性考虑,它不支持 DNS 解析。若需要修改其配置,可先导出内存中的网络,再修改导出文件:
- rootful 默认网络:
podman network inspect podman | jq .[] > /etc/containers/networks/podman.json- rootless 默认网络:
podman network inspect podman | jq .[] > ~/.local/share/containers/storage/networks/podman.json端口转发:rootlessport 与实验性的 pasta
rootless 桥接网络默认使用rootlessport进行端口转发——它是一个用户态代理,不会保留客户端源 IP。若容器需要看到真实的客户端 IP,可在containers.conf的[network]节中设置:
[network] rootless_port_forwarder = "pasta"该选项使用pesto配置 pasta 的内核级转发,使容器看到真实的客户端 IP 而非桥接网关地址。注意:此选项目前为实验特性,行为可能发生变化,且要求安装携带pesto二进制的 passt 版本(>= passt-0^20260507.g1afd4ed)。从源码看,pasta/pesto 的端口转发在容器库(container-libs)的 netavarkSetup()内完成,Podman 侧仅在需要时对 rootlessport 做显式配置(见 libpod/networking_linux.go)。
Bridge 实战示例:对外暴露 Web 服务
默认情况下(未从 Podman v3 迁移时),rootful 容器使用 netavark 作为默认网络后端,无需指定网络名。下面的示例分别以 rootful 与 rootless 身份运行 Web 服务器并对外暴露,同时展示外部客户端如何连接。
rootful 方式(将容器 80 端口映射到宿主 8080):
(rootful) $ sudo podman run -d --name webserver -p 8080:80 quay.io/libpod/banner 00f3440c7576aae2d5b193c40513c29c7964e96bf797cf0cc352c2b68ccbe66arootless 方式(加入自定义网络 podman1,映射到宿主 8081):
$ podman run -d --name webserver --network podman1 -p 8081:80 quay.io/libpod/banner 269fd0d6b2c8ed60f2ca41d7beceec2471d72fb9a33aa8ca45b81dc9a0abbb12注意:上述命令将容器内 Nginx 监听的80 端口映射到了宿主8080/8081 端口,特意选择了非 80 端口来演示宿主端口与容器端口的映射关系(其实也可直接映射为 80,rootless 用户除外——非特权用户无法绑定 1024 以下端口)。
外部客户端访问时,只需将 HTTP 客户端指向宿主 IP 的对应端口:
(outside_host): $ curl 192.168.99.109:8080 ___ __ / _ \___ ___/ /_ _ ___ ____ / ___/ _ \/ _ / ' \/ _ `/ _ \ /_/ \___/\_,_/_/_/_/\_,_/_//_/ (outside_host): $ curl 192.168.99.109:8081 ___ __ / _ \___ ___/ /_ _ ___ ____ / ___/ _ \/ _ / ' \/ _ `/ _ \ /_/ \___/\_,_/_/_/_/\_,_/_//_/端口发布语法补充(详见 options/publish.md):--publish/-p的完整格式为[[hostIP:][hostPort]:]containerPort[/protocol]。宿主与容器端口均可指定为区间;hostIP缺省时绑定宿主全部 IPv4/IPv6 地址,0.0.0.0仅绑定 IPv4,[::]仅绑定 IPv6;默认发布 TCP 端口,发布 UDP 需显式指定udp,rootful 容器还支持sctp;省略hostPort时会随机分配宿主端口,可用podman port $CONTAINER $CONTAINERPORT查看实际映射。端口发布仅对使用自身网络命名空间的bridge网络与pasta模式生效。
Macvlan
使用 macvlan 时,容器获得宿主机上一块物理网络接口的访问权。该接口可配置多个子接口,每个子接口拥有独立的MAC 地址与 IP 地址;对 Podman 容器而言,它会在网络上表现得如同与宿主机处于同一网络的普通主机。
如上图所示,外部客户端可以直接通过容器自身的 IP 地址访问 Web 容器。通常容器的网络信息(含 IP 地址)像网络中的其他客户端一样,由DHCP 服务器租约分配。如果笔记本运行了 firewalld 之类的防火墙,需要相应放行以保证正常访问。
重要限制:使用 macvlan 必须以 root 身份运行 Podman。
Macvlan 实战示例
首先创建 macvlan 网络。你需要知道宿主连接可路由网络的接口名,示例中为eth0:
$ sudo podman network create -d macvlan -o parent=eth0 webnetwork webnetwork下一步确保DHCP 服务正在运行,它负责处理来自网络的 DHCP 租约。如果不需要 DHCP,可以在上面的network create命令中使用--subnet选项分配静态子网。
Podman 使用 netavark 实现网络功能,使用 DHCP 要求 netavark v1.6 或更高版本(配合 Podman v4.5+)。
启用 netavark DHCP 的两种方式——systemd 系统启用 socket 激活:
$ sudo systemctl enable --now netavark-dhcp-proxy.socket或非 systemd 系统手动启动守护进程:
$ /usr/libexec/podman/netavark dhcp-proxy --activity-timeout 0然后运行容器并确保挂接上刚创建的网络:
$ sudo podman run -d --name webserver --network webnetwork quay.io/libpod/banner 03d82083c434d7e937fc0b87c25401f46ab5050007df403bf988e25e52c5cc40 [baude@localhost ~]$ sudo podman exec webserver ip address show eth0 2: eth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP link/ether 0a:3c:e2:eb:87:0f brd ff:ff:ff:ff:ff:ff inet 192.168.99.186/24 brd 192.168.99.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::83c:e2ff:feeb:870f/64 scope link valid_lft forever preferred_lft forever从输出可见,容器 eth0 直接获得了局域网内的可路由地址192.168.99.186/24。由于容器持有该网络上的可路由 IP 且不受 firewalld 管理,无需改动防火墙,外部客户端可直接访问:
(outside_host): $ curl http://192.168.99.186 ___ __ / _ \___ ___/ /_ _ ___ ____ / ___/ _ \/ _ / ' \/ _ `/ _ \ /_/ \___/\_,_/_/_/_/\_,_/_//_/Pasta
pasta 是 rootless 容器与 Pod 的默认网络模式,专为无法在宿主机创建网络接口的非特权用户提供用户态网络(user-mode networking)。pasta 在容器的网络命名空间中创建一个TAP 设备,并提供完整的用户态 TCP/IP 协议栈。
如上图所示:笔记本上的非特权用户创建了 db 与 web 两个容器,二者都能访问笔记本之外的网络;只要容器绑定到宿主端口且笔记本防火墙放行,外部客户端即可访问容器。需要注意,非特权用户只能使用 1024–65535 的端口,低端口需要 root 权限(对应CAP_NET_BIND_SERVICE能力);该限制可通过sysctl net.ipv4.ip_unprivileged_port_start调整。
pasta 的一个固有局限是:默认情况下容器之间彼此隔离,与 bridge 的虚拟网络不同,没有共享的内部网络。容器间通信有两种途径:一是借助宿主系统上的端口映射,二是放入同一个 Pod共享网络命名空间(详见下文"容器与 Pod 之间的通信")。
从源码看,pasta 还内建了 DNS 转发能力(见 libpod/container_internal_common.go),并会在容器内注入对应的 DNS 服务器地址(见 libpod/container_internal_linux.go)。
Pasta 的默认参数细节
根据 options/network.md 的说明,Podman 调用 pasta 时默认附带若干参数,理解它们有助于排查网络问题:
--config-net:容器启动时自动配置网络(默认给出);--no-map-gw:默认禁止容器通过网关地址直接访问宿主;可通过在 pasta 专用选项中传--map-gw覆盖(--map-gw并非真正的 pasta(1) 选项,由 Podman 特判处理);--dns-forward 169.254.1.1:默认启用 DNS 转发并将该地址写入容器resolv.conf作为首选解析器,也可显式传--dns-forward指定其他地址;--map-guest-addr 169.254.1.2:默认启用,用于让容器内host.containers.internal的/etc/hosts条目生效,使容器能够连接宿主机;- 未配置任何
--publish或 pasta 的-t/-u选项时,默认传递-t none -u none关闭基于绑定端口的自动转发;同理-T none -U none关闭容器到宿主方向的自动转发。
pasta 常用选项示例(通过--network pasta:OPTIONS传入,多个选项用逗号分隔):
| 选项 | 作用 |
|---|---|
--network pasta:--map-gw | 允许容器通过网关地址直接访问宿主 |
--network pasta:--mtu,1500 | 设置容器内 tap 接口 MTU 为 1500 字节 |
--network pasta:-t,auto,-u,auto,-T,auto,-U,auto | 基于观察到的绑定端口,自动启用宿主机与容器两侧的端口转发 |
--network pasta:-T,5201 | 将容器 TCP 5201 端口转发到宿主(走回环接口,性能更佳) |
--network pasta:-t,5201 | 将宿主 TCP 5201 端口转发到容器 |
所有 pasta 选项也可在containers.conf的[network]节pasta_options键中统一配置。
Pasta 实战示例
下面的示例演示两个 rootless 容器如何通过端口映射通信,以及宿主网络中的客户端如何访问 rootless Web 服务器。
首先运行 rootless Web 服务器,将容器 80 端口映射到非特权端口 8080:
$ podman run -d --name webserver -p 8080:80 quay.io/libpod/banner 17ea33ccd7f55ff45766b3ec596b990a5f2ba66eb9159cb89748a85dc3cebfe0由于 rootless 容器之间无法直接通过 IP 地址进行 TCP/IP 通信,需要借助宿主机 IP 与端口映射。先查询宿主接口 IP:
$ ip address show eth0 3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 3c:e1:a1:c1:7a:3f brd ff:ff:ff:ff:ff:ff altname eth0 inet 192.168.99.109/24 brd 192.168.99.255 scope global dynamic noprefixroute eth0 valid_lft 78808sec preferred_lft 78808sec inet6 fe80::5632:6f10:9e76:c33/64 scope link noprefixroute valid_lft forever preferred_lft forever从另一个 rootless 容器中,使用宿主 IP 与端口即可成功通信:
$ podman run -it quay.io/libpod/banner curl http://192.168.99.109:8080 ___ __ / _ \___ ___/ /_ _ ___ ____ / ___/ _ \/ _ / ' \/ _ `/ _ \ /_/ \___/\_,_/_/_/_/\_,_/_//_/宿主机外的客户端同样可以借助 IP 与端口访问:
(outside_host): $ curl http://192.168.99.109:8080 ___ __ / _ \___ ___/ /_ _ ___ ____ / ___/ _ \/ _ / ' \/ _ `/ _ \ /_/ \___/\_,_/_/_/_/\_,_/_//_/容器与 Pod 之间的通信
大多数容器用户都熟悉容器间及容器与外部世界的通信方式:通常每个容器拥有独立的 IP 地址与网络信息,通过常规 TCP/IP 手段(IP 地址,或基于容器名的 DNS 名称)互相通信。但Pod 是一个或多个容器的集合,因此继承了一些特殊性。
按定义,Podman Pod 中的所有容器共享同一个网络命名空间——这意味着它们拥有相同的 IP 地址、MAC 地址与端口映射。因此,Pod 内容器之间可以方便地使用localhost通信。
上图描绘了一个挂接在桥接网络上的 Pod:Pod 内"装"有 db 与 web 两个容器。由于共享网络命名空间,二者可通过localhost(127.0.0.1)互相通信;同时它们也都能通过Pod 自身分配到的 IP 地址(以及适用的 DNS 名称)被外部寻址。
这一设计意味着:在 pasta 模式下被"隔离"的容器,一旦放进同一个 Pod,即可像在桥接网络中一样使用 localhost 自由互访,这正是 pasta 场景下推荐用 Pod 组织多容器应用的根本原因。
小结与排障要点
- 身份决定默认网络:rootful 默认 netavark 桥接(容器拥有可路由 IP),rootless 默认 pasta(用户态网络,容器无独立 IP);
- 端口映射是外部访问的统一入口:无论哪种模式,外部客户端通常都经宿主 IP + 映射端口访问容器,语法遵循
[[hostIP:][hostPort]:]containerPort[/protocol]; - macvlan 仅限 root,容器直接暴露在局域网,需自行管理 DHCP(netavark v1.6+/Podman v4.5+)或静态子网,并注意宿主防火墙放行;
- rootless 端口受限:1024 以下端口需要特权,可用
sysctl net.ipv4.ip_unprivileged_port_start调整; - 容器不通先查防火墙:重载防火墙可能清掉 netavark 的 iptables 规则,rootful 容器可用
podman network reload恢复; - 容器互访:rootless 场景下通过宿主端口映射,或直接放入同一 Pod 共享网络命名空间以 localhost 互访;
- rootless 网络命名空间排查:使用
podman unshare --rootless-netns进入容器网络命名空间查看。
关于 rootless 环境的前置准备(/etc/subuid、/etc/subgid配置、pasta 安装要求等),可进一步参阅 docs/tutorials/rootless_tutorial.md;--network各模式的完整选项清单见 options/network.md,端口发布细节见 options/publish.md。
- 容器运行时
- 云原生
- CLI
【免费下载链接】podman
Podman: A tool for managing OCI containers and pods.
相关推荐
Podman 网络驱动选项 --driver 完全指南:bridge、macvlan、ipvlan 与 netavark 插件机制
Podman 网络驱动选项 driver 完全指南:bridge、macvlan、ipvlan 与 netavark 插件机制 driver (短选项 d )是
容器运行时云原生CLI突破容器网络限制:macvlan网络实战指南
突破容器网络限制:macvlan网络实战指南 一、容器网络的痛点与macvlan的价值 你是否遇到过容器需要直接接入物理网络的场景?传统的bridge模式下,容
云原生DevOpsDocker网络驱动对比:Bridge、Host、Macvlan等网络模式详解
Docker网络驱动对比:Bridge、Host、Macvlan等网络模式详解 在容器化部署中,网络配置往往是最令人头疼的环节——明明镜像和运行命令都正确,容器
云原生容器运行时虚拟化容器编排
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考