返回博客

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 端口映射策略

服务容器端口默认主机端口环境变量覆盖
PostgreSQL54325432POSTGRES_PORT
Redis63796379REDIS_PORT
Ontology Service90909090ONTOLOGY_GRPC_PORT
API Gateway80808080GATEWAY_HTTP_PORT
Platform Console30003000CONSOLE_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 和配置覆盖,实现了从最小开发环境到完整测试环境的灵活编排。关键设计亮点:

  1. 多 Profile:minimal/standard/full 三级配置
  2. 健康检查:所有服务配置健康检查,确保启动顺序
  3. 配置覆盖:环境变量 + override 文件的灵活配置
  4. 运维工具:一键启动/停止/重置/日志管理脚本
  5. GPU 支持:Intelligence Layer 的 GPU 加速配置

下一篇将探讨 coomia-dip 的 Kubernetes Operator 部署方案。