diff --git a/backend/services/auth-service/Dockerfile b/backend/services/auth-service/Dockerfile new file mode 100644 index 00000000..1f7962a8 --- /dev/null +++ b/backend/services/auth-service/Dockerfile @@ -0,0 +1,48 @@ +# ============================================================================= +# Auth Service - Dockerfile +# ============================================================================= + +# 阶段1: 构建 +FROM node:20-alpine AS builder +WORKDIR /app + +RUN apk add --no-cache python3 make g++ + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY prisma ./prisma/ +RUN npx prisma generate + +COPY . . +RUN npm run build + +# 阶段2: 生产运行 +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache curl tzdata + +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nestjs + +COPY package.json package-lock.json ./ +RUN npm ci --only=production && npm cache clean --force + +COPY prisma ./prisma/ +RUN npx prisma generate + +COPY --from=builder /app/dist ./dist + +RUN chown -R nestjs:nodejs /app +USER nestjs + +EXPOSE 3024 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:3024/api/v2/health || exit 1 + +CMD ["node", "dist/main.js"] diff --git a/backend/services/contribution-service/Dockerfile b/backend/services/contribution-service/Dockerfile new file mode 100644 index 00000000..c07bdd96 --- /dev/null +++ b/backend/services/contribution-service/Dockerfile @@ -0,0 +1,48 @@ +# ============================================================================= +# Contribution Service - Dockerfile +# ============================================================================= + +# 阶段1: 构建 +FROM node:20-alpine AS builder +WORKDIR /app + +RUN apk add --no-cache python3 make g++ + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY prisma ./prisma/ +RUN npx prisma generate + +COPY . . +RUN npm run build + +# 阶段2: 生产运行 +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache curl tzdata + +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nestjs + +COPY package.json package-lock.json ./ +RUN npm ci --only=production && npm cache clean --force + +COPY prisma ./prisma/ +RUN npx prisma generate + +COPY --from=builder /app/dist ./dist + +RUN chown -R nestjs:nodejs /app +USER nestjs + +EXPOSE 3020 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:3020/health || exit 1 + +CMD ["node", "dist/main.js"] diff --git a/backend/services/deploy-mining.sh b/backend/services/deploy-mining.sh index 8ee8db54..747f4beb 100644 --- a/backend/services/deploy-mining.sh +++ b/backend/services/deploy-mining.sh @@ -39,6 +39,7 @@ # trading -> trading-service # admin -> mining-admin-service # auth -> auth-service +# web, admin-web -> mining-admin-web (frontend) # set -e @@ -48,7 +49,7 @@ set -e # =========================================================================== SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE="$SCRIPT_DIR/.env" -COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml" +COMPOSE_FILE="$SCRIPT_DIR/docker-compose.2.0.yml" # 2.0 Services MINING_SERVICES=( @@ -57,6 +58,7 @@ MINING_SERVICES=( "trading-service" "mining-admin-service" "auth-service" + "mining-admin-web" ) # Service Aliases @@ -67,6 +69,8 @@ declare -A SERVICE_ALIASES=( ["trading"]="trading-service" ["admin"]="mining-admin-service" ["auth"]="auth-service" + ["web"]="mining-admin-web" + ["admin-web"]="mining-admin-web" ) # 2.0 Databases @@ -94,6 +98,7 @@ declare -A SERVICE_PORTS=( ["trading-service"]="3022" ["mining-admin-service"]="3023" ["auth-service"]="3024" + ["mining-admin-web"]="3100" ) # CDC Consumer Group @@ -871,6 +876,7 @@ show_help() { echo " trading -> trading-service" echo " admin -> mining-admin-service" echo " auth -> auth-service" + echo " web, admin-web -> mining-admin-web" echo "" echo -e "${BOLD}Examples:${NC}" echo " $0 up # Start all services" diff --git a/backend/services/docker-compose.2.0.yml b/backend/services/docker-compose.2.0.yml new file mode 100644 index 00000000..e651a8c9 --- /dev/null +++ b/backend/services/docker-compose.2.0.yml @@ -0,0 +1,210 @@ +# ============================================================================= +# RWA Mining Ecosystem 2.0 - Docker Compose +# ============================================================================= +# +# 2.0 系统完全独立于 1.0,可随时重置 +# +# Usage: +# docker-compose -f docker-compose.2.0.yml up -d # 启动所有 2.0 服务 +# docker-compose -f docker-compose.2.0.yml down # 停止所有 2.0 服务 +# docker-compose -f docker-compose.2.0.yml up -d mining-admin # 启动单个服务 +# docker-compose -f docker-compose.2.0.yml logs -f # 查看日志 +# +# ============================================================================= + +services: + # =========================================================================== + # Backend Services (2.0) + # =========================================================================== + + contribution-service: + build: + context: ./contribution-service + dockerfile: Dockerfile + container_name: rwa-contribution-service + environment: + NODE_ENV: production + TZ: Asia/Shanghai + PORT: 3020 + DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@${POSTGRES_HOST:-host.docker.internal}:${POSTGRES_PORT:-5432}/rwa_contribution?schema=public + REDIS_HOST: ${REDIS_HOST:-host.docker.internal} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_PASSWORD: ${REDIS_PASSWORD:-} + KAFKA_BROKERS: ${KAFKA_BROKERS:-host.docker.internal:9092} + CDC_TOPIC_ADOPTIONS: ${CDC_TOPIC_ADOPTIONS:-dbserver1.public.adoptions} + CDC_TOPIC_PAYMENTS: ${CDC_TOPIC_PAYMENTS:-dbserver1.public.payment_records} + CDC_CONSUMER_GROUP: contribution-service-cdc-group + ports: + - "3020:3020" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3020/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + restart: unless-stopped + networks: + - rwa-2.0-network + + mining-service: + build: + context: ./mining-service + dockerfile: Dockerfile + container_name: rwa-mining-service + depends_on: + contribution-service: + condition: service_healthy + environment: + NODE_ENV: production + TZ: Asia/Shanghai + PORT: 3021 + DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@${POSTGRES_HOST:-host.docker.internal}:${POSTGRES_PORT:-5432}/rwa_mining?schema=public + REDIS_HOST: ${REDIS_HOST:-host.docker.internal} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_PASSWORD: ${REDIS_PASSWORD:-} + KAFKA_BROKERS: ${KAFKA_BROKERS:-host.docker.internal:9092} + ports: + - "3021:3021" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3021/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + restart: unless-stopped + networks: + - rwa-2.0-network + + trading-service: + build: + context: ./trading-service + dockerfile: Dockerfile + container_name: rwa-trading-service + depends_on: + mining-service: + condition: service_healthy + environment: + NODE_ENV: production + TZ: Asia/Shanghai + PORT: 3022 + DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@${POSTGRES_HOST:-host.docker.internal}:${POSTGRES_PORT:-5432}/rwa_trading?schema=public + REDIS_HOST: ${REDIS_HOST:-host.docker.internal} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_PASSWORD: ${REDIS_PASSWORD:-} + KAFKA_BROKERS: ${KAFKA_BROKERS:-host.docker.internal:9092} + MINING_SERVICE_URL: http://mining-service:3021 + ports: + - "3022:3022" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3022/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + restart: unless-stopped + networks: + - rwa-2.0-network + + mining-admin-service: + build: + context: ./mining-admin-service + dockerfile: Dockerfile + container_name: rwa-mining-admin-service + depends_on: + contribution-service: + condition: service_healthy + mining-service: + condition: service_healthy + environment: + NODE_ENV: production + TZ: Asia/Shanghai + PORT: 3023 + DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@${POSTGRES_HOST:-host.docker.internal}:${POSTGRES_PORT:-5432}/rwa_mining_admin?schema=public + REDIS_HOST: ${REDIS_HOST:-host.docker.internal} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_PASSWORD: ${REDIS_PASSWORD:-} + CONTRIBUTION_SERVICE_URL: http://contribution-service:3020 + MINING_SERVICE_URL: http://mining-service:3021 + TRADING_SERVICE_URL: http://trading-service:3022 + JWT_SECRET: ${ADMIN_JWT_SECRET:-your-admin-jwt-secret-change-in-production} + ports: + - "3023:3023" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3023/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + restart: unless-stopped + networks: + - rwa-2.0-network + + auth-service: + build: + context: ./auth-service + dockerfile: Dockerfile + container_name: rwa-auth-service + environment: + NODE_ENV: production + TZ: Asia/Shanghai + PORT: 3024 + DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@${POSTGRES_HOST:-host.docker.internal}:${POSTGRES_PORT:-5432}/rwa_auth?schema=public + REDIS_HOST: ${REDIS_HOST:-host.docker.internal} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_PASSWORD: ${REDIS_PASSWORD:-} + KAFKA_BROKERS: ${KAFKA_BROKERS:-host.docker.internal:9092} + CDC_TOPIC_USERS: ${CDC_TOPIC_USERS:-dbserver1.public.users} + CDC_CONSUMER_GROUP: auth-service-cdc-group + JWT_SECRET: ${JWT_SECRET:-your-jwt-secret-change-in-production} + JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d} + JWT_REFRESH_EXPIRES_IN: ${JWT_REFRESH_EXPIRES_IN:-30d} + SMS_ACCESS_KEY_ID: ${SMS_ACCESS_KEY_ID:-} + SMS_ACCESS_KEY_SECRET: ${SMS_ACCESS_KEY_SECRET:-} + SMS_SIGN_NAME: ${SMS_SIGN_NAME:-榴莲生态} + SMS_TEMPLATE_CODE: ${SMS_TEMPLATE_CODE:-} + ports: + - "3024:3024" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3024/api/v2/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + restart: unless-stopped + networks: + - rwa-2.0-network + + # =========================================================================== + # Frontend Services (2.0) + # =========================================================================== + + mining-admin-web: + build: + context: ../../frontend/mining-admin-web + dockerfile: Dockerfile + container_name: rwa-mining-admin-web + depends_on: + mining-admin-service: + condition: service_healthy + environment: + NODE_ENV: production + TZ: Asia/Shanghai + PORT: 3100 + NEXT_PUBLIC_API_URL: http://mining-admin-service:3023 + NEXT_PUBLIC_APP_NAME: 挖矿管理后台 + ports: + - "3100:3100" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3100/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 15s + restart: unless-stopped + networks: + - rwa-2.0-network + +networks: + rwa-2.0-network: + driver: bridge + name: rwa-2.0-network diff --git a/backend/services/mining-admin-service/Dockerfile b/backend/services/mining-admin-service/Dockerfile new file mode 100644 index 00000000..15b7336c --- /dev/null +++ b/backend/services/mining-admin-service/Dockerfile @@ -0,0 +1,67 @@ +# ============================================================================= +# Mining Admin Service - Dockerfile +# ============================================================================= + +# 阶段1: 构建 +FROM node:20-alpine AS builder +WORKDIR /app + +# 安装必要的构建工具 +RUN apk add --no-cache python3 make g++ + +# 复制依赖文件 +COPY package.json package-lock.json ./ + +# 安装所有依赖(包括 devDependencies) +RUN npm ci + +# 复制 Prisma schema +COPY prisma ./prisma/ + +# 生成 Prisma Client +RUN npx prisma generate + +# 复制源代码 +COPY . . + +# 构建应用 +RUN npm run build + +# 阶段2: 生产运行 +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV TZ=Asia/Shanghai + +# 安装必要的运行时依赖 +RUN apk add --no-cache curl tzdata + +# 创建非 root 用户 +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nestjs + +# 复制依赖文件并安装生产依赖 +COPY package.json package-lock.json ./ +RUN npm ci --only=production && npm cache clean --force + +# 复制 Prisma schema 并生成 client +COPY prisma ./prisma/ +RUN npx prisma generate + +# 复制构建产物 +COPY --from=builder /app/dist ./dist + +# 设置权限 +RUN chown -R nestjs:nodejs /app +USER nestjs + +# 暴露端口 +EXPOSE 3023 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:3023/health || exit 1 + +# 启动应用 +CMD ["node", "dist/main.js"] diff --git a/backend/services/mining-service/Dockerfile b/backend/services/mining-service/Dockerfile new file mode 100644 index 00000000..2f74ad58 --- /dev/null +++ b/backend/services/mining-service/Dockerfile @@ -0,0 +1,48 @@ +# ============================================================================= +# Mining Service - Dockerfile +# ============================================================================= + +# 阶段1: 构建 +FROM node:20-alpine AS builder +WORKDIR /app + +RUN apk add --no-cache python3 make g++ + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY prisma ./prisma/ +RUN npx prisma generate + +COPY . . +RUN npm run build + +# 阶段2: 生产运行 +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache curl tzdata + +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nestjs + +COPY package.json package-lock.json ./ +RUN npm ci --only=production && npm cache clean --force + +COPY prisma ./prisma/ +RUN npx prisma generate + +COPY --from=builder /app/dist ./dist + +RUN chown -R nestjs:nodejs /app +USER nestjs + +EXPOSE 3021 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:3021/health || exit 1 + +CMD ["node", "dist/main.js"] diff --git a/backend/services/trading-service/Dockerfile b/backend/services/trading-service/Dockerfile new file mode 100644 index 00000000..529f5fcd --- /dev/null +++ b/backend/services/trading-service/Dockerfile @@ -0,0 +1,48 @@ +# ============================================================================= +# Trading Service - Dockerfile +# ============================================================================= + +# 阶段1: 构建 +FROM node:20-alpine AS builder +WORKDIR /app + +RUN apk add --no-cache python3 make g++ + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY prisma ./prisma/ +RUN npx prisma generate + +COPY . . +RUN npm run build + +# 阶段2: 生产运行 +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache curl tzdata + +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nestjs + +COPY package.json package-lock.json ./ +RUN npm ci --only=production && npm cache clean --force + +COPY prisma ./prisma/ +RUN npx prisma generate + +COPY --from=builder /app/dist ./dist + +RUN chown -R nestjs:nodejs /app +USER nestjs + +EXPOSE 3022 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:3022/health || exit 1 + +CMD ["node", "dist/main.js"] diff --git a/frontend/mining-admin-web/Dockerfile b/frontend/mining-admin-web/Dockerfile new file mode 100644 index 00000000..1a8847bb --- /dev/null +++ b/frontend/mining-admin-web/Dockerfile @@ -0,0 +1,65 @@ +# ============================================================================= +# Mining Admin Web - Dockerfile (Next.js) +# ============================================================================= + +# 阶段1: 依赖安装 +FROM node:20-alpine AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# 复制依赖文件 +COPY package.json package-lock.json ./ + +# 安装依赖 +RUN npm ci + +# 阶段2: 构建 +FROM node:20-alpine AS builder +WORKDIR /app + +# 复制依赖 +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# 设置环境变量 +ENV NEXT_TELEMETRY_DISABLED=1 +ENV NODE_ENV=production + +# 构建应用 +RUN npm run build + +# 阶段3: 生产运行 +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +ENV TZ=Asia/Shanghai + +# 安装 curl 用于健康检查 +RUN apk add --no-cache curl tzdata + +# 创建非 root 用户 +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs + +# 复制构建产物 +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +# 设置用户 +USER nextjs + +# 暴露端口 +EXPOSE 3100 + +ENV PORT=3100 +ENV HOSTNAME="0.0.0.0" + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:3100/ || exit 1 + +# 启动应用 +CMD ["node", "server.js"] diff --git a/frontend/mining-admin-web/next.config.js b/frontend/mining-admin-web/next.config.js index 54bc9918..846aef0b 100644 --- a/frontend/mining-admin-web/next.config.js +++ b/frontend/mining-admin-web/next.config.js @@ -1,6 +1,7 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, + output: 'standalone', async rewrites() { return [ {