QDAirPortBackend0122/doc/deploy/deploy-design.md
2026-01-22 13:19:47 +08:00

12 KiB
Raw Permalink Blame History

QAUP 极简离线部署方案

Spring Boot + Redis + PostgreSQL with PostGIS一键部署、一键升级

1. 设计原则

  • 极简优先:最少的文件,最少的步骤
  • 离线部署:预打包所有依赖,无需联网
  • 一键操作:部署和升级都是一条命令
  • 配置灵活:关键配置可外部修改
  • 自动化迁移数据库版本自动管理Flyway

2. 打包准备(开发环境执行一次)

2.1 打包脚本package-all.sh

#!/bin/bash
echo "=== QAUP 打包脚本 ==="

# 1. 构建应用在macOS上
mvn clean package -DskipTests

# 2. 拉取并导出镜像(在服务器上)
docker pull m.daocloud.io/docker.io/postgis/postgis:17-3.5-alpine
docker pull m.daocloud.io/docker.io/library/redis:8.0-alpine  
docker pull m.daocloud.io/docker.io/library/eclipse-temurin:21-jre

# 导出镜像
docker save m.daocloud.io/docker.io/postgis/postgis:17-3.5-alpine \
          m.daocloud.io/docker.io/library/redis:8.0-alpine \
          m.daocloud.io/docker.io/library/eclipse-temurin:21-jre | gzip > images.tar.gz

# 3. 准备部署包
mkdir -p qaup-deploy
cp qaup-admin/target/qaup-admin.jar qaup-deploy/app.jar
cp deploy/docker-compose.yml qaup-deploy/
cp deploy/config.yml qaup-deploy/
cp images.tar.gz qaup-deploy/

# 4. 打包
tar -czf qaup-deploy-$(date +%Y%m%d-%H%M%S).tar.gz -C qaup-deploy .
echo "打包完成: qaup-deploy-$(date +%Y%m%d-%H%M%S).tar.gz"

2.2 部署包结构

qaup-deploy.tar.gz
├── images.tar.gz                         # Docker镜像包PostGIS + Redis + Java21
├── docker-compose.yml                    # 服务编排(包含健康检查)
├── app.jar                               # 应用程序
├── config.yml                            # 外部配置(可修改)
├── deploy-all.sh                         # 一键部署脚本
├── deploy-update.sh                      # 一键升级脚本
├── DeployGuide.md                        # 详细部署指南
└── qaup_database_export.sql              # 完整数据库备份(可选)

3. docker-compose.yml当前实际版本

services:
  # PostgreSQL + PostGIS 数据库服务
  qaup-postgres:
    image: m.daocloud.io/docker.io/postgis/postgis:17-3.5-alpine
    container_name: qaup-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: qaup
      POSTGRES_USER: qaup
      POSTGRES_PASSWORD: qaup123
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U qaup"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Redis 缓存服务
  qaup-redis:
    image: m.daocloud.io/docker.io/library/redis:8.0-alpine
    container_name: qaup-redis
    restart: unless-stopped
    command: ["redis-server", "--maxmemory", "256mb", "--maxmemory-policy", "allkeys-lru"]
    volumes:
      - ./data/redis:/data
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 10s
      retries: 3

  # QAUP 应用服务Java 21
  qaup-app:
    image: m.daocloud.io/docker.io/library/eclipse-temurin:21-jre
    container_name: qaup-app
    restart: unless-stopped
    environment:
      SPRING_PROFILES_ACTIVE: prod
      LOG_PATH: /app/logs
      # 数据库连接配置
      DB_HOST: qaup-postgres
      DB_PORT: 5432
      DB_NAME: qaup
      DB_USER: qaup
      DB_PASSWORD: qaup123
      # Flyway配置自动化数据库迁移
      SPRING_FLYWAY_ENABLED: true
      SPRING_FLYWAY_BASELINE_ON_MIGRATE: true
      SPRING_FLYWAY_VALIDATE_ON_MIGRATE: true
      SPRING_FLYWAY_CLEAN_DISABLED: true
    volumes:
      - ./app.jar:/app/app.jar
      - ./config.yml:/app/config.yml
      - ./logs:/app/logs
      - ./backup:/app/backup
    ports:
      - "8080:8080"
    depends_on:
      qaup-postgres:
        condition: service_healthy
      qaup-redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 120s
    command: [
      "sh", "-c", 
      "echo 'Waiting for database to be ready...' && 
       sleep 10 && 
       echo 'Starting QAUP application with Flyway migration...' && 
       java -jar /app/app.jar --spring.config.location=/app/config.yml"
    ]

