gcx/backend/docker-compose.yml

561 lines
16 KiB
YAML

version: '3.9'
services:
# ============================================================
# Infrastructure Services
# ============================================================
postgres:
image: postgres:15-alpine
container_name: genex-postgres
environment:
POSTGRES_USER: genex
POSTGRES_PASSWORD: genex_dev_password
POSTGRES_DB: genex
ports:
# 安全加固: 仅绑定 127.0.0.1, 禁止公网直连数据库
- "127.0.0.1:5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./migrations:/docker-entrypoint-initdb.d
command:
- "postgres"
- "-c"
- "wal_level=logical" # Required for Debezium CDC
- "-c"
- "max_replication_slots=10" # CDC connector slots
- "-c"
- "max_wal_senders=10" # WAL sender processes
- "-c"
# WAL 安全阀: 限制单个 replication slot 最多保留 10GB WAL
# 超过此值 PostgreSQL 会使 slot 失效, 防止磁盘被吃满
# (rwadurian 事故: 无此限制, 单个 stuck slot 累积 305GB WAL)
- "max_slot_wal_keep_size=10GB"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U genex"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- genex-network
redis:
image: redis:7-alpine
container_name: genex-redis
ports:
# 安全加固: 仅绑定 127.0.0.1, Redis 无密码保护, 暴露公网极易被利用
- "127.0.0.1:6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- genex-network
kafka:
image: confluentinc/cp-kafka:7.7.0
container_name: genex-kafka
environment:
# KRaft mode (no Zookeeper needed since Kafka 3.5+)
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093,PLAINTEXT_HOST://0.0.0.0:29092
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
KAFKA_LOG_DIRS: /var/lib/kafka/data
CLUSTER_ID: "genex-kafka-cluster-001"
ports:
- "9092:9092"
# 安全加固: 外部访问端口仅绑定 127.0.0.1
- "127.0.0.1:29092:29092"
volumes:
- kafka_data:/var/lib/kafka/data
healthcheck:
test: ["CMD", "kafka-broker-api-versions", "--bootstrap-server", "localhost:9092"]
interval: 10s
timeout: 10s
retries: 5
restart: unless-stopped
networks:
- genex-network
# MinIO Object Storage (S3-compatible, multi-region replication support)
minio:
image: minio/minio:latest
container_name: genex-minio
environment:
MINIO_ROOT_USER: genex-admin
MINIO_ROOT_PASSWORD: genex-minio-secret
ports:
- "9000:9000" # S3 API
# 安全加固: MinIO Console 仅绑定 127.0.0.1, 带默认密码暴露公网极其危险
- "127.0.0.1:9001:9001" # Console UI
volumes:
- minio_data:/data
command: server /data --console-address ":9001"
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- genex-network
# MinIO bucket initialization
minio-init:
image: minio/mc:latest
container_name: genex-minio-init
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set genex http://minio:9000 genex-admin genex-minio-secret;
mc mb --ignore-existing genex/kyc-documents;
mc mb --ignore-existing genex/coupon-images;
mc mb --ignore-existing genex/issuer-documents;
mc mb --ignore-existing genex/sar-reports;
mc mb --ignore-existing genex/avatars;
mc mb --ignore-existing genex/exports;
mc mb --ignore-existing genex/app-releases;
mc anonymous set download genex/coupon-images;
mc anonymous set download genex/avatars;
echo 'MinIO buckets initialized';
"
networks:
- genex-network
# Debezium Kafka Connect (CDC - Change Data Capture)
# 版本说明: 必须使用 2.5.1+ (修复 DBZ-7316: searchWalPosition 不推进 confirmed_flush_lsn, 导致 WAL 无限积压)
kafka-connect:
image: debezium/connect:2.5.4.Final
container_name: genex-kafka-connect
environment:
BOOTSTRAP_SERVERS: kafka:9092
GROUP_ID: genex-connect
CONFIG_STORAGE_TOPIC: genex_connect_configs
OFFSET_STORAGE_TOPIC: genex_connect_offsets
STATUS_STORAGE_TOPIC: genex_connect_statuses
CONFIG_STORAGE_REPLICATION_FACTOR: 1
OFFSET_STORAGE_REPLICATION_FACTOR: 1
STATUS_STORAGE_REPLICATION_FACTOR: 1
# Offset 提交频率: 默认 60s, 缩短至 10s 以减少重启后重复处理窗口
OFFSET_FLUSH_INTERVAL_MS: 10000
OFFSET_FLUSH_TIMEOUT_MS: 5000
ports:
# 安全加固: 仅绑定 127.0.0.1, 禁止公网访问 Kafka Connect REST API
# 暴露公网会导致 SSRF 攻击 (恶意注入 connector 读取 /etc/passwd 等)
- "127.0.0.1:8083:8083"
depends_on:
kafka:
condition: service_healthy
postgres:
condition: service_healthy
restart: unless-stopped
networks:
- genex-network
# Kong API Gateway (DB-less / Declarative mode)
kong:
image: kong:3.5-alpine
container_name: genex-kong
environment:
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: /etc/kong/kong.yml
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: 0.0.0.0:8001
KONG_PROXY_LISTEN: 0.0.0.0:8080
ports:
- "8080:8080" # Proxy (frontend connects here)
# 安全加固: Kong Admin API 仅绑定 127.0.0.1, 暴露公网可被用于篡改路由规则
- "127.0.0.1:8001:8001" # Admin API
volumes:
- ./kong/kong.yml:/etc/kong/kong.yml:ro
healthcheck:
test: ["CMD", "kong", "health"]
interval: 10s
timeout: 10s
retries: 5
restart: unless-stopped
networks:
- genex-network
# ============================================================
# NestJS Services (5)
# ============================================================
user-service:
build:
context: .
dockerfile: services/user-service/Dockerfile
container_name: genex-user-service
ports:
- "3001:3001"
environment:
- NODE_ENV=development
- PORT=3001
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- REDIS_HOST=redis
- REDIS_PORT=6379
- KAFKA_BROKERS=kafka:9092
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
- JWT_ACCESS_EXPIRY=15m
- JWT_REFRESH_SECRET=dev-refresh-secret-change-in-production
- JWT_REFRESH_EXPIRY=7d
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- genex-network
issuer-service:
build:
context: .
dockerfile: services/issuer-service/Dockerfile
container_name: genex-issuer-service
ports:
- "3002:3002"
environment:
- NODE_ENV=development
- PORT=3002
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- REDIS_HOST=redis
- REDIS_PORT=6379
- KAFKA_BROKERS=kafka:9092
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- genex-network
clearing-service:
build:
context: .
dockerfile: services/clearing-service/Dockerfile
container_name: genex-clearing-service
ports:
- "3004:3004"
environment:
- NODE_ENV=development
- PORT=3004
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- KAFKA_BROKERS=kafka:9092
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
depends_on:
postgres:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- genex-network
compliance-service:
build:
context: .
dockerfile: services/compliance-service/Dockerfile
container_name: genex-compliance-service
ports:
- "3005:3005"
environment:
- NODE_ENV=development
- PORT=3005
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- KAFKA_BROKERS=kafka:9092
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
depends_on:
postgres:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- genex-network
notification-service:
build:
context: .
dockerfile: services/notification-service/Dockerfile
container_name: genex-notification-service
ports:
- "3008:3008"
environment:
- NODE_ENV=development
- PORT=3008
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- KAFKA_BROKERS=kafka:9092
- REDIS_HOST=redis
- REDIS_PORT=6379
depends_on:
kafka:
condition: service_healthy
networks:
- genex-network
# ============================================================
# Telemetry Service (NestJS :3011) - User presence, events, DAU, Prometheus metrics
# ============================================================
telemetry-service:
build:
context: .
dockerfile: services/telemetry-service/Dockerfile
container_name: genex-telemetry-service
ports:
- "3011:3011"
environment:
- NODE_ENV=development
- PORT=3011
- SERVICE_NAME=telemetry-service
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- REDIS_HOST=redis
- REDIS_PORT=6379
- KAFKA_BROKERS=kafka:9092
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- genex-network
# ============================================================
# Admin Service (NestJS :3012) - App version management, OTA updates
# ============================================================
admin-service:
build:
context: .
dockerfile: services/admin-service/Dockerfile
container_name: genex-admin-service
ports:
- "3012:3012"
environment:
- NODE_ENV=development
- PORT=3012
- SERVICE_NAME=admin-service
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- MINIO_ENDPOINT=minio
- MINIO_PORT=9000
- MINIO_ACCESS_KEY=genex-admin
- MINIO_SECRET_KEY=genex-minio-secret
- MINIO_BUCKET=app-releases
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
networks:
- genex-network
# ============================================================
# Go Services (3)
# ============================================================
trading-service:
build:
context: ./services/trading-service
dockerfile: Dockerfile
container_name: genex-trading-service
ports:
- "3003:3003"
environment:
- PORT=3003
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- REDIS_HOST=redis
- REDIS_PORT=6379
- KAFKA_BROKERS=kafka:9092
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- genex-network
translate-service:
build:
context: ./services/translate-service
dockerfile: Dockerfile
container_name: genex-translate-service
ports:
- "3007:3007"
environment:
- PORT=3007
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- REDIS_HOST=redis
- REDIS_PORT=6379
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- genex-network
chain-indexer:
build:
context: ./services/chain-indexer
dockerfile: Dockerfile
container_name: genex-chain-indexer
ports:
- "3009:3009"
environment:
- PORT=3009
- KAFKA_BROKERS=kafka:9092
- CHAIN_RPC_URL=http://localhost:26657
depends_on:
kafka:
condition: service_healthy
networks:
- genex-network
# ============================================================
# Auth Service (NestJS) - JWT dual-token, registration, login, RBAC
# ============================================================
auth-service:
build:
context: .
dockerfile: services/auth-service/Dockerfile
container_name: genex-auth-service
ports:
- "3010:3010"
environment:
- NODE_ENV=development
- PORT=3010
- SERVICE_NAME=auth-service
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- REDIS_HOST=redis
- REDIS_PORT=6379
- KAFKA_BROKERS=kafka:9092
- JWT_ACCESS_SECRET=dev-access-secret-change-in-production
- JWT_ACCESS_EXPIRY=15m
- JWT_REFRESH_SECRET=dev-refresh-secret-change-in-production
- JWT_REFRESH_EXPIRY=7d
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- genex-network
# ============================================================
# AI Service (NestJS) - Anti-corruption layer to external AI agent cluster
# ============================================================
ai-service:
build:
context: .
dockerfile: services/ai-service/Dockerfile
container_name: genex-ai-service
ports:
- "3006:3006"
environment:
- NODE_ENV=development
- PORT=3006
- SERVICE_NAME=ai-service
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=genex
- DB_PASSWORD=genex_dev_password
- DB_NAME=genex
- KAFKA_BROKERS=kafka:9092
- REDIS_HOST=redis
- REDIS_PORT=6379
- AI_AGENT_CLUSTER_URL=http://external-ai-agents:8000
- AI_AGENT_API_KEY=your-ai-agent-api-key
- AI_AGENT_TIMEOUT=30000
depends_on:
postgres:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- genex-network
volumes:
postgres_data:
redis_data:
kafka_data:
minio_data:
networks:
genex-network:
driver: bridge