
Podman 下 docker-compose v2 集成测试套件全解析架构、运行机制与用例编写指南【免费下载链接】podmanPodman: A tool for managing OCI containers and pods.项目地址: https://gitcode.com/gh_mirrors/po/podman本篇技术指南聚焦于 Podman 仓库中位于 test/compose 的 docker-compose v2 集成测试目录它既是验证 Podman 与 docker-compose 兼容性的自动化测试框架也是开发者编写 Compose 兼容用例、复现和调试 compose 相关问题的实战参考。读完本文你将掌握该测试套件的目录规范、test-compose驱动脚本的完整执行流程、tests.sh断言写法以及如何利用COMPOSE_WAIT等调试手段深入排查失败用例。一、背景为什么需要一套 docker-compose 集成测试Podman 通过podman compose详见 cmd/podman/compose.go支持运行 docker-compose 编排的容器栈同时其内置的podman system service可以对外提供兼容 Docker 的 RESTful APIunix:///var/run/docker.sock这使得原生 docker-compose 客户端可以直接把 Podman 当作后端来驱动。正因如此Podman 仓库在 test/compose 下维护了一套完整的 docker-compose v2 集成测试它只面向 docker-compose v2。docker-compose v1 上游已停止维护Podman 不再对其进行测试每个测试子目录对应一个独立的 Compose 场景包含docker-compose.yml及全部所需基础设施Containerfile/Dockerfile、需要拷入容器的文件等整个框架由 test-compose 这一个 Bash 驱动脚本统一调度。这套测试的价值在于任何对 compose 兼容层、网络端口映射、/etc/hosts注入、IPAM、健康检查、CDI 设备等功能的改动都可以通过它快速获得端到端的回归验证。二、测试目录规范一个子目录 一个完整场景按照 README 的约定每个测试子目录必须包含一个docker-compose.yml——定义被测的 Compose 编排全部必要的基础设施——例如构建镜像用的Dockerfile/Containerfile、需要 COPY 进容器的源码文件等可选的辅助脚本——setup.sh在docker-compose up之前执行、teardown.sh在docker-compose down之后执行、tests.sh核心断言脚本被驱动脚本 source 执行可选的跳过标记——SKIP无条件跳过与SKIP_ROOT仅在 root 模式下跳过。仓库中现有的 14 个测试子目录覆盖了多类典型场景可以直接当作用例范本子目录覆盖能力simple_port_map将容器内端口映射到同一编号的宿主机端口5000:5000port_map_diff_port宿主机与容器端口号不同的映射5001:5000two_networks单个容器同时挂载两个 bridge 网络ipam_set_ip通过 IPAM 指定子网并为容器固定ipv4_address与mac_addressetc_hosts自定义hostname、网络别名以及/etc/hosts绑定挂载update_network_mtu网络 MTU 更新场景pasta_optspasta 网络后端相关选项root 模式下跳过disable_healthcheck禁用健康检查的 Compose 配置cdi_device通过device.json注入 CDI 设备env_and_volume环境变量透传与卷挂载的读写验证mount_and_label挂载与 SELinux 标签uptwice、uptwice_idempotent对同一编排重复up的幂等性三、test-compose 驱动脚本整体执行流程test-compose位于 test/compose/test-compose是整个测试套件的调度核心。对每一个测试子目录它依次执行以下步骤与 README 描述一致脚本第 324-416 行是具体实现准备全新的 Podman 存储根在mktemp生成的空工作目录WORKDIR下创建root、runroot、networks、cdi四个子目录脚本第 26 行与 206 行在该根目录下启动一个 Podman 服务端以system service --time 0方式运行监听 Docker 兼容 socket脚本第 209-220 行进入测试子目录执行docker-compose up -d通过辅助函数podman_compose调用脚本第 369 行source 执行tests.sh运行其中的断言脚本第 381-385 行执行docker-compose down清理脚本第 394 行。此外脚本在进入子目录前会以source方式执行setup.sh在down之后执行teardown.shREADME 特别说明由于是 source 执行setup.sh中定义的变量可以回流到脚本环境这也解释了为何 setup.sh.example 中使用export导出变量而 teardown.sh.example 负责将其清理。3.1 服务端启动细节隔离的存储与网络脚本第 209-220 行启动服务端的关键参数值得注意$PODMAN_BIN \ --log-level debug \ --storage-drivervfs \ --root $WORKDIR/root \ --runroot $WORKDIR/runroot \ --cgroup-managersystemd \ --network-config-dir $WORKDIR/networks \ --cdi-spec-dir $WORKDIR/cdi \ system service \ --time 0 unix://$DOCKER_SOCK \ $WORKDIR/server.log 存储驱动固定为vfs规避了不同宿主机文件系统差异--network-config-dir与--cdi-spec-dir指向隔离目录确保测试不污染宿主网络配置与 CDI 规范--time 0表示服务不会因空闲超时自动退出所有日志写入server.log供失败时回溯test_port的 curl 失败分支就会打印该文件内容。3.2 Root 与 Rootless 双模式脚本用is_rootlessid -u是否为 0第 48-50 行区分两种运行模式两种模式在 socket 与客户端连接方式上有显著差异Root 模式直接复用/var/run/docker.sock并导出DOCKER_HOSTunix://$DOCKER_SOCK供 docker-compose 使用脚本第 294-297 行Rootless 模式socket 位于$WORKDIR/docker.sock并通过PODMAN_CONNECTIONS_CONF指向隔离的connections.json避免覆盖用户自身配置预先注册两个连接——默认连接notexists与真实连接compose-sock脚本第 284-291 行此时podman_compose会使用podman --connection compose-sock compose第 253-258 行。Rootless 模式下的各种清理操作rm -rf、umount等都会经由$PODMAN_BIN unshare执行确保在正确的用户命名空间中操作。3.3 跳过机制与 TAP 输出若测试目录存在SKIP文件该测试被无条件跳过文件内容作为跳过原因脚本第 328-334 行若存在SKIP_ROOT文件且当前为 root 模式同样跳过第 337-344 行例如 pasta_opts/SKIP_ROOT输出采用TAP version 13格式脚本第 322 行末尾输出1..N汇总测试总数使结果可被 CI 日志格式化工具识别。3.4 基础设施函数测试断言与辅助工具脚本还提供了一组可被tests.sh直接调用的函数第 43-271 行的 infrastructure 区段test_port port op expect对http://127.0.0.1:port/发起 curl带--retry 3 --retry-all-errors容忍启动延迟再按操作符断言结果is/like等值比较与expr子串匹配like在等值失败后回退到expr $actual : .*$expectpodman以相同的隔离参数调用真实 podman 二进制供个别用例检查容器标签、状态等输出会追加到output.lograndom_string从/dev/urandom生成随机字符串供setup.sh构造随机的环境变量值。四、编写 tests.shtest_port断言语法README 给出了tests.sh最核心的断言形式test_port 12345 hello there三个参数的含义对应脚本第 165-189 行的实现12345要 curl 的宿主机端口比较操作符表示 curl 返回内容与期望字符串完全相等~表示用expr做子串匹配常用于只需包含关键字、不关心前后文的情况hello there期望在 curl 结果中出现或相等的字符串。以 simple_port_map/tests.sh 为真实范例# -*- bash -*- test_port 5000 Podman rulez!配合 simple_port_map/frontend/Dockerfile基于 Alpine 安装py3-flask并运行app.py与 docker-compose.ymlports: [5000:5000]这条断言验证的是容器内 Flask 服务通过5000:5000端口映射暴露后宿主机curl http://localhost:5000/能精确返回预期文本。tests.sh里还可以混用podman辅助函数做更细粒度的状态检查如容器标签、运行状态README 中明确说明这一点may also include podman commands to inspect labels, state。五、setup.sh 与 teardown.sh前后置钩子setup.sh与teardown.sh是可选的按 README 约定分别在docker-compose up之前与docker-compose down之后执行。由于驱动脚本以source方式加载它们脚本第 363-367 行其中export的变量会延续到后续的 compose 命令环境。仓库中的真实例子etc_hosts/setup.sh通过mount --bind将测试自带的hosts文件绑定挂载到/etc/hostsrootless 下走podman unshare从而为容器提供自定义 hosts 内容teardown.sh负责卸载setup.sh.example 与 teardown.sh.example演示用random_string生成随机环境变量并在结束时清理。六、运行与调试6.1 基本用法README 给出的标准调用方式是$ sudo test/compose/test-compose [pattern]不带参数时运行所有测试子目录传入 pattern 时只运行目录名能匹配*pattern*的子目录脚本第 302-316 行通过${TEST_ROOTDIR}/*${i}*/docker-compose.yml展开无匹配时直接报错退出运行前脚本会做前置检查第 275-277 行宿主机必须已安装curl与docker-compose要求环境中已有编译好的 podman 二进制脚本固定使用../../bin/podman见第 15 行。例如只跑端口映射相关用例$ sudo test/compose/test-compose port_map6.2 用 COMPOSE_WAIT 调试失败用例当某个用例失败时docker-compose down会立即销毁现场给调试带来困难。README 给出的调试手法是设置COMPOSE_WAIT使脚本在down之前暂停脚本第 388-391 行会提示 Pausing due to $COMPOSE_WAIT 并等待回车$ env COMPOSE_WAIT1 sudo --preserve-envCOMPOSE_WAIT test/compose/test-compose暂停期间在另一个终端找到最新的工作目录ls -lt /var/tmp/中形如test-compose.tmp.XXXXXX的最新条目即WORKDIR然后以完全相同的隔离参数手动执行 podman 命令排查现场# X/var/tmp/test-compose.tmp.XXXXXX --- 上述最新结果 # podman --root $X/root --runroot $X/runroot ps -a # podman --root $X/root --runroot $X/runroot logs -l手动带--root/--runroot指定存储根后就可以绕过服务端 socket 直接查看容器状态与日志。除此之外脚本还会把每次 HTTP 请求/响应的完整记录写入$TMPDIR/test-compose.log及带时间戳的副本第 29-31 行服务端日志则在$WORKDIR/server.log这两处都是定位 curl 失败或启动异常的第一手资料。6.3 保留工作目录若需在测试结束后进一步分析或避免 rootless 下unshare rm -rf的清理可设置PODMAN_TESTS_KEEP_WORKDIR脚本将跳过工作目录清理第 426-432 行。七、从源码看整体设计要点结合 test-compose 的完整实现可以总结出该测试套件的几个设计要点完全隔离每个测试都用独立的--root/--runroot存储树和网络配置目录测试之间互不干扰也不会污染宿主 Podman 数据面向真实客户端测试驱动的是真正的 docker-compose v2 二进制通过 Docker 兼容 socket 走完整 HTTP API 链路而非 Podman 内部函数调用因此能真实反映用户在宿主机上docker compose up的体验双模式覆盖同一套用例在 root 与 rootless 两种模式下运行验证 socket 路径、--connection切换、unshare清理等路径差异TAP 兼容输出统一的ok/not ok计数与1..N汇总方便接入 CI 日志工具失败可观测server.log、output.log、HTTP 请求日志、COMPOSE_WAIT暂停钩子构成了完整的失败排查链路。八、扩展如何新增一个测试场景在 test/compose 下新增场景时遵循以下步骤即可与框架无缝集成新建一个子目录如my_scenario/编写docker-compose.yml定义服务与网络若服务需要构建镜像提供Dockerfile/Containerfile及必要的应用文件参考 simple_port_map/frontend 的结构编写tests.sh用test_port port expect或test_port port ~ substring断言结果必要时混用podman函数检查状态如需前置/后置动作添加setup.sh与teardown.sh若该场景在某些环境不适用添加SKIP带原因或SKIP_ROOT标记文件用sudo test/compose/test-compose my_scenario单独验证。结语test/compose 这套 docker-compose v2 集成测试框架是理解 Podman 如何承接 Docker 生态编排工作流的最佳切入点之一。无论是想验证某个 compose 配置在 Podman 下的行为、为 compose 兼容性提交回归用例还是排查podman compose相关的疑难问题掌握test-compose的目录规范、执行流程与test_port断言语法都能让你事半功倍。其隔离存储 真实 compose 客户端 TAP 输出 可暂停调试的设计模式本身也是编写容器编排集成测试的一套值得借鉴的范本。【免费下载链接】podmanPodman: A tool for managing OCI containers and pods.项目地址: https://gitcode.com/gh_mirrors/po/podman创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考