- 容器运行时
- 云原生
- CLI
【免费下载链接】podman
Podman: A tool for managing OCI containers and pods.
容器接入多个网络是 Compose 工作负载中常见的拓扑需求(例如业务网络与存储网络分离、服务同时暴露在管理网与业务网)。本文以 Podman 仓库中的 compose 集成测试用例two_networks为主线,完整讲解其配置写法、验证命令、底层数据结构与测试框架的运行机制,帮助你掌握"如何用 Compose 定义多网络服务"以及"如何在 Podman 上可靠地验证容器确实同时处于多个网络"。
一、测试用例定位:它在验证什么
在 Podman 仓库中,test/compose/目录下存放着一组针对 docker-compose v2 的集成测试,每个子目录对应一个独立场景。test/compose/two_networks/Readme.md是该用例的说明文档,全文虽短,但定义了一个非常明确的验收标准:
- 测试目的:验证 Podman 能够创建同时接入不止一个网络(more than one network)的容器;
- 验收命令:
podman container inspect two_networks_con1_1 --format '{{len .NetworkSettings.Networks}}'- 期望结果:输出
2,即该容器的NetworkSettings.Networks中记录了 2 个网络。
这一条命令是整个用例的灵魂:它通过 Go template 对podman container inspect的 JSON 输出取长度,从而断言容器同时连接到了两个网络。相关文件包括:
- test/compose/two_networks/Readme.md
- test/compose/two_networks/docker-compose.yml
- test/compose/two_networks/tests.sh
二、Compose 配置:让一个服务加入两个网络
two_networks用例的docker-compose.yml是完整的、可复现的示例(约 12 行),其核心写法如下:
version: '3' services: con1: image: alpine command: top networks: - net1 - net2 networks: net1: net2:拆解这个配置:
| 片段 | 作用 | 说明 |
|---|---|---|
services.con1.image: alpine | 使用基础镜像 | alpine体积小,适合作为常驻进程测试载体 |
services.con1.command: top | 让容器保持前台运行 | 避免容器因无前台进程而立即退出,top保证容器处于运行态 |
services.con1.networks: [net1, net2] | 声明服务接入多个网络 | 这是"多网络"的关键——在同一服务下罗列两个网络名 |
networks.net1 / net2 | 顶层网络定义 | Compose 会自动为每个顶层网络创建对应的 Podman 网络 |
要点:在 Compose 规范中,一个服务(service)的networks字段是一个列表,列出该服务要加入的全部网络;顶层networks段则声明这些网络的属性(此处为空,表示使用默认配置)。Compose 将按项目名_网络名的规则为网络命名,这也是后面测试断言中网络名前缀为two_networks_的原因。
三、验证逻辑:inspect 与 Go template 的用法
测试用例的核心验证逻辑位于 test/compose/two_networks/tests.sh,它比 Readme 中的单条命令更完整,共包含三步断言:
# -*- bash -*- ctr_name="two_networks-con1-1" podman container inspect "$ctr_name" --format '{{len .NetworkSettings.Networks}}' is "$output" "2" "$testname : Container is connected to both networks" podman container inspect "$ctr_name" --format '{{.NetworkSettings.Networks}}' like "$output" "two_networks_net1" "$testname : First network name exists" like "$output" "two_networks_net2" "$testname : Second network name exists"逐步解读:
- 容器名约定:Compose 项目名取自目录名
two_networks,服务名con1的实例默认命名为<项目名>-<服务名>-<序号>,因此这里用two_networks-con1-1。(注意:Readme 中写的是two_networks_con1_1,带下划线;tests.sh 中实际使用的是带连字符的two_networks-con1-1,这与 docker-compose v2 的实际命名规则一致,后者才是运行时真正生效的容器名。) - 数量断言:
{{len .NetworkSettings.Networks}}对 inspect JSON 中的NetworkSettings.Networks映射取元素个数,is断言其严格等于2,证明容器同时连接了两个网络。 - 成员断言:
{{.NetworkSettings.Networks}}直接打印整个网络映射,like断言输出中同时包含two_networks_net1与two_networks_net2两个网络名,证明连接的是正确的、预期的两个网络(而非任意两个)。
这一"先验数量、再验成员"的验证模式在整个 Podman 测试体系中反复出现。例如 test/e2e/network_connect_disconnect_test.go 中同样使用--format '{{len .NetworkSettings.Networks}}'来断言网络连接/断开后容器所连网络的数量变化,还进一步使用{{(index .NetworkSettings.Networks "网络名").Aliases}}与DNSNames验证单个网络的别名与 DNS 记录——如果你想做更细粒度的多网络验证(如确认每个网络内的别名、DNS 解析),可以参考该文件的写法。
四、底层数据结构:NetworkSettings.Networks 从哪来
{{len .NetworkSettings.Networks}}之所以能工作,是因为podman container inspect的输出结构在源码中有明确定义。在 libpod/define/container_inspect.go 中:
// InspectNetworkSettings holds information about the network settings of the // container. // Many fields are maintained only for compatibility with `docker inspect` and // are unused within Libpod. type InspectNetworkSettings struct { InspectBasicNetworkConfig Bridge string `json:"Bridge"` SandboxID string `json:"SandboxID"` HairpinMode bool `json:"HairpinMode"` LinkLocalIPv6Address string `json:"LinkLocalIPv6Address"` LinkLocalIPv6PrefixLen int `json:"LinkLocalIPv6PrefixLen"` Ports map[string][]InspectHostPort `json:"Ports"` SandboxKey string `json:"SandboxKey"` // Networks contains information on non-default networks this // container has joined. // It is a map of network name to network information. Networks map[string]*InspectAdditionalNetwork `json:"Networks,omitempty"` }从中可以得到几个关键事实:
Networks是一个以网络名为 key的 map,{{len .NetworkSettings.Networks}}得到的就是容器所加入网络的个数;- 该结构刻意保持与
docker inspect输出兼容(源码注释明确说明"Many fields are maintained only for compatibility withdocker inspect"),因此对 Docker 用户而言字段语义可直接迁移; - 每个网络的值类型是
InspectAdditionalNetwork,其中包含该网络下容器的别名(Aliases)、DNS 名称(DNSNames)、静态 IP/MAC 等信息——这正是 e2e 测试中用(index .NetworkSettings.Networks "net").Aliases取单网络细节的原因。
从源码结构可以推断:只要容器通过任何方式(Compose 编排、podman network connect、--network多网络参数)加入了多个网络,这些网络都会以"网络名 → 网络详情"的条目出现在NetworkSettings.Networks中,因此len的返回值能作为"多网络"是否成立的通用判据。
五、测试框架:test-compose 如何运行该用例
two_networks不是孤立脚本,而是由 test/compose/test-compose 统一驱动的用例之一。根据 test/compose/README.md 与脚本实现,其运行流程为:
- 在临时工作目录下建立全新的 Podman root/runroot;
- 以
podman system service --time 0 unix://$DOCKER_SOCK方式启动一个基于本地 Unix socket 的 Podman API 服务; cd进入用例子目录,执行docker-compose up -d(后台拉起服务);source该目录下的tests.sh,执行其中的断言(即上一节的 inspect 校验);- 执行
docker-compose down清理,然后杀掉 API 服务进程。
运行方式(默认运行所有 compose 用例,也可用模式限定单个用例):
$ sudo test/compose/test-compose [pattern]例如只跑本用例:
$ sudo test/compose/test-compose two_networks脚本还针对 rootless 场景做了适配:rootless 下会把 Docker socket 放到工作目录内,并通过podman system connection add compose-sock "unix://$DOCKER_SOCK"注册连接、设置PODMAN_CONNECTIONS_CONF以免覆盖用户配置,再以podman --connection compose-sock compose ...驱动 compose provider。脚本默认导出PODMAN_COMPOSE_WARNING_LOGS=false,以避免 compose provider 的引擎提示干扰对 stderr 的断言。
调试技巧:设置COMPOSE_WAIT=1可让脚本在执行down之前暂停,方便你在另一个终端里用独立 root 检查容器状态:
$ env COMPOSE_WAIT=1 sudo --preserve-env=COMPOSE_WAIT test/compose/test-compose two_networks # 另一个终端: # podman --root $X/root --runroot $X/runroot ps -a # podman --root $X/root --runroot $X/runroot logs -l六、前置知识:podman compose 是什么
要理解为什么该用例能用docker-compose up -d驱动 Podman,需要知道podman compose的本质。在 cmd/podman/compose.go 中,compose命令被明确定义为:
"a thin wrapper around an external compose provider such as docker-compose or podman-compose"(对外部 compose provider 的薄封装)
也就是说,Podman 本身并不实现 Compose 编排逻辑,而是:
- 按顺序查找可用的外部 provider(默认候选为
docker-compose、podman-compose,docker-compose 优先);也可通过环境变量PODMAN_COMPOSE_PROVIDER或 containers.conf 的[engine]表中compose_providers字段指定; - 在调用 provider 前注入环境变量:将
DOCKER_HOST指向本地 Podman API socket(unix://默认地址或podman machine连接),并设置DOCKER_BUILDKIT=0(Podman 不追踪全部 buildkit 特性)、透传DOCKER_CONFIG; - 把
podman compose之后的所有参数原样透传给外部 provider,并将 provider 的退出码作为自己的退出码返回。
正是这种"环境重定向 + 参数透传"机制,让 docker-compose v2 可以把网络创建、容器启动等 API 调用全部落到 Podman 上,从而让"容器接入多个 Compose 网络"在 Podman 下成为现实。这也解释了本用例为什么命名为"two networks"集成测试:它在验证 Docker Compose 的多网络语义在 Podman 兼容层上的端到端表现。
七、手动复现与扩展验证
不借助测试框架,你也可以手动复现该用例的完整链路:
# 1. 创建项目目录与配置文件 mkdir -p ~/two_networks_demo && cd ~/two_networks_demo # 内容即上文第二节的 docker-compose.yml # 2. 启动服务 podman compose up -d # 3. 执行与 Readme 一致的验收命令,期望输出 2 podman container inspect two_networks-con1-1 --format '{{len .NetworkSettings.Networks}}' # 4. 查看容器实际接入的网络明细 podman container inspect two_networks-con1-1 --format '{{.NetworkSettings.Networks}}' # 5. 清理 podman compose down如果需要进一步验证每个网络内的细节,可参考 e2e 测试的写法(见第三节),使用index语法按网络名取值:
podman container inspect two_networks-con1-1 \ --format '{{(index .NetworkSettings.Networks "two_networks_net1").Aliases}}' podman container inspect two_networks-con1-1 \ --format '{{(index .NetworkSettings.Networks "two_networks_net1").DNSNames}}'八、小结
two_networks这个看似只有两行说明的用例,实际覆盖了一条完整的验证链:Compose 侧通过networks列表声明多网络,Podman 兼容层通过注入DOCKER_HOST承接 docker-compose 的网络 API,容器运行时把多个网络记录进NetworkSettings.Networks,测试侧则用{{len .NetworkSettings.Networks}}与{{.NetworkSettings.Networks}}分别验证"数量为 2"与"成员为预期的两个网络"。阅读本文后,你既能照抄它的配置与命令完成自己的多网络容器验证,也能顺着 test/compose/test-compose、cmd/podman/compose.go 与 libpod/define/container_inspect.go 三条源码线索,理解这一能力从编排到 inspect 的完整实现路径。
- 容器运行时
- 云原生
- CLI
【免费下载链接】podman
Podman: A tool for managing OCI containers and pods.
相关推荐
compiledb完全指南:从安装到高级配置的完整攻略
compiledb完全指南:从安装到高级配置的完整攻略 compiledb是一款强大的Clang JSON编译数据库生成工具,专为基于GNU make的构建系统
如何用OpenCore Legacy Patcher为老款Mac安装最新macOS:终极指南
如何用OpenCore Legacy Patcher为老款Mac安装最新macOS:终极指南 想让你的老款Mac电脑重新焕发活力,运行最新的macOS系统吗?O
操作系统固件驱动开发Podman 下用 docker-compose 验证 Bind Mount 与容器 Label 的实战测试解析
Podman 下用 docker compose 验证 Bind Mount 与容器 Label 的实战测试解析 导读 本文基于 Podman 仓库中的 tes
容器运行时云原生CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考