Docker Compose 部署:开发与测试环境的一键编排
coomia-dip 使用 Docker Compose 实现开发和测试环境的一键部署,编排 8 个 Layer 的 20+ 服务容器。设计支持多 Profile(minimal/standard/full)、服务依赖的健康检查、配置覆盖、数据卷管理和 GPU 支持。本文从编排架构、服务定义、网络设计、存储策略、环境管理到运维工具,完整解析 Docker Compose 部署方案。
Coomia发布于 2025年10月2日7 分钟阅读
分享本文Twitter / X
“系列:S6 平台工程 · 第 18 篇 | 难度:高级 | 阅读时间:18 分钟
Docker Compose 部署:开发与测试环境的一键编排
#TL;DR
coomia-dip 使用 Docker Compose 实现开发和测试环境的一键部署,编排 8 个 Layer 的 20+ 服务容器。设计支持多 Profile(minimal/standard/full)、服务依赖的健康检查、配置覆盖、数据卷管理和 GPU 支持。本文从编排架构、服务定义、网络设计、存储策略、环境管理到运维工具,完整解析 Docker Compose 部署方案。
#1. 编排架构
#1.1 服务拓扑
Code
┌──────────────────── Docker Compose ────────────────────┐
│ │
│ ┌─────────────────── Infrastructure ─────────────────┐ │
│ │ PostgreSQL │ Redis │ MinIO │ Kafka │ Nessie │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────── Control Layer (B) ─────────────────┐ │
│ │ ontology-service │ schema-registry │ auth-service │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────── Data Layer (C) ───────────────────┐ │
│ │ data-service │ iceberg-rest │ materialization │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────── Intelligence Layer (D/E) ────────────┐ │
│ │ reasoning-service │ agent-runtime │ temporal │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────── Platform (A) ─────────────────────┐ │
│ │ api-gateway │ platform-console │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
#1.2 多 Profile 支持
YAML
# docker-compose.yml
# Profile: minimal - 核心服务(开发调试)
# Profile: standard - 标准服务(集成测试)
# Profile: full - 完整服务(验收测试)
services:
# ========================
# Infrastructure Services
# ========================
postgres:
image: postgres:16-alpine
profiles: ["minimal", "standard", "full"]
environment:
POSTGRES_DB: coomia-dip
POSTGRES_USER: onto
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-onto_dev}
ports:
- "${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./deployment-Layer/init-scripts:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "pg_isready -U onto"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
profiles: ["minimal", "standard", "full"]
ports:
- "${REDIS_PORT:-6379}:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
minio:
image: minio/minio:latest
profiles: ["standard", "full"]
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD:-minioadmin}
ports:
- "${MINIO_PORT:-9000}:9000"
- "${MINIO_CONSOLE_PORT:-9001}:9001"
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 30s
timeout: 10s
retries: 3
kafka:
image: confluentinc/cp-kafka:7.5.0
profiles: ["standard", "full"]
environment:
KAFKA_NODE_ID: 1
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
CLUSTER_ID: "coomia-dip-dev"
ports:
- "${KAFKA_PORT:-9092}:9092"
volumes:
- kafka_data:/var/lib/kafka/data
nessie:
image: projectnessie/nessie:latest
profiles: ["standard", "full"]
environment:
NESSIE_VERSION_STORE_TYPE: JDBC
QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://postgres:5432/nessie
ports:
- "${NESSIE_PORT:-19120}:19120"
depends_on:
postgres:
condition: service_healthy
# ========================
# Control Layer (B)
# ========================
ontology-service:
build:
context: ./control-Layer/ontology-service
dockerfile: Dockerfile
profiles: ["minimal", "standard", "full"]
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/coomia-dip
SPRING_DATASOURCE_USERNAME: onto
SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD:-onto_dev}
SPRING_REDIS_HOST: redis
GRPC_SERVER_PORT: 9090
ports:
- "${ONTOLOGY_GRPC_PORT:-9090}:9090"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "grpc_health_probe", "-addr=:9090"]
interval: 15s
timeout: 5s
retries: 10
schema-registry:
build:
context: ./control-Layer/schema-registry
dockerfile: Dockerfile
profiles: ["minimal", "standard", "full"]
environment:
DATABASE_URL: postgresql://onto:${POSTGRES_PASSWORD:-onto_dev}@postgres:5432/coomia-dip
GRPC_PORT: 9091
ports:
- "${SCHEMA_GRPC_PORT:-9091}:9091"
depends_on:
postgres:
condition: service_healthy
auth-service:
build:
context: ./control-Layer/auth-service
dockerfile: Dockerfile
profiles: ["standard", "full"]
environment:
DATABASE_URL: postgresql://onto:${POSTGRES_PASSWORD:-onto_dev}@postgres:5432/coomia-dip
JWT_SECRET: ${JWT_SECRET:-dev-secret-key-change-in-prod}
ports:
- "${AUTH_GRPC_PORT:-9092}:9092"
depends_on:
postgres:
condition: service_healthy
# ========================
# Data Layer (C)
# ========================
data-service:
build:
context: ./data-Layer/data-service
dockerfile: Dockerfile
profiles: ["standard", "full"]
environment:
ICEBERG_CATALOG_URI: http://nessie:19120/api/v1
S3_ENDPOINT: http://minio:9000
S3_ACCESS_KEY: ${MINIO_USER:-minioadmin}
S3_SECRET_KEY: ${MINIO_PASSWORD:-minioadmin}
ports:
- "${DATA_GRPC_PORT:-9093}:9093"
depends_on:
nessie:
condition: service_started
minio:
condition: service_healthy
# ========================
# Intelligence Layer (D/E)
# ========================
reasoning-service:
build:
context: ./intelligence-Layer/reasoning-service
dockerfile: Dockerfile
profiles: ["standard", "full"]
environment:
ONTOLOGY_SERVICE_URL: ontology-service:9090
GRPC_PORT: 9094
ports:
- "${REASONING_GRPC_PORT:-9094}:9094"
depends_on:
ontology-service:
condition: service_healthy
agent-runtime:
build:
context: ./intelligence-Layer/agent-runtime
dockerfile: Dockerfile
profiles: ["full"]
environment:
TEMPORAL_HOST: temporal:7233
ONTOLOGY_SERVICE_URL: ontology-service:9090
depends_on:
temporal:
condition: service_started
ontology-service:
condition: service_healthy
temporal:
image: temporalio/auto-setup:latest
profiles: ["full"]
environment:
DB: postgresql
DB_PORT: 5432
POSTGRES_USER: onto
POSTGRES_PWD: ${POSTGRES_PASSWORD:-onto_dev}
POSTGRES_SEEDS: postgres
ports:
- "${TEMPORAL_PORT:-7233}:7233"
- "${TEMPORAL_UI_PORT:-8233}:8233"
depends_on:
postgres:
condition: service_healthy
# ========================
# Platform (A)
# ========================
api-gateway:
build:
context: ./deployment-Layer/api-gateway
dockerfile: Dockerfile
profiles: ["standard", "full"]
environment:
ONTOLOGY_SERVICE_URL: ontology-service:9090
SCHEMA_REGISTRY_URL: schema-registry:9091
AUTH_SERVICE_URL: auth-service:9092
ports:
- "${GATEWAY_HTTP_PORT:-8080}:8080"
- "${GATEWAY_GRPC_PORT:-8443}:8443"
depends_on:
ontology-service:
condition: service_healthy
platform-console:
build:
context: ./deployment-Layer/platform-console
dockerfile: Dockerfile
profiles: ["full"]
environment:
API_GATEWAY_URL: http://api-gateway:8080
ports:
- "${CONSOLE_PORT:-3000}:3000"
depends_on:
api-gateway:
condition: service_started
volumes:
postgres_data:
minio_data:
kafka_data:
networks:
default:
name: coomia-dip-network
#2. 网络设计
#2.1 服务发现
Docker Compose 内置 DNS 解析,服务通过容器名称互相发现:
Python
# 服务间通信使用容器名称
ONTOLOGY_SERVICE_URL = "ontology-service:9090"
SCHEMA_REGISTRY_URL = "schema-registry:9091"
#2.2 端口映射策略
| 服务 | 容器端口 | 默认主机端口 | 环境变量覆盖 |
|---|---|---|---|
| PostgreSQL | 5432 | 5432 | POSTGRES_PORT |
| Redis | 6379 | 6379 | REDIS_PORT |
| Ontology Service | 9090 | 9090 | ONTOLOGY_GRPC_PORT |
| API Gateway | 8080 | 8080 | GATEWAY_HTTP_PORT |
| Platform Console | 3000 | 3000 | CONSOLE_PORT |
#3. 健康检查策略
Python
class HealthCheckConfig:
"""健康检查配置策略"""
STRATEGIES = {
"postgres": {
"test": "pg_isready -U onto",
"interval": "10s",
"timeout": "5s",
"retries": 5,
},
"redis": {
"test": "redis-cli ping",
"interval": "10s",
"timeout": "5s",
"retries": 5,
},
"grpc_service": {
"test": "grpc_health_probe -addr=:PORT",
"interval": "15s",
"timeout": "5s",
"retries": 10,
},
"http_service": {
"test": "curl -f http://localhost:PORT/health",
"interval": "15s",
"timeout": "10s",
"retries": 5,
},
}
#4. 环境管理
#4.1 环境变量文件
Bash
# .env.development
POSTGRES_PASSWORD=onto_dev
JWT_SECRET=dev-secret-key
MINIO_USER=minioadmin
MINIO_PASSWORD=minioadmin
LOG_LEVEL=DEBUG
# .env.testing
POSTGRES_PASSWORD=onto_test
JWT_SECRET=test-secret-key
LOG_LEVEL=INFO
# .env.staging
POSTGRES_PASSWORD=${VAULT_POSTGRES_PASSWORD}
JWT_SECRET=${VAULT_JWT_SECRET}
LOG_LEVEL=WARN
#4.2 配置覆盖
YAML
# docker-compose.override.yml(开发覆盖)
services:
ontology-service:
volumes:
- ./control-Layer/ontology-service/src:/app/src # 源码映射(热重载)
environment:
SPRING_PROFILES_ACTIVE: dev
JAVA_OPTS: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
ports:
- "5005:5005" # 调试端口
reasoning-service:
volumes:
- ./intelligence-Layer/reasoning-service:/app
command: ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0"]
#5. 运维工具
#5.1 管理脚本
Bash
#!/bin/bash
# scripts/onto-dev.sh - 开发环境管理工具
case "$1" in
up)
PROFILE=${2:-standard}
echo "Starting coomia-dip with profile: $PROFILE"
docker compose --profile $PROFILE up -d
echo "Waiting for services to be healthy..."
docker compose --profile $PROFILE wait ontology-service
echo "Platform ready at http://localhost:8080"
;;
down)
docker compose --profile full down
;;
reset)
docker compose --profile full down -v
echo "All data volumes removed"
;;
logs)
SERVICE=${2:-""}
docker compose logs -f $SERVICE
;;
status)
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
;;
test)
docker compose --profile standard up -d
docker compose wait ontology-service
pytest tests/ -v
docker compose --profile standard down
;;
*)
echo "Usage: $0 {up|down|reset|logs|status|test} [profile|service]"
;;
esac
#5.2 初始化脚本
SQL
-- deployment-Layer/init-scripts/01-create-databases.sql
CREATE DATABASE nessie;
CREATE DATABASE temporal;
-- deployment-Layer/init-scripts/02-create-schemas.sql
\c coomia-dip;
CREATE SCHEMA IF NOT EXISTS ontology;
CREATE SCHEMA IF NOT EXISTS auth;
CREATE SCHEMA IF NOT EXISTS audit;
#6. GPU 支持
YAML
# docker-compose.gpu.yml(GPU 覆盖)
services:
reasoning-service:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
environment:
CUDA_VISIBLE_DEVICES: "0"
MODEL_DEVICE: "cuda"
#7. 测试策略
Python
class TestDockerCompose:
def test_minimal_profile_starts(self):
result = subprocess.run(
["docker", "compose", "--profile", "minimal", "up", "-d"],
capture_output=True,
)
assert result.returncode == 0
def test_services_healthy(self):
# 等待所有服务健康
result = subprocess.run(
["docker", "compose", "ps", "--format", "json"],
capture_output=True, text=True,
)
services = json.loads(result.stdout)
for svc in services:
if "Health" in svc:
assert svc["Health"] == "healthy"
def test_service_connectivity(self):
# 验证 gRPC 连通性
channel = grpc.insecure_channel("localhost:9090")
stub = OntologyServiceStub(channel)
response = stub.HealthCheck(HealthCheckRequest())
assert response.status == "SERVING"
#8. 生产最佳实践
#8.1 资源限制
YAML
services:
ontology-service:
deploy:
resources:
limits:
cpus: "2.0"
memory: 2G
reservations:
cpus: "0.5"
memory: 512M
#8.2 日志管理
YAML
services:
ontology-service:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
#8.3 安全建议
- 永远不要在 docker-compose.yml 中硬编码密码
- 使用 .env 文件管理敏感配置,确保 .env 在 .gitignore 中
- 生产环境使用 Docker Secrets 或外部密钥管理
- 限制暴露的端口范围
#9. 总结
coomia-dip 的 Docker Compose 部署方案通过多 Profile 和配置覆盖,实现了从最小开发环境到完整测试环境的灵活编排。关键设计亮点:
- 多 Profile:minimal/standard/full 三级配置
- 健康检查:所有服务配置健康检查,确保启动顺序
- 配置覆盖:环境变量 + override 文件的灵活配置
- 运维工具:一键启动/停止/重置/日志管理脚本
- GPU 支持:Intelligence Layer 的 GPU 加速配置
下一篇将探讨 coomia-dip 的 Kubernetes Operator 部署方案。