networks:
  default:
    name: qaup-network

4. 外部配置文件config.yml

# 服务器配置
server:
  port: 8080

# 应用配置
qaup:
  # 文件上传路径
  profile: /tmp/uploads
  # 外部接口配置(客户可修改)
  external:
    api-host: 192.168.1.100
    api-port: 8090
    
# 日志配置
logging:
  level:
    com.qaup: INFO
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
  file:
    name: /app/logs/qaup.log
    
# 注意数据库和Redis配置通过环境变量设置

5. 自动化数据库迁移Flyway

5.1 迁移脚本位置

qaup-admin/src/main/resources/db/migration/
├── V1.0.0__Initial_baseline.sql    # 数据库基线结构86KB
├── V1.0.1__Initial_data.sql        # 初始数据50KB
└── README.md                       # 迁移脚本编写规范

5.2 自动迁移机制

  • 应用启动时自动执行无需手动运行SQL脚本
  • 版本控制:所有迁移按版本顺序执行
  • 幂等性:安全重复执行,不会重复创建对象
  • 健康检查:依赖数据库健康状态启动应用

5.3 迁移状态查询

# 查看应用日志中的迁移信息
docker compose logs qaup-app | grep -i flyway

# 直接查询数据库
docker exec -it qaup-postgres psql -U qaup -d qaup -c "SELECT * FROM flyway_schema_history ORDER BY installed_rank;"

6. 一键部署deploy-all.sh

#!/bin/bash
echo "=== QAUP 一键部署 ==="

# 检查Docker
if ! command -v docker &> /dev/null; then
    echo "❌ Docker 未安装"
    exit 1
fi

# 载入镜像
echo "载入Docker镜像..."
docker load -i images.tar.gz

# 创建数据目录
echo "创建数据目录..."
mkdir -p data/postgres data/redis logs

# 启动服务
echo "启动服务..."
docker compose up -d

# 等待服务启动
echo "等待服务启动60秒..."
sleep 60

# 检查服务状态
if curl -f -s http://localhost:8080/actuator/health > /dev/null 2>&1; then
    echo "✅ 部署成功!"
    echo ""
    echo "访问地址: http://localhost:8080"
    echo "数据库: localhost:5432 (qaup/qaup123)"
    echo "Redis: localhost:6379"
    echo ""
    echo "管理命令:"
    echo "  查看状态: docker compose ps"
    echo "  查看日志: docker compose logs -f qaup-app"
    echo "  停止服务: docker compose down"
    echo "  升级应用: ./deploy-update.sh"
else
    echo "❌ 服务启动失败,请检查日志:"
    docker compose logs
fi

7. 客户部署1条命令

tar -xzf qaup-deploy.tar.gz && cd qaup-deploy && ./deploy-all.sh

8. 一键升级deploy-update.sh

#!/bin/bash
echo "=== QAUP 一键升级 ==="

# 检查新版本文件
if [ ! -f "new-app.jar" ]; then
    echo "❌ 请先将新版本文件重命名为 new-app.jar"
    exit 1
fi

