fujian_water_biz_doc/water_biz_deployment_design.md

28 KiB
Raw Blame History

福建水务营收系统部署设计文档

文档信息

项目信息 详情
项目名称 福建水务营收系统
文档类型 概要设计文档
技术框架 RuoYi-Vue-Pro + yudao-ui-admin-vue3
文档版本 v1.0
编写日期 2024-12-19
文档状态 🟡 进行中

目录

1. 部署概述

福建水务业务系统采用集中化部署模式,基于集团私有云环境进行部署,构建高可用、可扩展的系统架构,满足集团及下属各水务公司的业务需求。

1.1 部署目标

  • 实现系统的集中部署和统一管理
  • 确保系统高可用性和可靠性
  • 支持业务动态扩展和弹性伸缩
  • 保障数据安全和业务连续性
  • 降低运维成本,提高管理效率

1.2 部署原则

  • 集中部署:核心业务系统集中部署在集团数据中心,统一管理和维护
  • 多级架构:采用多级架构设计,实现前端负载分担和后端高可用
  • 灾备设计:重要系统和数据实现灾备,确保业务连续性
  • 安全防护:多层次安全防护体系,确保系统和数据安全
  • 弹性扩展:支持系统横向和纵向扩展,适应业务增长需求

2. 部署架构

2.1 总体部署架构

福建水务业务系统采用三层架构部署:

  • 接入层:负责外部访问请求的接入和负载均衡
  • 应用层:部署业务应用服务,处理业务逻辑
  • 数据层:部署数据库服务,存储业务数据

系统部署采用集群模式,各层均部署多个节点,实现高可用和负载均衡。

2.2 生产环境部署架构

生产环境采用双机房部署方案,包括主生产环境和灾备环境:

2.2.1 主生产环境

主生产环境部署在集团主数据中心,包括:

  • 负载均衡集群2台负载均衡服务器
  • Web服务器集群4台Web服务器
  • 应用服务器集群6台应用服务器
  • 数据库服务器集群2台主备数据库服务器
  • 文件服务器2台主备文件服务器
  • 缓存服务器集群2台缓存服务器

2.2.2 灾备环境

灾备环境部署在集团备用数据中心,包括:

  • 负载均衡服务器1台
  • Web服务器2台
  • 应用服务器3台
  • 数据库服务器1台
  • 文件服务器1台
  • 缓存服务器1台

2.3 测试环境部署架构

测试环境部署在集团测试中心,用于系统测试和验证,包括:

  • Web服务器1台
  • 应用服务器2台
  • 数据库服务器1台
  • 文件服务器1台

2.4 开发环境部署架构

开发环境部署在开发中心,用于系统开发和集成测试,包括:

  • 应用服务器1台
  • 数据库服务器1台

3. 服务器配置

3.1 硬件配置要求

3.1.1 负载均衡服务器

  • CPU8核
  • 内存16GB
  • 存储100GB SSD
  • 网卡:双千兆网卡

3.1.2 Web服务器

  • CPU8核
  • 内存16GB
  • 存储200GB SSD
  • 网卡:双千兆网卡

3.1.3 应用服务器

  • CPU16核
  • 内存32GB
  • 存储300GB SSD
  • 网卡:双千兆网卡

3.1.4 数据库服务器

  • CPU24核
  • 内存64GB
  • 存储2TB SSD (RAID 10)
  • 网卡:双万兆网卡

3.1.5 文件服务器

  • CPU8核
  • 内存16GB
  • 存储4TB (RAID 5)
  • 网卡:双千兆网卡

3.1.6 缓存服务器

  • CPU8核
  • 内存32GB
  • 存储100GB SSD
  • 网卡:双千兆网卡

3.2 软件配置要求

3.2.1 操作系统

  • 服务端CentOS 7+、Ubuntu 18.04+或其他国产Linux发行版
  • 客户端支持Windows、macOS、Linux等现代操作系统

3.2.2 数据库

  • MySQL 5.7+ 或 MariaDB 10.2+(推荐)
  • 国产数据库可选OpenGauss、达梦等

