4. Docker Compose 编排多服务:docker-compose.yml 结构、定义 PostgreSQL 服务、定义应用服务
在 Mock 依赖隔离集成测试环境中,Docker Compose 是串联 PostgreSQL 数据库与被测应用的核心编排工具。通过一份 docker-compose.yml 文件,可以同时定义数据库服务、应用服务以及它们之间的网络、依赖和健康检查关系,实现“一条命令启动完整测试环境”。
4.1 docker-compose.yml 标准结构
一个用于集成测试的 Compose 文件通常包含以下顶层键:
| 顶层键 | 用途 | 是否必选 |
|---|---|---|
version |
声明 Compose 文件格式版本(推荐 "3.8" 或更高) |
是 |
services |
定义所有容器化服务(数据库、应用、Mock 服务等) | 是 |
networks |
自定义容器间通信网络,隔离测试环境 | 推荐 |
volumes |
持久化数据或挂载配置文件 | 按需 |
测试环境关键原则: 每个测试套件应使用独立的 Compose 项目名称(通过
-p 参数或目录名区分),避免并行运行时端口冲突与数据污染。
4.2 定义 PostgreSQL 服务
PostgreSQL 服务是测试环境的“数据底座”。定义时需要关注镜像版本、端口映射、环境变量、健康检查以及临时存储。以下是一个生产级测试用 PostgreSQL 服务定义:
services:
postgres-test:
image: postgres:16-alpine
container_name: mocktest-db
restart: unless-stopped
environment:
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_pass
POSTGRES_DB: integration_test
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U test_user -d integration_test"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
volumes:
- pg_test_data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d:ro
networks:
- test-net
关键参数说明:
- image: 使用
alpine变体以减小镜像体积,加速拉取。 - healthcheck: 通过
pg_isready检测数据库就绪状态,应用服务依赖此检查。 - volumes: 命名卷
pg_test_data保证数据持久化;init-scripts挂载初始化 SQL 脚本。 - networks: 加入自定义网络,与服务发现名称解耦。
Mock 测试最佳实践: 在
init-scripts 目录中放置建表、插入测试种子数据的 SQL 文件。Compose 启动时会按文件名顺序自动执行,确保应用启动时数据已就绪。
4.3 定义应用服务
应用服务是待测系统在容器中的化身。它必须依赖 PostgreSQL 服务就绪后才能启动,并通过环境变量或配置文件获取数据库连接信息。典型定义如下:
services:
app-under-test:
build:
context: ./app
dockerfile: Dockerfile.test
container_name: mocktest-app
depends_on:
postgres-test:
condition: service_healthy
environment:
DB_HOST: postgres-test
DB_PORT: 5432
DB_USER: test_user
DB_PASSWORD: test_pass
DB_NAME: integration_test
MOCK_SERVER_URL: http://mock-external:1080
ports:
- "8080:8080"
volumes:
- ./app/coverage:/app/coverage
networks:
- test-net
应用服务定义要点:
- depends_on + condition: service_healthy: 确保数据库健康后才启动应用,避免连接重试风暴。
- 环境变量注入: 使用服务名
postgres-test作为主机名,Compose 内部 DNS 自动解析。 - Mock 服务地址: 应用通过
MOCK_SERVER_URL指向另一个 Mock 服务(如 MockServer 或 WireMock),实现外部依赖隔离。 - 覆盖率挂载: 将容器内的覆盖率报告输出到宿主机,便于 CI 收集。
4.4 完整编排与网络定义
将上述服务组合到一份 Compose 文件中,并显式定义网络与卷:
version: "3.8"
services:
postgres-test:
# ...(如上定义)
app-under-test:
# ...(如上定义)
mock-external:
image: mockserver/mockserver:latest
container_name: mocktest-mock
environment:
MOCKSERVER_PROPERTY_FILE: /config/mockserver.properties
volumes:
- ./mock-config:/config:ro
networks:
- test-net
networks:
test-net:
driver: bridge
volumes:
pg_test_data:
端口冲突防范: 在 CI 并行执行时,不同测试套件可能同时启动 Compose。建议将宿主机映射端口改为动态分配(如
"0:5432"),或通过环境变量 COMPOSE_PROJECT_NAME 区分项目,避免端口占用导致测试失败。
4.5 服务依赖与启动顺序 SVG
下图展示了 Compose 编排下各服务的启动顺序与依赖关系:
4.6 服务间通信与网络隔离 SVG
在隔离测试环境中,服务间通信通过 Compose 内部 DNS 完成,无需暴露所有端口到宿主机。下图展示了网络隔离与通信路径:
4.7 常用命令速查表
| 操作 | 命令 | 说明 |
|---|---|---|
| 启动所有服务 | docker compose up -d |
后台运行,保持终端可用 |
| 查看服务日志 | docker compose logs -f app-under-test |
实时跟踪应用日志 |
| 执行数据库初始化 | docker compose exec postgres-test psql -U test_user -d integration_test -f /init.sql |
手动触发初始化脚本 |
| 停止并清理 | docker compose down -v |
删除容器、网络和命名卷 |
| 指定项目名称 | docker compose -p mytest up -d |
避免并行测试冲突 |
CI 集成建议: 在 CI 流水线中,使用
docker compose run --rm app-under-test 替代 up,测试完成后自动销毁容器,避免残留进程影响后续任务。