#!/bin/bash # QAUP 一键升级脚本 set -e # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' NC='\033[0m' print_message() { echo -e "${1}${2}${NC}" } print_message $BLUE "=== QAUP 一键升级 ===" # 检查必要文件 REQUIRED_FILES=("app.jar" "docker-compose.yml" "config.yml") for file in "${REQUIRED_FILES[@]}"; do if [ ! -f "$file" ]; then print_message $RED "❌ 缺失必要文件: $file" print_message $BLUE "请确保在正确的部署目录中运行此脚本" exit 1 fi done # 1. 环境检查和准备 print_message $BLUE "1. 环境检查..." # 检查Docker服务状态 if ! docker compose ps > /dev/null 2>&1; then print_message $RED "❌ 无法连接到Docker服务" print_message $BLUE "请确保Docker服务正在运行: sudo systemctl status docker" exit 1 fi # 检查应用服务状态 APP_STATUS=$(docker compose ps qaup-app --format json 2>/dev/null | jq -r '.[0].State' 2>/dev/null || echo "exited") if [ "$APP_STATUS" != "running" ]; then print_message $YELLOW "⚠️ 应用服务当前状态: $APP_STATUS" print_message $BLUE "正在启动应用服务..." docker compose up -d qaup-app sleep 30 fi # 获取当前应用版本信息 print_message $BLUE "2. 检查应用版本..." if [ -f "new-app.jar" ]; then NEW_JAR_SIZE=$(stat -f%z new-app.jar 2>/dev/null || stat -c%s new-app.jar 2>/dev/null || echo "unknown") CURRENT_JAR_SIZE=$(stat -f%z app.jar 2>/dev/null || stat -c%s app.jar 2>/dev/null || echo "unknown") print_message $BLUE " 当前版本大小: $CURRENT_JAR_SIZE bytes" print_message $BLUE " 新版本大小: $NEW_JAR_SIZE bytes" if [ "$NEW_JAR_SIZE" = "$CURRENT_JAR_SIZE" ]; then print_message $YELLOW "⚠️ 新旧版本大小相同,请确认版本是否正确" read -p "是否继续升级?(y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then print_message $BLUE "升级已取消" exit 0 fi fi else print_message $RED "❌ 未找到新版本文件: new-app.jar" print_message $BLUE "请先将新版本文件重命名为 new-app.jar" print_message $BLUE " 例如: cp qaup-admin-1.0.2.jar new-app.jar" exit 1 fi # 3. 数据库备份 print_message $BLUE "3. 备份数据库..." BACKUP_DIR="backup" mkdir -p "$BACKUP_DIR" BACKUP_TIMESTAMP=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="$BACKUP_DIR/qaup_db_backup_$BACKUP_TIMESTAMP.sql" if docker exec qaup-postgres pg_dump -U qaup qaup > "$BACKUP_FILE" 2>/dev/null; then BACKUP_SIZE=$(stat -f%z "$BACKUP_FILE" 2>/dev/null || stat -c%s "$BACKUP_FILE" 2>/dev/null || echo "unknown") print_message $GREEN "✓ 数据库备份成功: $BACKUP_FILE ($BACKUP_SIZE bytes)" else print_message $RED "❌ 数据库备份失败" print_message $BLUE "升级已取消,请检查数据库连接" exit 1 fi # 4. 备份当前应用 print_message $BLUE "4. 备份当前应用..." BACKUP_JAR="$BACKUP_DIR/app.jar.backup.$BACKUP_TIMESTAMP" cp app.jar "$BACKUP_JAR" print_message $GREEN "✓ 应用备份成功: $BACKUP_JAR" # 5. 获取升级前数据库迁移状态 print_message $BLUE "5. 记录升级前迁移状态..." BEFORE_MIGRATION=$(docker exec qaup-postgres psql -U qaup -d qaup -t -c "SELECT version,description FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 5;" 2>/dev/null || echo "无法获取迁移状态") print_message $BLUE "升级前迁移状态已记录" # 6. 停止应用服务 print_message $BLUE "6. 停止应用服务..." docker compose stop qaup-app sleep 10 print_message $GREEN "✓ 应用服务已停止" # 7. 替换应用文件 print_message $BLUE "7. 更新应用文件..." if cp new-app.jar app.jar; then print_message $GREEN "✓ 应用文件更新成功" else print_message $RED "❌ 应用文件更新失败" print_message $BLUE "正在恢复备份..." cp "$BACKUP_JAR" app.jar docker compose start qaup-app exit 1 fi # 8. 启动应用服务 print_message $BLUE "8. 启动应用服务..." docker compose up -d qaup-app sleep 15 # 9. 监控应用启动和数据库迁移 print_message $BLUE "9. 监控应用启动和数据库迁移..." print_message $BLUE " 这可能需要2-3分钟,请耐心等待..." WAIT_TIME=0 HEALTH_URL="http://localhost:8080/actuator/health" while [ $WAIT_TIME -lt 180 ]; do sleep 10 WAIT_TIME=$((WAIT_TIME + 10)) # 检查应用健康状态 if curl -f -s "$HEALTH_URL" > /dev/null 2>&1; then print_message $GREEN "✓ 应用启动成功!" break fi # 显示等待进度 if [ $((WAIT_TIME % 30)) -eq 0 ]; then print_message $BLUE " 已等待 ${WAIT_TIME} 秒..." # 检查应用日志中的迁移信息 MIGRATION_LOGS=$(docker compose logs qaup-app --tail=10 2>/dev/null | grep -E "(Flyway|migration|Migration)" | tail -2) if [ -n "$MIGRATION_LOGS" ]; then print_message $BLUE " 迁移进度:" echo "$MIGRATION_LOGS" | while read line; do print_message $BLUE " $line" done fi # 检查是否有错误 ERROR_LOGS=$(docker compose logs qaup-app --tail=5 2>/dev/null | grep -i -E "(error|exception|fail)" || true) if [ -n "$ERROR_LOGS" ]; then print_message $YELLOW " 检测到可能的错误:" echo "$ERROR_LOGS" | while read line; do print_message $YELLOW " $line" done fi fi done # 10. 验证升级结果 print_message $BLUE "10. 验证升级结果..." if curl -f -s "$HEALTH_URL" > /dev/null 2>&1; then # 获取升级后数据库迁移状态 print_message $BLUE " 检查数据库迁移状态..." AFTER_MIGRATION=$(docker exec qaup-postgres psql -U qaup -d qaup -t -c "SELECT version,description FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 3;" 2>/dev/null || echo "无法获取迁移状态") print_message $GREEN "🎉 升级成功完成!" echo "" print_message $GREEN "📊 升级信息:" print_message $BLUE " 应用状态: 运行中" print_message $BLUE " 健康检查: 通过" echo "" print_message $BLUE "💾 备份信息:" print_message $BLUE " 应用备份: $BACKUP_JAR" print_message $BLUE " 数据库备份: $BACKUP_FILE" echo "" print_message $BLUE "📋 升级前迁移状态:" echo "$BEFORE_MIGRATION" | while read line; do print_message $BLUE " $line" done echo "" print_message $BLUE "📋 升级后迁移状态:" echo "$AFTER_MIGRATION" | while read line; do print_message $BLUE " $line" done echo "" print_message $BLUE "🔍 验证命令:" print_message $BLUE " 查看应用日志: docker compose logs -f qaup-app" print_message $BLUE " 检查数据库连接: docker exec qaup-postgres psql -U qaup -d qaup -c 'SELECT version();'" print_message $BLUE " 回滚命令: ./rollback.sh $BACKUP_TIMESTAMP" # 创建回滚脚本 cat > rollback_$BACKUP_TIMESTAMP.sh << EOF #!/bin/bash echo "正在回滚到版本 $BACKUP_TIMESTAMP..." docker compose stop qaup-app cp backup/app.jar.backup.$BACKUP_TIMESTAMP app.jar docker compose start qaup-app echo "回滚完成,请检查应用状态" EOF chmod +x rollback_$BACKUP_TIMESTAMP.sh print_message $BLUE " 自动回滚脚本: rollback_$BACKUP_TIMESTAMP.sh" else print_message $RED "❌ 升级失败" print_message $BLUE "正在执行自动回滚..." # 自动回滚 docker compose stop qaup-app cp "$BACKUP_JAR" app.jar docker compose start qaup-app sleep 30 # 验证回滚 if curl -f -s "$HEALTH_URL" > /dev/null 2>&1; then print_message $GREEN "✓ 自动回滚成功" print_message $BLUE " 应用已恢复到升级前版本" print_message $BLUE " 请检查应用日志: docker compose logs qaup-app" else print_message $RED "❌ 回滚失败" print_message $BLUE " 请手动检查并恢复服务" fi echo "" print_message $BLUE "📋 详细信息:" print_message $BLUE " 应用备份: $BACKUP_JAR" print_message $BLUE " 数据库备份: $BACKUP_FILE" print_message $BLUE " 升级前状态: $APP_STATUS" exit 1 fi