# MPC Party Service 部署文档 ## 概述 本文档描述 MPC Party Service 的部署架构、部署流程和运维指南。 ## 部署架构 ### 生产环境架构 ``` ┌─────────────────┐ │ Load Balancer │ │ (Nginx/ALB) │ └────────┬────────┘ │ ┌────────────────────────┼────────────────────────┐ │ │ │ ┌───────▼───────┐ ┌────────▼───────┐ ┌────────▼───────┐ │ MPC Service │ │ MPC Service │ │ MPC Service │ │ Node 1 │ │ Node 2 │ │ Node 3 │ │ (Party 1) │ │ (Party 2) │ │ (Party 3) │ └───────┬───────┘ └────────┬───────┘ └────────┬───────┘ │ │ │ └────────────────────────┼────────────────────────┘ │ ┌────────────────────────┼────────────────────────┐ │ │ │ ┌───────▼───────┐ ┌────────▼───────┐ ┌────────▼───────┐ │ MySQL │ │ Redis │ │ Kafka │ │ (Primary) │ │ (Cluster) │ │ (Cluster) │ └───────────────┘ └────────────────┘ └────────────────┘ ``` ### 容器化部署 ``` ┌─────────────────────────────────────────────────────────────────┐ │ Kubernetes Cluster │ ├─────────────────────────────────────────────────────────────────┤ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Namespace: mpc-system │ │ │ ├─────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ mpc-party-1 │ │ mpc-party-2 │ │ mpc-party-3 │ │ │ │ │ │ Deployment │ │ Deployment │ │ Deployment │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ │ │ Shared Services │ │ │ │ │ │ - ConfigMap - Secrets │ │ │ │ │ │ - PVC (Logs) - ServiceAccount │ │ │ │ │ └─────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Infrastructure Services │ │ │ │ - MySQL StatefulSet │ │ │ │ - Redis StatefulSet │ │ │ │ - Kafka StatefulSet │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Docker 部署 ### Dockerfile ```dockerfile # Dockerfile FROM node:18-alpine AS builder WORKDIR /app # 安装依赖 COPY package*.json ./ RUN npm ci --only=production # 复制源代码 COPY . . # 生成 Prisma Client RUN npx prisma generate # 构建 RUN npm run build # 生产镜像 FROM node:18-alpine AS production WORKDIR /app # 复制构建产物 COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/package*.json ./ COPY --from=builder /app/prisma ./prisma # 创建非 root 用户 RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 -G nodejs USER nodejs # 健康检查 HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:3006/api/v1/mpc-party/health || exit 1 # 启动服务 CMD ["node", "dist/main.js"] EXPOSE 3006 ``` ### Docker Compose ```yaml # docker-compose.yml version: '3.8' services: mpc-party-service: build: . ports: - "3006:3006" environment: - NODE_ENV=production - APP_PORT=3006 - DATABASE_URL=mysql://mpc:password@mysql:3306/mpc_service - REDIS_HOST=redis - REDIS_PORT=6379 - JWT_SECRET=${JWT_SECRET} - SHARE_MASTER_KEY=${SHARE_MASTER_KEY} - MPC_PARTY_ID=party-server-1 - MPC_COORDINATOR_URL=http://coordinator:50051 - MPC_MESSAGE_ROUTER_WS_URL=ws://message-router:50052 - KAFKA_BROKERS=kafka:9092 - KAFKA_ENABLED=true depends_on: mysql: condition: service_healthy redis: condition: service_healthy networks: - mpc-network restart: unless-stopped mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_DATABASE=mpc_service - MYSQL_USER=mpc - MYSQL_PASSWORD=${MYSQL_PASSWORD} volumes: - mysql-data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 networks: - mpc-network redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - redis-data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - mpc-network kafka: image: bitnami/kafka:3.5 environment: - KAFKA_CFG_NODE_ID=0 - KAFKA_CFG_PROCESS_ROLES=controller,broker - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093 - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER volumes: - kafka-data:/bitnami/kafka networks: - mpc-network volumes: mysql-data: redis-data: kafka-data: networks: mpc-network: driver: bridge ``` ### 构建和运行 ```bash # 构建镜像 docker build -t mpc-party-service:latest . # 运行 Docker Compose docker-compose up -d # 查看日志 docker-compose logs -f mpc-party-service # 停止服务 docker-compose down ``` --- ## Kubernetes 部署 ### ConfigMap ```yaml # k8s/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: mpc-party-config namespace: mpc-system data: NODE_ENV: "production" APP_PORT: "3006" API_PREFIX: "api/v1" REDIS_PORT: "6379" KAFKA_ENABLED: "true" ``` ### Secrets ```yaml # k8s/secrets.yaml apiVersion: v1 kind: Secret metadata: name: mpc-party-secrets namespace: mpc-system type: Opaque data: JWT_SECRET: SHARE_MASTER_KEY: MYSQL_PASSWORD: ``` ### Deployment ```yaml # k8s/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: mpc-party-service namespace: mpc-system labels: app: mpc-party-service spec: replicas: 3 selector: matchLabels: app: mpc-party-service template: metadata: labels: app: mpc-party-service spec: serviceAccountName: mpc-party-sa containers: - name: mpc-party-service image: your-registry/mpc-party-service:latest imagePullPolicy: Always ports: - containerPort: 3006 protocol: TCP envFrom: - configMapRef: name: mpc-party-config env: - name: MPC_PARTY_ID valueFrom: fieldRef: fieldPath: metadata.name - name: DATABASE_URL valueFrom: secretKeyRef: name: mpc-party-secrets key: DATABASE_URL - name: JWT_SECRET valueFrom: secretKeyRef: name: mpc-party-secrets key: JWT_SECRET - name: SHARE_MASTER_KEY valueFrom: secretKeyRef: name: mpc-party-secrets key: SHARE_MASTER_KEY resources: requests: cpu: "500m" memory: "512Mi" limits: cpu: "2000m" memory: "2Gi" livenessProbe: httpGet: path: /api/v1/mpc-party/health port: 3006 initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /api/v1/mpc-party/health port: 3006 initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 volumeMounts: - name: logs mountPath: /app/logs volumes: - name: logs emptyDir: {} ``` ### Service ```yaml # k8s/service.yaml apiVersion: v1 kind: Service metadata: name: mpc-party-service namespace: mpc-system spec: type: ClusterIP selector: app: mpc-party-service ports: - port: 3006 targetPort: 3006 protocol: TCP ``` ### Ingress ```yaml # k8s/ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: mpc-party-ingress namespace: mpc-system annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/proxy-body-size: "10m" spec: ingressClassName: nginx tls: - hosts: - mpc-api.example.com secretName: mpc-tls-secret rules: - host: mpc-api.example.com http: paths: - path: /api/v1/mpc-party pathType: Prefix backend: service: name: mpc-party-service port: number: 3006 ``` ### HPA (Horizontal Pod Autoscaler) ```yaml # k8s/hpa.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: mpc-party-hpa namespace: mpc-system spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: mpc-party-service minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 ``` ### 部署命令 ```bash # 创建命名空间 kubectl create namespace mpc-system # 应用配置 kubectl apply -f k8s/configmap.yaml kubectl apply -f k8s/secrets.yaml kubectl apply -f k8s/deployment.yaml kubectl apply -f k8s/service.yaml kubectl apply -f k8s/ingress.yaml kubectl apply -f k8s/hpa.yaml # 检查部署状态 kubectl get pods -n mpc-system kubectl get svc -n mpc-system kubectl get ingress -n mpc-system # 查看日志 kubectl logs -f deployment/mpc-party-service -n mpc-system # 扩容/缩容 kubectl scale deployment mpc-party-service --replicas=5 -n mpc-system ``` --- ## 环境配置 ### 开发环境 ```env NODE_ENV=development APP_PORT=3006 LOG_LEVEL=debug DATABASE_URL=mysql://root:password@localhost:3306/mpc_service_dev REDIS_HOST=localhost REDIS_PORT=6379 KAFKA_ENABLED=false ``` ### 测试环境 ```env NODE_ENV=test APP_PORT=3006 LOG_LEVEL=info DATABASE_URL=mysql://mpc:password@mysql-test:3306/mpc_service_test REDIS_HOST=redis-test REDIS_PORT=6379 KAFKA_ENABLED=true KAFKA_BROKERS=kafka-test:9092 ``` ### 生产环境 ```env NODE_ENV=production APP_PORT=3006 LOG_LEVEL=warn DATABASE_URL=mysql://mpc:${DB_PASSWORD}@mysql-prod:3306/mpc_service REDIS_HOST=redis-prod REDIS_PORT=6379 REDIS_PASSWORD=${REDIS_PASSWORD} KAFKA_ENABLED=true KAFKA_BROKERS=kafka-prod-1:9092,kafka-prod-2:9092,kafka-prod-3:9092 # 安全配置 JWT_SECRET=${JWT_SECRET} SHARE_MASTER_KEY=${SHARE_MASTER_KEY} ``` --- ## 数据库迁移 ### Prisma 迁移 ```bash # 生产环境迁移 npx prisma migrate deploy # 开发环境迁移 npx prisma migrate dev # 重置数据库(仅开发环境) npx prisma migrate reset ``` ### 迁移策略 1. **零停机迁移** - 使用蓝绿部署或金丝雀发布 - 确保迁移向后兼容 2. **回滚计划** - 保留迁移历史 - 准备回滚脚本 ```bash # 回滚到特定版本 npx prisma migrate resolve --rolled-back ``` --- ## 监控和告警 ### Prometheus 指标 ```yaml # prometheus/mpc-service-rules.yaml groups: - name: mpc-service rules: - alert: HighErrorRate expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1 for: 5m labels: severity: critical annotations: summary: High error rate detected - alert: HighLatency expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 2 for: 5m labels: severity: warning annotations: summary: High latency detected - alert: ServiceDown expr: up{job="mpc-party-service"} == 0 for: 1m labels: severity: critical annotations: summary: MPC Party Service is down ``` ### Grafana Dashboard 关键监控指标: - 请求速率和延迟 - 错误率 - CPU 和内存使用率 - 活跃连接数 - MPC 操作统计 ### 日志聚合 使用 ELK Stack 或 Loki 进行日志聚合: ```yaml # fluentd 配置 @type tail path /app/logs/*.log pos_file /var/log/fluentd/mpc-service.log.pos tag mpc.service @type json @type elasticsearch host elasticsearch port 9200 logstash_format true logstash_prefix mpc-service ``` --- ## 安全配置 ### TLS 配置 ```yaml # 使用 cert-manager 自动管理证书 apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: mpc-tls namespace: mpc-system spec: secretName: mpc-tls-secret issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - mpc-api.example.com ``` ### 网络策略 ```yaml # k8s/network-policy.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: mpc-party-network-policy namespace: mpc-system spec: podSelector: matchLabels: app: mpc-party-service policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: matchLabels: name: ingress-nginx ports: - protocol: TCP port: 3006 egress: - to: - podSelector: matchLabels: app: mysql ports: - protocol: TCP port: 3306 - to: - podSelector: matchLabels: app: redis ports: - protocol: TCP port: 6379 - to: - podSelector: matchLabels: app: kafka ports: - protocol: TCP port: 9092 ``` ### Secret 管理 推荐使用: - HashiCorp Vault - AWS Secrets Manager - Kubernetes External Secrets ```yaml # 使用 External Secrets Operator apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: mpc-party-secrets namespace: mpc-system spec: refreshInterval: 1h secretStoreRef: kind: ClusterSecretStore name: vault-backend target: name: mpc-party-secrets creationPolicy: Owner data: - secretKey: JWT_SECRET remoteRef: key: mpc-service/jwt-secret - secretKey: SHARE_MASTER_KEY remoteRef: key: mpc-service/share-master-key ``` --- ## 备份和恢复 ### 数据库备份 ```bash # MySQL 备份 mysqldump -h mysql-host -u mpc -p mpc_service > backup_$(date +%Y%m%d_%H%M%S).sql # 压缩备份 gzip backup_*.sql # 上传到 S3 aws s3 cp backup_*.sql.gz s3://your-bucket/backups/mpc-service/ ``` ### 自动备份 CronJob ```yaml # k8s/backup-cronjob.yaml apiVersion: batch/v1 kind: CronJob metadata: name: mysql-backup namespace: mpc-system spec: schedule: "0 2 * * *" # 每天凌晨 2 点 jobTemplate: spec: template: spec: containers: - name: backup image: mysql:8.0 command: - /bin/bash - -c - | mysqldump -h mysql -u mpc -p${MYSQL_PASSWORD} mpc_service | \ gzip > /backup/mpc_$(date +%Y%m%d_%H%M%S).sql.gz envFrom: - secretRef: name: mpc-party-secrets volumeMounts: - name: backup-volume mountPath: /backup restartPolicy: OnFailure volumes: - name: backup-volume persistentVolumeClaim: claimName: backup-pvc ``` ### 恢复流程 ```bash # 1. 停止服务 kubectl scale deployment mpc-party-service --replicas=0 -n mpc-system # 2. 恢复数据库 gunzip -c backup_20240115_020000.sql.gz | mysql -h mysql-host -u mpc -p mpc_service # 3. 启动服务 kubectl scale deployment mpc-party-service --replicas=3 -n mpc-system # 4. 验证服务 curl https://mpc-api.example.com/api/v1/mpc-party/health ``` --- ## 故障排除 ### 常见问题 #### 1. Pod 无法启动 ```bash # 查看 Pod 事件 kubectl describe pod -n mpc-system # 查看日志 kubectl logs -n mpc-system --previous ``` #### 2. 数据库连接失败 ```bash # 检查数据库连接 kubectl exec -it -n mpc-system -- \ mysql -h mysql -u mpc -p -e "SELECT 1" ``` #### 3. Redis 连接失败 ```bash # 检查 Redis 连接 kubectl exec -it -n mpc-system -- \ redis-cli -h redis ping ``` #### 4. 服务不可达 ```bash # 检查 Service kubectl get svc -n mpc-system kubectl get endpoints mpc-party-service -n mpc-system # 检查 Ingress kubectl describe ingress mpc-party-ingress -n mpc-system ``` ### 健康检查端点 ```bash # 检查服务健康 curl -v https://mpc-api.example.com/api/v1/mpc-party/health ``` ### 日志查询 ```bash # 查看实时日志 kubectl logs -f deployment/mpc-party-service -n mpc-system # 查看特定时间范围的日志 kubectl logs deployment/mpc-party-service -n mpc-system --since=1h # 搜索错误日志 kubectl logs deployment/mpc-party-service -n mpc-system | grep -i error ``` --- ## 版本发布流程 ### 1. 构建新版本 ```bash # 打标签 git tag -a v1.2.3 -m "Release v1.2.3" git push origin v1.2.3 # 构建镜像 docker build -t your-registry/mpc-party-service:v1.2.3 . docker push your-registry/mpc-party-service:v1.2.3 ``` ### 2. 滚动更新 ```bash # 更新镜像 kubectl set image deployment/mpc-party-service \ mpc-party-service=your-registry/mpc-party-service:v1.2.3 \ -n mpc-system # 监控更新状态 kubectl rollout status deployment/mpc-party-service -n mpc-system ``` ### 3. 回滚 ```bash # 查看历史 kubectl rollout history deployment/mpc-party-service -n mpc-system # 回滚到上一版本 kubectl rollout undo deployment/mpc-party-service -n mpc-system # 回滚到特定版本 kubectl rollout undo deployment/mpc-party-service \ --to-revision=2 -n mpc-system ``` --- ## 联系与支持 - **技术支持**: tech@example.com - **紧急问题**: oncall@example.com - **文档**: https://docs.example.com/mpc-service