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 编排下各服务的启动顺序与依赖关系:

Docker Compose 服务依赖与启动顺序 Docker Compose 服务依赖与启动顺序 docker-compose up postgres-test (健康检查) app-under-test (依赖就绪) 集成测试执行 依赖条件 • depends_on: service_healthy • 内部 DNS 服务发现 • 自定义网络隔离

4.6 服务间通信与网络隔离 SVG

在隔离测试环境中,服务间通信通过 Compose 内部 DNS 完成,无需暴露所有端口到宿主机。下图展示了网络隔离与通信路径:

服务间通信与网络隔离 服务间通信与网络隔离 test-net (bridge) postgres-test :5432 app-under-test :8080 mock-external :1080 JDBC HTTP 宿主机 → localhost:8080

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,测试完成后自动销毁容器,避免残留进程影响后续任务。