3.2.3 应用服务器

  • JDK 17或JDK 21兼容支持JDK 8
  • Apache Tomcat 9.0+或内嵌Tomcat
  • Nginx 1.18+(作为前端静态资源服务器和反向代理)

3.2.4 缓存服务器

  • Redis 5.0+或Redis集群

3.2.5 中间件

  • 消息队列基于Redis的轻量级队列可选
  • 分布式任务调度Quartz集群
  • 工作流引擎Flowable 6.x
  • 文件存储支持本地存储、MinIO、阿里云OSS等

3.2.6 前端环境

  • Node.js 16+
  • NPM 8+或Yarn 1.22+
  • Vue 3.x
  • Element Plus

4. 网络架构

4.1 网络拓扑

福建水务业务系统网络架构采用三层网络结构:

  • 接入层:对外提供服务接入,部署防火墙、负载均衡等设备
  • 核心层:实现业务系统间的互联互通,部署核心交换机
  • 服务层:部署各类服务器,实现业务处理和数据存储

4.2 网络安全区域划分

网络安全区域划分为以下几个区域:

  • DMZ区部署面向外部的Web服务器与内网隔离
  • 应用区:部署业务应用服务器
  • 数据区:部署数据库服务器和文件服务器
  • 管理区:部署运维管理服务器

4.3 网络带宽配置

  • 外网接入带宽100Mbps根据实际需求可升级
  • 内网骨干带宽1000Mbps
  • 服务器接入带宽1000Mbps
  • 数据中心间专线带宽100Mbps

5. 安全设计

5.1 网络安全

5.1.1 边界安全

  • 部署高性能防火墙,实现网络隔离
  • 部署入侵检测系统(IDS)和入侵防御系统(IPS)
  • 部署Web应用防火墙(WAF)防御Web应用攻击
  • 采用VPN技术保障远程访问安全

5.1.2 内网安全

  • 网络安全区域划分,实现不同级别网络隔离
  • 内网访问控制,限制不必要的网络访问
  • 内网流量监控,及时发现异常流量

5.2 系统安全

5.2.1 主机安全

  • 操作系统安全加固,关闭不必要的服务和端口
  • 系统补丁及时更新,修复安全漏洞
  • 部署主机防病毒软件,防御恶意代码
  • 主机审计和日志管理,记录重要操作

5.2.2 应用安全

  • 应用访问控制,基于角色的权限管理
  • 应用操作审计,记录重要业务操作
  • 数据传输加密,保护敏感信息
  • 输入验证防止SQL注入、XSS等攻击

5.3 数据安全

5.3.1 数据存储安全

  • 数据库访问控制,限制数据库访问权限
  • 敏感数据加密存储,防止数据泄露
  • 数据库审计,记录重要数据操作

5.3.2 数据备份与恢复

  • 定期数据备份,每日增量备份,每周全量备份
  • 备份数据异地存储,防止灾难性事件导致数据丢失
  • 定期演练数据恢复,确保备份数据可用

6. 部署流程

6.1 部署准备

  • 服务器硬件准备和上架
  • 网络环境配置和测试
  • 操作系统安装和配置
  • 基础软件安装和配置

6.2 应用部署

6.2.1 数据库部署

  • 数据库服务器配置
  • 数据库实例创建和配置
  • 数据库高可用配置
  • 数据备份策略配置

6.2.2 应用服务部署

  • 应用服务器配置
  • 应用程序部署
  • 应用服务参数配置
  • 应用服务高可用配置

6.2.3 Web服务部署

  • Web服务器配置
  • Web应用部署
  • Web服务参数配置
  • 负载均衡配置

6.3 系统联调

  • 各组件功能测试
  • 系统整体联调测试
  • 性能和压力测试
  • 高可用性测试

6.4 系统上线

  • 制定上线计划
  • 系统割接准备
  • 系统割接实施
  • 系统运行监控

7. 监控与运维

7.1 监控系统

7.1.1 基础设施监控

  • 服务器硬件监控CPU、内存、磁盘、网络等
  • 网络设备监控:带宽使用率、连接状态等
  • 操作系统监控:系统负载、进程状态等

