feat(infra): api-gateway 环境变量补全 + build context 修复 + docker-compose.test 新增

This commit is contained in:
SpecialX
2026-07-14 16:04:20 +08:00
parent a70977ad4b
commit 2796d7c88f
3 changed files with 162 additions and 6 deletions

View File

@@ -32,8 +32,11 @@ ADMIN_PORTAL_PORT=4003
KAFKA_BROKERS=
# ============ push-gatewayWebSocket 推送服务)============
# /internal/push 鉴权 tokenmsg 服务调用时需携带 X-Internal-Token 头
INTERNAL_API_TOKEN=CHANGE_ME_TO_STRONG_INTERNAL_TOKEN
# /internal/push 鉴权 tokenmsg 服务调用时需携带 X-Internal-Key 头ARB-013
# PUSH_INTERNAL_TOKEN 是 v2 规范环境变量;INTERNAL_API_TOKEN 作为向后兼容别名仍被接受
PUSH_INTERNAL_TOKEN=CHANGE_ME_TO_STRONG_INTERNAL_TOKEN
# 向后兼容别名(留空则使用 PUSH_INTERNAL_TOKEN设置后会回退到此值
INTERNAL_API_TOKEN=
# WebSocket 允许的 Origin 白名单(逗号分隔)
WS_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:4000,http://localhost:4001,http://localhost:4002,http://localhost:4003
# push-gateway 对外端口

View File