# 验证Java版本兼容性重要确保jar与容器Java版本匹配
echo "验证Java版本兼容性..."
if command -v java &> /dev/null; then
    LOCAL_JAVA_VERSION=$(java -version 2>&1 | head -1 | cut -d'"' -f2 | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
    echo "本地Java版本: $LOCAL_JAVA_VERSION"
    echo "容器Java版本: eclipse-temurin:21-jre"
fi

# 备份当前版本
echo "备份当前版本..."
cp app.jar app.jar.backup.$(date +%Y%m%d_%H%M%S)

# 数据库备份(重要)
echo "备份数据库..."
docker exec qaup-postgres pg_dump -U qaup qaup > backup/qaup-backup-$(date +%Y%m%d_%H%M%S).sql

# 停止应用(不影响数据库)
echo "停止应用服务..."
docker compose stop qaup-app

# 替换应用
cp new-app.jar app.jar
echo "已更新应用文件"

# 启动应用Flyway自动处理数据库迁移
echo "启动应用服务..."
docker compose start qaup-app

# 等待启动和迁移完成
echo "等待应用启动和数据库迁移120秒..."
sleep 120

# 检查升级结果
if curl -f -s http://localhost:8080/actuator/health > /dev/null 2>&1; then
    echo "✅ 升级成功!"
    echo ""
    echo "Flyway迁移状态:"
    docker exec -it qaup-postgres psql -U qaup -d qaup -c "SELECT version, description, installed_rank FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 5;"
else
    echo "❌ 升级失败,开始回滚..."
    # 恢复jar文件
    LATEST_BACKUP=$(ls -t app.jar.backup.* 2>/dev/null | head -1)
    if [ -n "$LATEST_BACKUP" ]; then
        cp "$LATEST_BACKUP" app.jar
        docker compose restart qaup-app
        echo "✅ 已回滚到版本: $LATEST_BACKUP"
    else
        echo "❌ 未找到备份文件,请手动处理"
    fi
fi

9. Java版本兼容性注意事项

9.1 编译与运行环境匹配

  • 编译环境: 确保项目在Java 21环境下编译
  • 运行环境: Docker镜像使用 eclipse-temurin:21-jre

9.2 常见版本错误

如果遇到 UnsupportedClassVersionError,确认以下配置:

# docker-compose.yml 中必须使用Java 21镜像
services:
  qaup-app:
    # 正确示例
    image: m.daocloud.io/docker.io/library/eclipse-temurin:21-jre

9.3 版本验证命令

# 检查容器中Java版本
docker exec qaup-app java -version

# 检查jar文件编译版本
javap -cp app.jar -version

# 快速健康检查
curl http://localhost:8080/actuator/health

10. 系统维护操作

10.1 日常运维命令

# 查看服务状态
docker compose ps

# 查看应用日志
docker compose logs -f qaup-app

# 查看数据库日志
docker compose logs qaup-postgres

# 查看Redis日志
docker compose logs qaup-redis

# 查看系统资源使用
docker stats

# 数据库连接测试
docker exec -it qaup-postgres psql -U qaup -d qaup -c "SELECT version();"

# Redis连接测试
docker exec -it qaup-redis redis-cli ping

10.2 监控数据库迁移状态

# 查看Flyway迁移历史
docker exec -it qaup-postgres psql -U qaup -d qaup -c "SELECT * FROM flyway_schema_history ORDER BY installed_rank;"

# 查看应用日志中的迁移信息
docker compose logs qaup-app | grep -i flyway

# 查看最近的迁移记录
docker exec -it qaup-postgres psql -U qaup -d qaup -c "SELECT version, description, installed_on FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 3;"

10.3 数据备份和恢复

# 手动备份数据库
docker exec qaup-postgres pg_dump -U qaup qaup > backup/manual-backup-$(date +%Y%m%d_%H%M%S).sql

# 恢复数据库(需要停止应用)
docker compose stop qaup-app
docker exec -i qaup-postgres psql -U qaup qaup < backup/qaup-backup-20250120_143000.sql
docker compose start qaup-app

10.4 完全重置(开发测试用)

# 停止所有服务
docker compose down

# 删除数据目录(⚠️ 注意:这会删除所有数据)
rm -rf data/

# 重新部署
./deploy-all.sh

11. 操作总结

开发环境(一次性)

# 在macOS上构建
mvn clean package -DskipTests
./deploy/package-all.sh

# 或在服务器上打包
./deploy/package-all.sh

客户环境

# 首次部署
tar -xzf qaup-deploy.tar.gz && cd qaup-deploy && ./deploy-all.sh

# 程序更新
# 1. 复制新jar文件并重命名为 new-app.jar
# 2. 执行更新
./deploy-update.sh

# 查看状态
docker compose ps

# 查看日志
docker compose logs -f qaup-app

12. 现代化优势总结

极简部署:解压 → 运行脚本2步完成
极简升级替换jar → 运行脚本,自动完成
离线友好:所有依赖预打包,无需联网
配置灵活:关键配置外部文件,可随时修改
自动化迁移Flyway自动处理数据库版本管理
健康检查:服务依赖和健康状态监控
PostGIS支持:内置地理空间数据库能力
一键回滚:升级失败可快速回滚到上一版本
零停机升级:只重启应用服务,数据库保持运行
版本兼容Java 21运行时确保版本一致性