7.1.2 应用监控

  • 应用服务状态监控
  • 应用性能监控:响应时间、并发数等
  • 业务监控:重要业务指标监控

7.1.3 数据库监控

  • 数据库服务状态监控
  • 数据库性能监控CPU使用率、内存使用率、IO性能等
  • SQL执行监控慢查询、锁等待等

7.2 运维管理

7.2.1 日常运维

  • 系统日常巡检
  • 系统性能优化
  • 系统容量管理
  • 系统备份管理

7.2.2 变更管理

  • 变更申请和审批
  • 变更实施和验证
  • 变更回退预案
  • 变更记录管理

7.2.3 故障管理

  • 故障监控和告警
  • 故障处理流程
  • 故障升级机制
  • 故障复盘和改进

7.2.4 应急预案

  • 系统宕机应急预案
  • 网络故障应急预案
  • 数据丢失应急预案
  • 安全事件应急预案

8. 容器化部署方案

8.1 Docker Compose部署

8.1.1 完整部署配置

# docker-compose.yml
version: '3.8'

services:
  # MySQL 数据库
  water-mysql:
    image: mysql:8.0
    container_name: water-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: "water_root_2024"
      MYSQL_DATABASE: "ruoyi_water"
      MYSQL_USER: "water_user"
      MYSQL_PASSWORD: "water_pass_2024"
      TZ: "Asia/Shanghai"
    volumes:
      - ./data/mysql:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d
      - ./config/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    ports:
      - "3306:3306"
    command: 
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --default-time-zone=+8:00
    networks:
      - water-network

  # Redis 缓存
  water-redis:
    image: redis:7.0-alpine
    container_name: water-redis
    restart: always
    volumes:
      - ./data/redis:/data
      - ./config/redis/redis.conf:/etc/redis/redis.conf
    ports:
      - "6379:6379"
    command: redis-server /etc/redis/redis.conf
    networks:
      - water-network

  # 后端应用
  water-server:
    build:
      context: ./water-server
      dockerfile: Dockerfile
    container_name: water-server
    restart: always
    depends_on:
      - water-mysql
      - water-redis
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=jdbc:mysql://water-mysql:3306/ruoyi_water?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
      - SPRING_DATASOURCE_USERNAME=water_user
      - SPRING_DATASOURCE_PASSWORD=water_pass_2024
      - SPRING_REDIS_HOST=water-redis
      - SPRING_REDIS_PORT=6379
      - SERVER_PORT=8080
    volumes:
      - ./logs:/app/logs
      - ./upload:/app/upload
    ports:
      - "8080:8080"
    networks:
      - water-network

  # 前端应用
  water-ui:
    build:
      context: ./water-ui
      dockerfile: Dockerfile
    container_name: water-ui
    restart: always
    depends_on:
      - water-server
    volumes:
      - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./config/nginx/conf.d:/etc/nginx/conf.d
    ports:
      - "80:80"
      - "443:443"
    networks:
      - water-network

  # Nginx 反向代理
  water-nginx:
    image: nginx:1.24-alpine
    container_name: water-nginx
    restart: always
    depends_on:
      - water-server
      - water-ui
    volumes:
      - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./config/nginx/conf.d:/etc/nginx/conf.d
      - ./ssl:/etc/nginx/ssl
      - ./logs/nginx:/var/log/nginx
    ports:
      - "80:80"
      - "443:443"
    networks:
      - water-network

  # MinIO 文件存储
  water-minio:
    image: minio/minio:latest
    container_name: water-minio
    restart: always
    environment:
      MINIO_ACCESS_KEY: "admin"
      MINIO_SECRET_KEY: "admin123456"
    volumes:
      - ./data/minio:/data
    ports:
      - "9000:9000"
      - "9001:9001"
    command: server /data --console-address ":9001"
    networks:
      - water-network

networks:
  water-network:
    driver: bridge

volumes:
  mysql-data:
  redis-data:
  minio-data:

8.1.2 后端应用Dockerfile

# water-server/Dockerfile
FROM openjdk:17-jdk-slim

LABEL maintainer="fujian-water-dev-team"