@@ -23,25 +23,31 @@ services:
# ============================================================
api-gateway:
build:
context: ./repo/services/api-gateway
dockerfile: Dockerfile
context: ./repo
dockerfile: services/api-gateway/Dockerfile
container_name: edu-api-gateway
restart: unless-stopped
environment:
API_GATEWAY_PORT: ${API_GATEWAY_PORT:-8080}
ENV: production
JWT_SECRET: ${JWT_SECRET}
JWT_ISSUER: ${JWT_ISSUER:-next-edu-cloud}
JWT_AUDIENCE: ${JWT_AUDIENCE:-next-edu-cloud}
# RS256 公钥端点(非 DevMode 下必填config.go W7 防护)
IAM_JWKS_URL: http://iam:3002/v1/iam/.well-known/jwks.json
# 生产环境强制关闭 dev-token 旁路
DEV_MODE: "false"
CLASSES_SERVICE_URL: http://classes:3001
IAM_SERVICE_URL: http://iam:3002
TEACHER_BFF_URL: http://teacher-bff:3003
STUDENT_BFF_URL: http://student-bff:3009
PARENT_BFF_URL: http://parent-bff:3010
CORE_EDU_SERVICE_URL: http://core-edu:3004
CONTENT_SERVICE_URL: http://content:3005
DATA_ANA_SERVICE_URL: http://data-ana:3006
MSG_SERVICE_URL: http://msg:3007
AI_SERVICE_URL: http://ai:3008
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000,http://localhost:4000,http://localhost:4001,http://localhost:4002,http://localhost:4003}
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
LOG_LEVEL: ${LOG_LEVEL:-info}
ports:
@@ -116,9 +122,19 @@ services:
restart: unless-stopped
environment:
PORT: 3003
TEACHER_BFF_DEV_MODE: "false"
REDIS_URL: ${REDIS_URL}
IAM_GRPC_TARGET: iam:50052
IAM_SERVICE_URL: http://iam:3002
CLASSES_SERVICE_URL: http://classes:3001
CORE_EDU_GRPC_TARGET: core-edu:50053
CORE_EDU_SERVICE_URL: http://core-edu:3004
CONTENT_GRPC_TARGET: content:50054
DATA_ANA_GRPC_TARGET: data-ana:50055
MSG_GRPC_TARGET: msg:50056
MSG_SERVICE_URL: http://msg:3007
AI_GRPC_TARGET: ai:50058
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
LOG_LEVEL: ${LOG_LEVEL:-info}
NODE_ENV: production
depends_on:
@@ -280,9 +296,12 @@ services:
JWT_SECRET: ${JWT_SECRET}
REDIS_URL: ${REDIS_URL}
KAFKA_BROKERS: ${KAFKA_BROKERS:-kafka:29092}
KAFKA_NOTIFICATION_TOPIC: edu.notification.requested
# ARB-013 canonical topic name (v2 alignment with msg Outbox publisher).
KAFKA_NOTIFICATION_TOPIC: edu.notify.notification.sent
KAFKA_CONSUMER_GROUP: push-gateway
INTERNAL_API_TOKEN: ${INTERNAL_API_TOKEN:-edu-internal-token}
# PUSH_INTERNAL_TOKEN is the canonical env var (ARB-013 alignment with
# msg). INTERNAL_API_TOKEN kept as backward-compat alias.
PUSH_INTERNAL_TOKEN: ${PUSH_INTERNAL_TOKEN:-${INTERNAL_API_TOKEN:-edu-internal-token}}
JWKS_URL: http://iam:3002/v1/iam/.well-known/jwks.json
WS_ALLOWED_ORIGINS: ${WS_ALLOWED_ORIGINS:-http://localhost:3000,http://localhost:4000,http://localhost:4001,http://localhost:4002,http://localhost:4003}
MAX_CONNS_PER_USER: "5"

View File

@@ -0,0 +1,134 @@
# 本地测试用 Docker Composeiam + teacher-bff + ai 联调)
# 使用方式:
# docker compose -f infra/docker-compose.test.yml up -d --build
#
# 依赖edu-full_default 网络已存在MySQL/Redis/Kafka 已在该网络)
# 网络:复用 edu-full_default使各服务可直连 edu-mysql/edu-redis/edu-kafka
name: edu-test
services:
iam:
build:
context: ..
dockerfile: services/iam/Dockerfile
container_name: edu-iam-test
restart: unless-stopped
environment:
# 生产模式:避免 pino-pretty 依赖pruned by --prod
# DEV_MODE=true 仍可旁路鉴权
NODE_ENV: production
PORT: "3002"
GRPC_PORT: "50052"
DATABASE_URL: mysql://edu:changeme@edu-mysql:3306/next_edu_cloud
REDIS_URL: redis://edu-redis:6379
IAM_PRIVATE_KEY_PATH: /app/keys/iam-private.pem
IAM_PUBLIC_KEY_PATH: /app/keys/iam-public.pem
JWT_ISSUER: next-edu-cloud
JWT_AUDIENCE: next-edu-cloud
JWT_KEY_ID: iam-rs256-v1
KAFKA_BROKERS: kafka:29092
KAFKA_CLIENT_ID: iam-service
LOG_LEVEL: info
# 开发模式:接受 dev-token 旁路鉴权
DEV_MODE: "true"
ports:
- "3002:3002"
- "50052:50052"
volumes:
- ../keys:/app/keys:ro
healthcheck:
test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:3002/healthz"]
interval: 10s
timeout: 5s
start_period: 30s
retries: 5
networks:
- edu-full
teacher-bff:
build:
context: ..
dockerfile: services/teacher-bff/Dockerfile
container_name: edu-teacher-bff-test
restart: unless-stopped
environment:
NODE_ENV: production
PORT: "3003"
GRAPHQL_PATH: /graphql
TEACHER_BFF_DEV_MODE: "true"
REDIS_URL: redis://edu-redis:6379
IAM_GRPC_TARGET: iam:50052
IAM_SERVICE_URL: http://iam:3002
CORE_EDU_GRPC_TARGET: core-edu:50053
CONTENT_GRPC_TARGET: content:50054
DATA_ANA_GRPC_TARGET: data-ana:50055
MSG_GRPC_TARGET: msg:50056
MSG_SERVICE_URL: http://msg:3007
AI_GRPC_TARGET: ai:50058
LOG_LEVEL: info
ports:
- "3003:3003"
depends_on:
iam:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:3003/healthz"]
interval: 10s
timeout: 5s
start_period: 20s
retries: 5
networks:
- edu-full
ai:
build:
context: ../services/ai
dockerfile: Dockerfile
container_name: edu-ai-test
restart: unless-stopped
environment:
# HTTP/gRPC 端口
HTTP_PORT: "3008"
GRPC_PORT: "50058"
# 开发模式旁路鉴权dev-token
DEV_MODE: "true"
LOG_LEVEL: info
# 基础设施
REDIS_URL: redis://edu-redis:6379/0
KAFKA_BOOTSTRAP_SERVERS: kafka:29092
KAFKA_AI_USAGE_TOPIC: edu.ai.usage
# 下游 gRPC 端点edu-full_default 网络内服务名解析)
# content 服务未启动 → connect 失败但不阻断启动,调用时抛 AIError
CONTENT_GRPC_ENDPOINT: content:50054
DATA_ANA_GRPC_ENDPOINT: data-ana:50055
IAM_GRPC_ENDPOINT: iam:50052
# LLM 配置(测试环境不配 API keyLLM 功能降级HTTP 端点仍可调)
OPENAI_API_KEY: ""
OPENAI_BASE_URL: https://api.openai.com/v1
ANTHROPIC_API_KEY: ""
BAICHUAN_API_KEY: ""
OLLAMA_BASE_URL: ""
LLM_PROVIDER_PRIORITY: openai,anthropic,baichuan,local_ollama
DEFAULT_CHAT_MODEL: gpt-4o-mini
DEFAULT_QUESTION_MODEL: gpt-4o-mini
# 可观测性jaeger 已在 edu-full_default 网络中)
OTEL_EXPORTER_OTLP_ENDPOINT: http://edu-jaeger:4318
ports:
- "3008:3008"
- "50058:50058"
depends_on:
iam:
condition: service_healthy
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3008/healthz')"]
interval: 10s
timeout: 5s
start_period: 30s
retries: 5
networks:
- edu-full
networks:
edu-full:
external: true
name: edu-full_default