From d884e6bab22dfff4e569c73bd3f3e19c922e3918 Mon Sep 17 00:00:00 2001 From: huangping Date: Tue, 28 Apr 2026 18:31:49 +0800 Subject: [PATCH] feat: expand docker-compose to 8 services with monitoring stack per architecture spec --- .env.example | 20 ++++ services/delivery-platform-api/Dockerfile | 5 + services/docker-compose.yml | 124 +++++++++++++++++++- services/grafana/datasources/datasource.yml | 8 ++ services/license-webhook-ingress/Dockerfile | 5 + services/nginx/default.conf | 36 ++++++ services/prometheus/prometheus.yml | 14 +++ web/delivery-platform-ui/Dockerfile | 3 + 8 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 .env.example create mode 100644 services/delivery-platform-api/Dockerfile create mode 100644 services/grafana/datasources/datasource.yml create mode 100644 services/license-webhook-ingress/Dockerfile create mode 100644 services/nginx/default.conf create mode 100644 services/prometheus/prometheus.yml create mode 100644 web/delivery-platform-ui/Dockerfile diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4762a47 --- /dev/null +++ b/.env.example @@ -0,0 +1,20 @@ +# CraftLabs 平台环境变量模板 +# 复制为 .env 后修改实际值;.env 不提交 Git + +# 数据库 +DB_PASSWORD=change_me_in_production + +# Redis 密码(空字符串表示无密码) +REDIS_PASSWORD= + +# 比特安索 API Key +BIT_CLOUD_API_KEY=change_me + +# Webhook 预期 Token(与比特控制台配置一致) +CRAFTLABS_WEBHOOK_EXPECTED_TOKEN=change_me + +# JWT 签名密钥(≥32 字符) +PLATFORM_JWT_SECRET=change_me_at_least_32_characters_long + +# Grafana 管理员密码 +GRAFANA_ADMIN_PASSWORD=admin diff --git a/services/delivery-platform-api/Dockerfile b/services/delivery-platform-api/Dockerfile new file mode 100644 index 0000000..0d438cb --- /dev/null +++ b/services/delivery-platform-api/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:17-jre-alpine +WORKDIR /app +COPY target/*.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/services/docker-compose.yml b/services/docker-compose.yml index 3e7e402..ee82bcd 100644 --- a/services/docker-compose.yml +++ b/services/docker-compose.yml @@ -1,10 +1,128 @@ -# 本地/联调:PostgreSQL 15(与架构文档一致) services: + # ── 数据层 ── postgres: image: postgres:15-alpine environment: - POSTGRES_USER: craftlabs - POSTGRES_PASSWORD: craftlabs POSTGRES_DB: craftlabs_platform + POSTGRES_USER: craftlabs + POSTGRES_PASSWORD: ${DB_PASSWORD:-craftlabs} + volumes: + - pg_data:/var/lib/postgresql/data + - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro ports: - "5432:5432" + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "pg_isready -U craftlabs -d craftlabs_platform"] + interval: 10s + timeout: 5s + retries: 5 + + redis: + image: redis:7-alpine + command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-} + volumes: + - redis_data:/data + ports: + - "6379:6379" + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + + # ── 应用层 ── + backend: + build: + context: ./delivery-platform-api + dockerfile: Dockerfile + image: craftlabs/delivery-platform-api:latest + environment: + SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/craftlabs_platform + SPRING_DATASOURCE_USERNAME: craftlabs + SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD:-craftlabs} + SPRING_DATA_REDIS_HOST: redis + SPRING_DATA_REDIS_PASSWORD: ${REDIS_PASSWORD:-} + PLATFORM_JWT_SECRET: ${PLATFORM_JWT_SECRET:-dev-secret-at-least-32-chars-long} + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + ports: + - "8080:8080" + restart: unless-stopped + + webhook: + build: + context: ./license-webhook-ingress + dockerfile: Dockerfile + image: craftlabs/license-webhook-ingress:latest + environment: + SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/craftlabs_platform + SPRING_DATASOURCE_USERNAME: craftlabs + SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD:-craftlabs} + CRAFTLABS_WEBHOOK_EXPECTED_TOKEN: ${CRAFTLABS_WEBHOOK_EXPECTED_TOKEN:-} + depends_on: + postgres: + condition: service_healthy + ports: + - "8081:8081" + restart: unless-stopped + + frontend: + build: + context: ../web/delivery-platform-ui + dockerfile: Dockerfile + image: craftlabs/delivery-platform-ui:latest + ports: + - "80:80" + depends_on: + - backend + restart: unless-stopped + + # ── 接入层 ── + nginx: + image: nginx:alpine + volumes: + - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro + ports: + - "443:443" + depends_on: + - backend + - webhook + - frontend + restart: unless-stopped + + # ── 监控层(可选) ── + prometheus: + image: prom/prometheus:latest + volumes: + - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - prometheus_data:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + ports: + - "9090:9090" + restart: unless-stopped + + grafana: + image: grafana/grafana:latest + environment: + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-admin} + volumes: + - ./grafana/datasources:/etc/grafana/provisioning/datasources:ro + - grafana_data:/var/lib/grafana + ports: + - "3000:3000" + depends_on: + - prometheus + restart: unless-stopped + +volumes: + pg_data: + redis_data: + prometheus_data: + grafana_data: diff --git a/services/grafana/datasources/datasource.yml b/services/grafana/datasources/datasource.yml new file mode 100644 index 0000000..86fd346 --- /dev/null +++ b/services/grafana/datasources/datasource.yml @@ -0,0 +1,8 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true diff --git a/services/license-webhook-ingress/Dockerfile b/services/license-webhook-ingress/Dockerfile new file mode 100644 index 0000000..5f44601 --- /dev/null +++ b/services/license-webhook-ingress/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:17-jre-alpine +WORKDIR /app +COPY target/*.jar app.jar +EXPOSE 8081 +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/services/nginx/default.conf b/services/nginx/default.conf new file mode 100644 index 0000000..0340284 --- /dev/null +++ b/services/nginx/default.conf @@ -0,0 +1,36 @@ +upstream backend_api { + server backend:8080; +} + +upstream webhook_api { + server webhook:8081; +} + +server { + listen 80; + server_name localhost; + + location / { + proxy_pass http://frontend:80; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + location /api/ { + proxy_pass http://backend_api; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location /webhook/ { + proxy_pass http://webhook_api; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location /actuator/health { + proxy_pass http://backend_api; + } +} diff --git a/services/prometheus/prometheus.yml b/services/prometheus/prometheus.yml new file mode 100644 index 0000000..ba1cc8a --- /dev/null +++ b/services/prometheus/prometheus.yml @@ -0,0 +1,14 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: 'platform-api' + metrics_path: '/actuator/prometheus' + static_configs: + - targets: ['backend:8080'] + + - job_name: 'webhook-ingress' + metrics_path: '/actuator/prometheus' + static_configs: + - targets: ['webhook:8081'] diff --git a/web/delivery-platform-ui/Dockerfile b/web/delivery-platform-ui/Dockerfile new file mode 100644 index 0000000..0f0dcf4 --- /dev/null +++ b/web/delivery-platform-ui/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:alpine +COPY dist/ /usr/share/nginx/html/ +EXPOSE 80