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 编排的典型授权测试环境网络架构:
多服务部署最佳实践:
- 服务拆分原则:每个容器只运行一个进程,授权服务、数据库、测试客户端应拆分为独立服务。
- 依赖管理:使用
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 遵循明确的优先级规则。理解这一规则有助于避免配置冲突:
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,帮助快速定位变量注入问题。