4. Docker Compose 编排:docker-compose.yml 编写、多服务部署与环境变量管理

在授权测试与数据传输优化的实际场景中,单一容器往往无法满足完整的测试链路需求。例如,一个典型的授权测试环境需要同时运行 授权服务、测试客户端、数据存储 以及 网络代理 等多个组件。Docker Compose 通过声明式的 docker-compose.yml 文件,允许你一键定义、启动和编排这些相互依赖的服务,从而构建可复现、可隔离的测试环境。

4.1 docker-compose.yml 核心结构

一个标准的 docker-compose.yml 文件遵循 YAML 语法,主要包含 version、services、networks 和 volumes 四个顶级字段。以下是一个针对授权测试场景的基础模板:

version: '3.8'

services:
  # 授权服务:模拟 OAuth2 授权服务器
  auth-server:
    image: your-registry/auth-server:latest
    container_name: auth-server
    ports:
      - "9000:9000"
    environment:
      - DB_HOST=postgres-db
      - DB_PORT=5432
      - AUTH_JWT_SECRET=${JWT_SECRET}
    depends_on:
      postgres-db:
        condition: service_healthy
    networks:
      - test-net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # 测试客户端:发起授权请求并验证响应
  test-client:
    image: your-registry/test-client:latest
    container_name: test-client
    environment:
      - AUTH_ENDPOINT=http://auth-server:9000
      - TEST_SCENARIO=${TEST_SCENARIO:-basic}
    depends_on:
      auth-server:
        condition: service_started
    networks:
      - test-net
    command: ["python", "run_tests.py"]

  # 数据库:存储授权令牌与审计日志
  postgres-db:
    image: postgres:15-alpine
    container_name: postgres-db
    environment:
      POSTGRES_USER: test_user
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: auth_test_db
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init-scripts:/docker-entrypoint-initdb.d
    networks:
      - test-net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U test_user -d auth_test_db"]
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  test-net:
    driver: bridge

volumes:
  pgdata:
    driver: local
关键字段说明:
  • depends_on:控制服务启动顺序,结合 condition 可实现更精细的依赖等待(如等待健康检查通过)。
  • healthcheck:为服务定义自定义健康检查,避免在服务未就绪时启动依赖服务。
  • networks:将服务隔离在自定义网络中,服务间通过服务名(如 auth-server)直接通信,无需暴露端口到宿主机。

4.2 多服务部署与网络拓扑

在授权测试中,服务间的网络拓扑直接影响测试的隔离性与安全性。下图展示了使用 Docker Compose 编排的典型授权测试环境网络架构:

授权测试环境 Docker Compose 网络拓扑 外部测试请求 (宿主机/CI 触发) 自定义网络:test-net (bridge) auth-server 端口 9000 OAuth2 授权服务 test-client 无端口暴露 自动化测试执行器 postgres-db 端口 5432 令牌与审计日志存储 pgdata (Volume) 持久化存储 数据不随容器销毁 HTTP 请求 授权响应 读写令牌 数据持久化 网络通信规则: 1. 所有服务通过服务名(如 auth-server)在 test-net 内通信,无需关心 IP 变化。 2. 只有 auth-server 暴露端口 9000 给宿主机,test-client 和 postgres-db 对外不可见。 3. 数据卷 pgdata 确保数据库重启后数据不丢失,适合长期测试场景。
多服务部署最佳实践:
  • 服务拆分原则:每个容器只运行一个进程,授权服务、数据库、测试客户端应拆分为独立服务。
  • 依赖管理:使用 depends_on + healthcheck 组合,避免启动竞争条件。
  • 网络隔离:为敏感服务(如数据库)不暴露端口到宿主机,仅通过内部网络访问。

4.3 环境变量管理策略

在授权测试中,环境变量用于管理敏感信息(如 JWT 密钥、数据库密码)和测试配置(如测试场景、端点地址)。Docker Compose 提供多种方式注入环境变量,以下表格对比了常用方法:

