feat(infra): p6 hardening - observability and deploy compose
- 5 NestJS services add /metrics endpoint via app.getHttpAdapter() - prometheus.yml scales to 8 services with rule_files and alertmanager - monitoring compose replaces blackbox with Loki+Promtail - Grafana datasource adds Loki - docker-compose.deploy.yml scales to 11 services - deploy.env.example completes Neo4j/ES/ClickHouse/LLM vars - teacher-bff adds health.controller - CI removes continue-on-error on lint step - teacher-portal lint script changed to eslint src
This commit is contained in:
@@ -18,6 +18,9 @@
|
||||
name: edu
|
||||
|
||||
services:
|
||||
# ============================================================
|
||||
# 应用服务(10 个:api-gateway + 3 Go/Python + 6 NestJS)
|
||||
# ============================================================
|
||||
api-gateway:
|
||||
build:
|
||||
context: ./repo/services/api-gateway
|
||||
@@ -34,6 +37,11 @@ services:
|
||||
CLASSES_SERVICE_URL: http://classes:3001
|
||||
IAM_SERVICE_URL: http://iam:3002
|
||||
TEACHER_BFF_URL: http://teacher-bff:3003
|
||||
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
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
ports:
|
||||
@@ -59,7 +67,6 @@ services:
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 3001
|
||||
# 连接服务器已有的 MySQL(容器名 edu-mysql,需在 edu-shared 网络)
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
REDIS_URL: ${REDIS_URL}
|
||||
KAFKA_BROKERS: ${KAFKA_BROKERS:-}
|
||||
@@ -75,6 +82,214 @@ services:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
iam:
|
||||
build:
|
||||
context: ./repo
|
||||
dockerfile: services/iam/Dockerfile
|
||||
container_name: edu-iam
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 3002
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
REDIS_URL: ${REDIS_URL}
|
||||
JWT_SECRET: ${JWT_SECRET}
|
||||
JWT_ISSUER: ${JWT_ISSUER:-next-edu-cloud}
|
||||
JWT_AUDIENCE: ${JWT_AUDIENCE:-next-edu-cloud}
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
NODE_ENV: production
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:3002/healthz"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 30s
|
||||
retries: 5
|
||||
networks:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
teacher-bff:
|
||||
build:
|
||||
context: ./repo
|
||||
dockerfile: services/teacher-bff/Dockerfile
|
||||
container_name: edu-teacher-bff
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 3003
|
||||
IAM_SERVICE_URL: http://iam:3002
|
||||
CLASSES_SERVICE_URL: http://classes:3001
|
||||
CORE_EDU_SERVICE_URL: http://core-edu:3004
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
NODE_ENV: production
|
||||
depends_on:
|
||||
iam:
|
||||
condition: service_healthy
|
||||
classes:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:3003/healthz"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 20s
|
||||
retries: 3
|
||||
networks:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
core-edu:
|
||||
build:
|
||||
context: ./repo
|
||||
dockerfile: services/core-edu/Dockerfile
|
||||
container_name: edu-core-edu
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 3004
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
REDIS_URL: ${REDIS_URL}
|
||||
KAFKA_BROKERS: ${KAFKA_BROKERS:-}
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
NODE_ENV: production
|
||||
DEV_MODE: "false"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:3004/healthz"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 30s
|
||||
retries: 5
|
||||
networks:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
content:
|
||||
build:
|
||||
context: ./repo
|
||||
dockerfile: services/content/Dockerfile
|
||||
container_name: edu-content
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 3005
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
REDIS_URL: ${REDIS_URL}
|
||||
NEO4J_URL: ${NEO4J_URL:-}
|
||||
NEO4J_PASSWORD: ${NEO4J_PASSWORD:-}
|
||||
ES_URL: ${ES_URL:-}
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
NODE_ENV: production
|
||||
DEV_MODE: "false"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:3005/healthz"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 30s
|
||||
retries: 5
|
||||
networks:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
msg:
|
||||
build:
|
||||
context: ./repo
|
||||
dockerfile: services/msg/Dockerfile
|
||||
container_name: edu-msg
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 3007
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
REDIS_URL: ${REDIS_URL}
|
||||
KAFKA_BROKERS: ${KAFKA_BROKERS:-}
|
||||
ES_URL: ${ES_URL:-}
|
||||
PUSH_GATEWAY_URL: http://push-gateway:8081
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
NODE_ENV: production
|
||||
DEV_MODE: "false"
|
||||
depends_on:
|
||||
push-gateway:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:3007/healthz"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 30s
|
||||
retries: 5
|
||||
networks:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
ai:
|
||||
build:
|
||||
context: ./repo/services/ai
|
||||
dockerfile: Dockerfile
|
||||
container_name: edu-ai
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 3008
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
||||
OPENAI_BASE_URL: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||
OTEL_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
DEV_MODE: "false"
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3008/healthz')"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 20s
|
||||
retries: 3
|
||||
networks:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
data-ana:
|
||||
build:
|
||||
context: ./repo/services/data-ana
|
||||
dockerfile: Dockerfile
|
||||
container_name: edu-data-ana
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 3006
|
||||
CLICKHOUSE_HOST: ${CLICKHOUSE_HOST:-}
|
||||
CLICKHOUSE_PORT: ${CLICKHOUSE_PORT:-8123}
|
||||
CLICKHOUSE_DATABASE: ${CLICKHOUSE_DATABASE:-edu_analytics}
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-}
|
||||
OTEL_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4318}
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
DEV_MODE: "false"
|
||||
KAFKA_BROKERS: ${KAFKA_BROKERS:-}
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3006/healthz')"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 20s
|
||||
retries: 3
|
||||
networks:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
push-gateway:
|
||||
build:
|
||||
context: ./repo/services/push-gateway
|
||||
dockerfile: Dockerfile
|
||||
container_name: edu-push-gateway
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PUSH_GATEWAY_PORT: 8081
|
||||
JWT_SECRET: ${JWT_SECRET}
|
||||
REDIS_URL: ${REDIS_URL}
|
||||
DEV_MODE: "false"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--spider", "http://localhost:8081/healthz"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- edu-net
|
||||
- edu-shared
|
||||
|
||||
teacher-portal:
|
||||
build:
|
||||
context: ./repo
|
||||
|
||||
Reference in New Issue
Block a user