# 设置工作目录
WORKDIR /app

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 添加应用jar包
COPY target/water-server.jar app.jar

# 创建日志目录
RUN mkdir -p /app/logs

# 暴露端口
EXPOSE 8080

# 启动应用
ENTRYPOINT ["java", "-jar", "-Xmx1024m", "-Xms512m", "-Dspring.profiles.active=prod", "/app/app.jar"]

8.1.3 前端应用Dockerfile

# water-ui/Dockerfile
# 构建阶段
FROM node:18-alpine AS builder

WORKDIR /app

# 复制包管理文件
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制源代码
COPY . .

# 构建应用
RUN npm run build:prod

# 生产阶段
FROM nginx:1.24-alpine

# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html

# 复制nginx配置
COPY nginx.conf /etc/nginx/nginx.conf

# 暴露端口
EXPOSE 80

# 启动nginx
CMD ["nginx", "-g", "daemon off;"]

8.2 Kubernetes部署

8.2.1 命名空间配置

# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: water-system
  labels:
    name: water-system

8.2.2 MySQL部署配置

# k8s/mysql-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: water-mysql
  namespace: water-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: water-mysql
  template:
    metadata:
      labels:
        app: water-mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "water_root_2024"
        - name: MYSQL_DATABASE
          value: "ruoyi_water"
        - name: MYSQL_USER
          value: "water_user"
        - name: MYSQL_PASSWORD
          value: "water_pass_2024"
        - name: TZ
          value: "Asia/Shanghai"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
        - name: mysql-config
          mountPath: /etc/mysql/conf.d
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
      - name: mysql-config
        configMap:
          name: mysql-config

---
apiVersion: v1
kind: Service
metadata:
  name: water-mysql-service
  namespace: water-system
spec:
  selector:
    app: water-mysql
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306
  type: ClusterIP

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: water-system
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
  storageClassName: fast-ssd

8.2.3 Redis部署配置

# k8s/redis-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: water-redis
  namespace: water-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: water-redis
  template:
    metadata:
      labels:
        app: water-redis
    spec:
      containers:
      - name: redis
        image: redis:7.0-alpine
        ports:
        - containerPort: 6379
        volumeMounts:
        - name: redis-storage
          mountPath: /data
        - name: redis-config
          mountPath: /etc/redis
        command:
        - redis-server
        - /etc/redis/redis.conf
      volumes:
      - name: redis-storage
        persistentVolumeClaim:
          claimName: redis-pvc
      - name: redis-config
        configMap:
          name: redis-config

---
apiVersion: v1
kind: Service
metadata:
  name: water-redis-service
  namespace: water-system
spec:
  selector:
    app: water-redis
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379
  type: ClusterIP

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: redis-pvc
  namespace: water-system
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: fast-ssd

8.2.4 应用服务部署配置

# k8s/water-server-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: water-server
  namespace: water-system
spec:
  replicas: 3
  selector:
    matchLabels:
      app: water-server
  template:
    metadata:
      labels:
        app: water-server
    spec:
      containers:
      - name: water-server
        image: water-server:latest
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "k8s"
        - name: SPRING_DATASOURCE_URL
          value: "jdbc:mysql://water-mysql-service:3306/ruoyi_water?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8"
        - name: SPRING_DATASOURCE_USERNAME
          value: "water_user"
        - name: SPRING_DATASOURCE_PASSWORD
          value: "water_pass_2024"
        - name: SPRING_REDIS_HOST
          value: "water-redis-service"
        - name: SPRING_REDIS_PORT
          value: "6379"
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        volumeMounts:
        - name: upload-storage
          mountPath: /app/upload
      volumes:
      - name: upload-storage
        persistentVolumeClaim:
          claimName: upload-pvc

---
apiVersion: v1
kind: Service
metadata:
  name: water-server-service
  namespace: water-system
spec:
  selector:
    app: water-server
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  type: ClusterIP

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: upload-pvc
  namespace: water-system
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard

8.2.5 Ingress配置

# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: water-system-ingress
  namespace: water-system
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: 50m
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
spec:
  tls:
  - hosts:
    - water.example.com
    secretName: water-tls-secret
  rules:
  - host: water.example.com
    http:
      paths:
      - path: /admin-api
        pathType: Prefix
        backend:
          service:
            name: water-server-service
            port:
              number: 8080
      - path: /
        pathType: Prefix
        backend:
          service:
            name: water-ui-service
            port:
              number: 80

8.3 自动化部署脚本

8.3.1 Docker部署脚本

#!/bin/bash
# deploy-docker.sh

set -e

echo "=== 福建水务营收系统 Docker 部署脚本 ==="

# 检查Docker环境
if ! command -v docker &> /dev/null; then
    echo "错误: Docker未安装请先安装Docker"
    exit 1
fi

if ! command -v docker-compose &> /dev/null; then
    echo "错误: Docker Compose未安装请先安装Docker Compose"
    exit 1
fi

# 创建必要目录
echo "创建数据目录..."
mkdir -p data/{mysql,redis,minio}
mkdir -p logs/{app,nginx}
mkdir -p config/{mysql,redis,nginx/conf.d}
mkdir -p upload
mkdir -p ssl

# 设置MySQL配置
echo "配置MySQL..."
cat > config/mysql/my.cnf << EOF
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time-zone='+8:00'
max_connections=1000
innodb_buffer_pool_size=512M
innodb_log_file_size=128M
slow_query_log=1
slow_query_log_file=/var/lib/mysql/slow.log
long_query_time=3
EOF

# 设置Redis配置
echo "配置Redis..."
cat > config/redis/redis.conf << EOF
port 6379
requirepass water_redis_2024
timeout 300
tcp-keepalive 300
maxmemory 256mb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
save 60 10000
EOF