方法 语法示例 适用场景 安全等级
硬编码 environment: - KEY=value 固定不变的测试配置(如服务端口) 低(明文暴露)
引用宿主变量 environment: - KEY=${HOST_VAR} 从 CI/CD 环境或本地 Shell 传入 中(依赖宿主安全)
.env 文件 在 docker-compose.yml 同级目录创建 .env 文件 多环境配置(开发/测试/生产) 中(需将 .env 加入 .gitignore)
Docker Secrets secrets: - db_password + secrets: db_password: file: ./secrets/db_password.txt 高敏感信息(数据库密码、JWT 私钥) 高(仅挂载到内存,不写入环境变量)
安全警告:在授权测试场景中,JWT 密钥、数据库密码等敏感信息严禁硬编码在 docker-compose.yml 中。推荐使用 .env 文件配合 .gitignore 管理,或使用 Docker Secrets 进行生产级保护。

4.4 环境变量作用域与优先级

当多种环境变量注入方式同时存在时,Docker Compose 遵循明确的优先级规则。理解这一规则有助于避免配置冲突:

Docker Compose 环境变量优先级(从高到低) 1. docker-compose run -e KEY=value (运行时覆盖) 2. docker-compose.yml 中 environment: 字段 3. Shell 环境变量 (export KEY=value) 4. .env 文件中的变量 注意:如果 .env 文件中未定义某变量,且 Shell 环境也未导出,Compose 会将其解析为空字符串。

4.5 实际授权测试场景的 Compose 配置示例

以下是一个完整的 docker-compose.yml 示例,集成了环境变量管理与多服务编排,适用于 OAuth2 授权码模式 的自动化测试:

version: '3.8'

services:
  # 授权服务器(模拟 Keycloak / 自定义 OAuth2 服务)
  auth-server:
    image: quay.io/keycloak/keycloak:22.0.1
    container_name: auth-server
    environment:
      KC_HOSTNAME: auth-server
      KC_HTTP_PORT: 9000
      KC_DB_URL_HOST: postgres-db
      KC_DB_URL_DATABASE: auth_test_db
      KC_DB_USERNAME: test_user
      KC_DB_PASSWORD: ${DB_PASSWORD}
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
    ports:
      - "9000:9000"
    depends_on:
      postgres-db:
        condition: service_healthy
    networks:
      - test-net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/health/ready"]
      interval: 30s
      timeout: 10s
      retries: 5

  # 测试客户端(使用 Python + requests 库执行授权流程)
  test-client:
    build:
      context: ./test-client
      dockerfile: Dockerfile
    container_name: test-client
    environment:
      AUTH_SERVER_URL: http://auth-server:9000
      CLIENT_ID: ${TEST_CLIENT_ID}
      CLIENT_SECRET: ${TEST_CLIENT_SECRET}
      REDIRECT_URI: http://localhost:8080/callback
      TEST_SCOPE: "openid profile email"
    depends_on:
      auth-server:
        condition: service_healthy
    networks:
      - test-net
    volumes:
      - ./test-results:/app/results
    command: ["pytest", "tests/", "--junitxml=/app/results/report.xml"]

  # 数据库
  postgres-db:
    image: postgres:15-alpine
    container_name: postgres-db
    environment:
      POSTGRES_USER: test_user
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: auth_test_db
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - test-net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U test_user -d auth_test_db"]
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  test-net:
    driver: bridge

volumes:
  pgdata:
    driver: local
启动与测试命令:
  • 启动所有服务:docker compose --env-file .env.test up -d
  • 仅运行测试客户端(不重启其他服务):docker compose run --rm test-client
  • 查看服务日志:docker compose logs -f auth-server test-client
  • 清理环境:docker compose down -v(-v 会同时删除数据卷)

4.6 常见问题与避坑指南

问题 原因 解决方案
服务启动顺序错误 仅使用 depends_on 未配合 condition 添加 condition: service_healthy 并定义 healthcheck
环境变量未生效 .env 文件未放在 Compose 文件同级目录,或变量名拼写错误 使用 docker compose config 检查解析后的配置
容器间无法通信 服务未加入同一自定义网络,或使用了 localhost 而非服务名 确保所有服务在 networks 中指定同一网络,使用服务名作为主机名
数据卷权限问题 容器内进程以非 root 用户运行,但数据卷目录权限不足 在 Dockerfile 中设置 USER 并确保数据卷目录可写,或使用 chmod
调试技巧:当 Compose 编排出现异常时,优先使用 docker compose config 验证最终配置,该命令会输出解析环境变量后的完整 YAML,帮助快速定位变量注入问题。