services: # ==================== 基础设施 ==================== postgres: image: postgres:17-bookworm container_name: juwan-postgres restart: unless-stopped environment: POSTGRES_USER: ${PD_USERNAME} POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: ${DB_NAME} ports: - "15432:5432" volumes: - pgdata:/var/lib/postgresql/data - ./init-db.sh:/docker-entrypoint-initdb.d/init-db.sh:ro - ../../desc/sql:/docker-entrypoint-initdb.d/sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${PD_USERNAME} -d ${DB_NAME}"] interval: 5s timeout: 3s start_period: 30s retries: 10 redis: image: redis:8-alpine container_name: juwan-redis restart: unless-stopped ports: - "16379:6379" volumes: - redisdata:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 10 rl-redis: image: redis:${REDIS_VERSION:-8} container_name: ${REDIS_CONTAINER_NAME:-rl-redis-dev-server} ports: - "6380:6379" restart: unless-stopped kafka: image: apache/kafka:4.0.1 container_name: juwan-kafka restart: unless-stopped environment: KAFKA_NODE_ID: 1 KAFKA_PROCESS_ROLES: broker,controller KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093 KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 CLUSTER_ID: juwan-dev-kafka-cluster-id ports: - "19092:9092" healthcheck: test: ["CMD-SHELL", "/opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092"] interval: 10s timeout: 5s retries: 10 # ==================== 共享服务 ==================== snowflake: image: juwan/snowflake-rpc:dev container_name: juwan-snowflake restart: unless-stopped authz-adapter: image: juwan/authz-adapter:dev container_name: juwan-authz-adapter restart: unless-stopped environment: LISTEN_ON: 0.0.0.0:9002 USER_RPC_TARGET: user-rpc:8080 depends_on: user-rpc: condition: service_started envoy-gateway: image: envoyproxy/envoy:v1.31-latest container_name: juwan-envoy-gateway restart: unless-stopped command: - /usr/local/bin/envoy - -c - /etc/envoy/envoy.yaml - --log-level - info - --disable-hot-restart ports: - "18080:8080" volumes: - ./envoy.yaml:/etc/envoy/envoy.yaml:ro depends_on: authz-adapter: condition: service_started users-api: condition: service_started player-api: condition: service_started game-api: condition: service_started shop-api: condition: service_started order-api: condition: service_started wallet-api: condition: service_started community-api: condition: service_started objectstory-api: condition: service_started email-api: condition: service_started chat-api: condition: service_started review-api: condition: service_started dispute-api: condition: service_started notification-api: condition: service_started search-api: condition: service_started ratelimit: image: envoyproxy/ratelimit:05c08d03 container_name: rl-service restart: unless-stopped command: /bin/ratelimit environment: - REDIS_SOCKET_TYPE=tcp - REDIS_URL=rl-redis:6379 - USE_STATSD=false - RUNTIME_ROOT=/data - RUNTIME_SUBDIRECTORY=ratelimit - RUNTIME_WATCH_ROOT=true - LOG_LEVEL=debug volumes: - ./rls/ratelimit.yaml:/data/ratelimit/config/ratelimit.yaml:ro ports: - "18081:8081" - "16070:6070" depends_on: rl-redis: condition: service_started # ==================== RPC 层 ==================== user-rpc: image: juwan/users-rpc:dev container_name: juwan-user-rpc restart: unless-stopped env_file: .env environment: ADMIN_USERNAME: ${ADMIN_USERNAME} ADMIN_PASSWORD: ${ADMIN_PASSWORD} ADMIN_EMAIL: ${ADMIN_EMAIL} depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started user-verifications-rpc: image: juwan/user_verifications-rpc:dev container_name: juwan-user-verifications-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started user-rpc: condition: service_started player-rpc: image: juwan/player-rpc:dev container_name: juwan-player-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started game-rpc: image: juwan/game-rpc:dev container_name: juwan-game-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started shop-rpc: image: juwan/shop-rpc:dev container_name: juwan-shop-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started user-rpc: condition: service_started order-rpc: image: juwan/order-rpc:dev container_name: juwan-order-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started wallet-rpc: image: juwan/wallet-rpc:dev container_name: juwan-wallet-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started community-rpc: image: juwan/community-rpc:dev container_name: juwan-community-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started chat-rpc: image: juwan/chat-rpc:dev container_name: juwan-chat-rpc restart: unless-stopped objectstory-rpc: image: juwan/objectstory-rpc:dev container_name: juwan-objectstory-rpc restart: unless-stopped env_file: .env review-rpc: image: juwan/review-rpc:dev container_name: juwan-review-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started dispute-rpc: image: juwan/dispute-rpc:dev container_name: juwan-dispute-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started notification-rpc: image: juwan/notification-rpc:dev container_name: juwan-notification-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started search-rpc: image: juwan/search-rpc:dev container_name: juwan-search-rpc restart: unless-stopped env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy snowflake: condition: service_started # ==================== API 层 ==================== users-api: image: juwan/users-api:dev container_name: juwan-users-api restart: unless-stopped env_file: .env ports: - "18801:8888" depends_on: user-rpc: condition: service_started user-verifications-rpc: condition: service_started player-api: image: juwan/player-api:dev container_name: juwan-player-api restart: unless-stopped env_file: .env ports: - "18802:8888" depends_on: player-rpc: condition: service_started game-api: image: juwan/game-api:dev container_name: juwan-game-api restart: unless-stopped env_file: .env ports: - "18803:8888" depends_on: game-rpc: condition: service_started shop-api: image: juwan/shop-api:dev container_name: juwan-shop-api restart: unless-stopped env_file: .env ports: - "18804:8888" depends_on: shop-rpc: condition: service_started order-api: image: juwan/order-api:dev container_name: juwan-order-api restart: unless-stopped env_file: .env ports: - "18805:8888" depends_on: order-rpc: condition: service_started player-rpc: condition: service_started shop-rpc: condition: service_started wallet-api: image: juwan/wallet-api:dev container_name: juwan-wallet-api restart: unless-stopped env_file: .env ports: - "18806:8888" depends_on: wallet-rpc: condition: service_started community-api: image: juwan/community-api:dev container_name: juwan-community-api restart: unless-stopped env_file: .env ports: - "18807:8888" depends_on: community-rpc: condition: service_started user-rpc: condition: service_started objectstory-api: image: juwan/objectstory-api:dev container_name: juwan-objectstory-api restart: unless-stopped env_file: .env ports: - "18808:8888" depends_on: objectstory-rpc: condition: service_started email-api: image: juwan/email-api:dev container_name: juwan-email-api restart: unless-stopped env_file: .env ports: - "18809:8888" depends_on: redis: condition: service_healthy kafka: condition: service_healthy chat-api: image: juwan/chat-api:dev container_name: juwan-chat-api restart: unless-stopped ports: - "18810:8888" - "18889:8889" - "18443:8443/udp" volumes: - ./certs:/etc/certs:ro depends_on: chat-rpc: condition: service_started review-api: image: juwan/review-api:dev container_name: juwan-review-api restart: unless-stopped env_file: .env ports: - "18811:8888" depends_on: review-rpc: condition: service_started order-rpc: condition: service_started dispute-api: image: juwan/dispute-api:dev container_name: juwan-dispute-api restart: unless-stopped env_file: .env ports: - "18812:8888" depends_on: dispute-rpc: condition: service_started order-rpc: condition: service_started notification-api: image: juwan/notification-api:dev container_name: juwan-notification-api restart: unless-stopped env_file: .env ports: - "18813:8888" depends_on: notification-rpc: condition: service_started search-api: image: juwan/search-api:dev container_name: juwan-search-api restart: unless-stopped env_file: .env ports: - "18814:8888" depends_on: search-rpc: condition: service_started # ==================== MQ ==================== email-mq: image: juwan/email-mq:dev container_name: juwan-email-mq restart: unless-stopped env_file: .env depends_on: kafka: condition: service_healthy volumes: pgdata: name: juwan-pgdata redisdata: name: juwan-redisdata