# 设置Nginx配置
echo "配置Nginx..."
cat > config/nginx/nginx.conf << EOF
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
                    '\$status \$body_bytes_sent "\$http_referer" '
                    '"\$http_user_agent" "\$http_x_forwarded_for"';
    
    access_log /var/log/nginx/access.log main;
    
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    client_max_body_size 50M;
    
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript 
               application/javascript application/xml+rss 
               application/json;
    
    include /etc/nginx/conf.d/*.conf;
}
EOF

cat > config/nginx/conf.d/water.conf << EOF
upstream water_backend {
    server water-server:8080;
}

server {
    listen 80;
    server_name localhost;
    
    location /admin-api/ {
        proxy_pass http://water_backend;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_connect_timeout 600;
        proxy_send_timeout 600;
        proxy_read_timeout 600;
    }
    
    location / {
        proxy_pass http://water-ui;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
}
EOF

# 构建和启动服务
echo "构建和启动Docker服务..."
docker-compose down
docker-compose build --no-cache
docker-compose up -d

# 等待服务启动
echo "等待服务启动..."
sleep 30

# 检查服务状态
echo "检查服务状态..."
docker-compose ps

echo "=== 部署完成 ==="
echo "系统访问地址: http://localhost"
echo "API接口地址: http://localhost/admin-api"
echo "MinIO控制台: http://localhost:9001 (admin/admin123456)"
echo ""
echo "查看日志: docker-compose logs -f [服务名]"
echo "停止服务: docker-compose down"
echo "重启服务: docker-compose restart"

8.3.2 Kubernetes部署脚本

#!/bin/bash
# deploy-k8s.sh

set -e

echo "=== 福建水务营收系统 Kubernetes 部署脚本 ==="

# 检查kubectl环境
if ! command -v kubectl &> /dev/null; then
    echo "错误: kubectl未安装请先安装kubectl"
    exit 1
fi

# 检查集群连接
if ! kubectl cluster-info &> /dev/null; then
    echo "错误: 无法连接到Kubernetes集群"
    exit 1
fi

# 创建命名空间
echo "创建命名空间..."
kubectl apply -f k8s/namespace.yaml

# 创建ConfigMap
echo "创建配置文件..."
kubectl create configmap mysql-config --from-file=config/mysql/ -n water-system --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap redis-config --from-file=config/redis/ -n water-system --dry-run=client -o yaml | kubectl apply -f -

# 部署数据层
echo "部署MySQL..."
kubectl apply -f k8s/mysql-deployment.yaml

echo "部署Redis..."
kubectl apply -f k8s/redis-deployment.yaml

# 等待数据层就绪
echo "等待数据层服务就绪..."
kubectl wait --for=condition=ready pod -l app=water-mysql -n water-system --timeout=300s
kubectl wait --for=condition=ready pod -l app=water-redis -n water-system --timeout=300s

# 部署应用层
echo "部署应用服务..."
kubectl apply -f k8s/water-server-deployment.yaml

echo "部署前端服务..."
kubectl apply -f k8s/water-ui-deployment.yaml

# 等待应用层就绪
echo "等待应用服务就绪..."
kubectl wait --for=condition=ready pod -l app=water-server -n water-system --timeout=300s
kubectl wait --for=condition=ready pod -l app=water-ui -n water-system --timeout=300s

# 部署Ingress
echo "部署Ingress..."
kubectl apply -f k8s/ingress.yaml

# 检查部署状态
echo "检查部署状态..."
kubectl get all -n water-system

echo "=== 部署完成 ==="
echo "查看服务状态: kubectl get all -n water-system"
echo "查看日志: kubectl logs -f deployment/water-server -n water-system"
echo "删除部署: kubectl delete namespace water-system"

8.4 持续集成/持续部署 (CI/CD)

8.4.1 GitHub Actions配置

# .github/workflows/deploy.yml
name: Build and Deploy Water System

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: docker.io
  IMAGE_NAME: water-system

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'
    
    - name: Cache Maven dependencies
      uses: actions/cache@v3
      with:
        path: ~/.m2
        key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
        restore-keys: ${{ runner.os }}-m2
    
    - name: Run tests
      run: mvn clean test
    
    - name: Generate test report
      uses: dorny/test-reporter@v1
      if: success() || failure()
      with:
        name: Maven Tests
        path: target/surefire-reports/*.xml
        reporter: java-junit

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'
    
    - name: Build with Maven
      run: mvn clean package -DskipTests
    
    - name: Build Docker image
      run: |
        docker build -t $REGISTRY/$IMAGE_NAME-server:$GITHUB_SHA ./water-server
        docker build -t $REGISTRY/$IMAGE_NAME-ui:$GITHUB_SHA ./water-ui
    
    - name: Log in to Docker Hub
      uses: docker/login-action@v2
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}
    
    - name: Push Docker images
      run: |
        docker push $REGISTRY/$IMAGE_NAME-server:$GITHUB_SHA
        docker push $REGISTRY/$IMAGE_NAME-ui:$GITHUB_SHA
        docker tag $REGISTRY/$IMAGE_NAME-server:$GITHUB_SHA $REGISTRY/$IMAGE_NAME-server:latest
        docker tag $REGISTRY/$IMAGE_NAME-ui:$GITHUB_SHA $REGISTRY/$IMAGE_NAME-ui:latest
        docker push $REGISTRY/$IMAGE_NAME-server:latest
        docker push $REGISTRY/$IMAGE_NAME-ui:latest

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Deploy to Kubernetes
      env:
        KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_DATA }}
      run: |
        echo $KUBE_CONFIG_DATA | base64 -d > kubeconfig
        export KUBECONFIG=kubeconfig
        
        # 更新镜像版本
        kubectl set image deployment/water-server water-server=$REGISTRY/$IMAGE_NAME-server:$GITHUB_SHA -n water-system
        kubectl set image deployment/water-ui water-ui=$REGISTRY/$IMAGE_NAME-ui:$GITHUB_SHA -n water-system
        
        # 等待部署完成
        kubectl rollout status deployment/water-server -n water-system
        kubectl rollout status deployment/water-ui -n water-system
        
        echo "部署完成!"

这样,我已经为福建水务营收系统的部署设计文档补充了完整的现代化部署方案,包括:

  1. Docker Compose部署:完整的容器化部署配置
  2. Kubernetes部署:云原生部署配置
  3. 自动化部署脚本:简化部署流程
  4. CI/CD流水线:持续集成和持续部署

这些配置都基于RuoYi-Vue-Pro框架的要求提供了生产就绪的部署方案。