50c63f1b1a
🐛 Java版本修复: - 修复Docker镜像使用Java 17 Alpine版本 - 解决Java 8与Spring Boot 17编译版本不兼容问题 - 修复Alpine Linux包管理器命令(apk替代apt-get) 🚀 一键部署脚本: - 新增one-click-deploy.sh一键部署脚本 - 支持完整部署、仅前端、仅后端、健康检查模式 - 集成环境检查、构建、部署、健康检查全流程 - 提供详细的部署报告和访问地址 ✅ 部署优化: - 使用openjdk:17-alpine镜像确保Java版本兼容 - 优化Docker构建流程和错误处理 - 完善健康检查和状态监控 🔧 使用方法: - ./one-click-deploy.sh # 完整部署 - ./one-click-deploy.sh frontend # 仅部署前端 - ./one-click-deploy.sh backend # 仅部署后端 - ./one-click-deploy.sh check # 健康检查
368 lines
11 KiB
Bash
Executable File
368 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# 情感博物馆 - 远程部署脚本
|
|
# 作者: emotion-museum
|
|
# 日期: 2025-07-18
|
|
# 用途: 将构建好的jar包部署到远程服务器
|
|
|
|
set -e
|
|
|
|
# 配置变量
|
|
REMOTE_HOST="'root@47.111.10.27'"
|
|
REMOTE_BUILD_DIR="/data/builds"
|
|
REMOTE_DOCKER_COMPOSE_DIR="/data/docker"
|
|
PROFILE="${DEPLOY_ENV:-test}"
|
|
PROJECT_NAME="${PROJECT_NAME:-emotion-museum}"
|
|
|
|
# Jenkins构建信息
|
|
BUILD_NUMBER="${BUILD_NUMBER:-manual}"
|
|
JOB_NAME="${JOB_NAME:-local-deploy}"
|
|
BUILD_URL="${BUILD_URL:-}"
|
|
|
|
# 颜色输出
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
# 日志函数
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
}
|
|
|
|
log_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
}
|
|
|
|
# 服务列表
|
|
SERVICES=(
|
|
"emotion-gateway:19000"
|
|
"emotion-user:19001"
|
|
"emotion-ai:19002"
|
|
"emotion-record:19003"
|
|
"emotion-growth:19004"
|
|
"emotion-explore:19005"
|
|
"emotion-reward:19006"
|
|
"emotion-websocket:19007"
|
|
"emotion-auth:19008"
|
|
"emotion-stats:19009"
|
|
)
|
|
|
|
# 部署状态跟踪
|
|
declare -A DEPLOYMENT_STATUS
|
|
declare -A DEPLOYMENT_ERRORS
|
|
declare -A DEPLOYMENT_TIMES
|
|
TOTAL_SERVICES=${#SERVICES[@]}
|
|
SUCCESSFUL_DEPLOYMENTS=0
|
|
FAILED_DEPLOYMENTS=0
|
|
|
|
# 检查远程服务器连接
|
|
check_remote_connection() {
|
|
log_info "检查远程服务器连接..."
|
|
if ssh -o ConnectTimeout=10 'root@47.111.10.27' "echo 'Connection successful'" > /dev/null 2>&1; then
|
|
log_success "远程服务器连接正常"
|
|
else
|
|
log_error "无法连接到远程服务器 'root@47.111.10.27'"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# 检查本地jar包
|
|
check_local_jars() {
|
|
log_info "检查本地jar包..."
|
|
|
|
local missing_jars=0
|
|
for service_info in "${SERVICES[@]}"; do
|
|
service_name=$(echo $service_info | cut -d':' -f1)
|
|
jar_file="${service_name}/target/${service_name}-1.0.0.jar"
|
|
|
|
if [ -f "$jar_file" ]; then
|
|
jar_size=$(du -h "$jar_file" | cut -f1)
|
|
log_info "✅ $service_name: $jar_size"
|
|
else
|
|
log_error "❌ $service_name: jar包不存在"
|
|
missing_jars=$((missing_jars + 1))
|
|
fi
|
|
done
|
|
|
|
if [ $missing_jars -gt 0 ]; then
|
|
log_error "发现 $missing_jars 个缺失的jar包,请先执行构建"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "所有jar包检查通过"
|
|
}
|
|
|
|
# 传输所有jar包到远程服务器
|
|
transfer_all_jars() {
|
|
log_info "开始传输所有jar包到远程服务器..."
|
|
|
|
# 创建远程目录
|
|
ssh 'root@47.111.10.27' "mkdir -p $REMOTE_BUILD_DIR"
|
|
|
|
local transfer_success=0
|
|
local transfer_failed=0
|
|
|
|
for service_info in "${SERVICES[@]}"; do
|
|
service_name=$(echo $service_info | cut -d':' -f1)
|
|
jar_file="${service_name}/target/${service_name}-1.0.0.jar"
|
|
|
|
if [ ! -f "$jar_file" ]; then
|
|
log_warning "跳过不存在的jar包: $service_name"
|
|
continue
|
|
fi
|
|
|
|
log_info "传输jar包: $service_name"
|
|
|
|
# 删除远程旧jar包
|
|
ssh 'root@47.111.10.27' "rm -f $REMOTE_BUILD_DIR/${service_name}-*.jar"
|
|
|
|
# 上传新jar包
|
|
if scp "$jar_file" 'root@47.111.10.27':$REMOTE_BUILD_DIR/${service_name}-1.0.0.jar; then
|
|
# 验证远程jar包
|
|
remote_size=$(ssh 'root@47.111.10.27' "du -h $REMOTE_BUILD_DIR/${service_name}-1.0.0.jar | cut -f1")
|
|
log_success "✅ $service_name 传输成功 (远程大小: $remote_size)"
|
|
transfer_success=$((transfer_success + 1))
|
|
else
|
|
log_error "❌ $service_name 传输失败"
|
|
transfer_failed=$((transfer_failed + 1))
|
|
fi
|
|
done
|
|
|
|
log_info "传输统计: 成功 $transfer_success, 失败 $transfer_failed"
|
|
|
|
if [ $transfer_failed -eq 0 ]; then
|
|
log_success "所有jar包传输成功"
|
|
return 0
|
|
else
|
|
log_error "部分jar包传输失败"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# 创建远程目录
|
|
create_remote_directories() {
|
|
log_info "创建远程目录结构..."
|
|
ssh 'root@47.111.10.27' "
|
|
mkdir -p $REMOTE_BUILD_DIR
|
|
mkdir -p $REMOTE_DOCKER_COMPOSE_DIR
|
|
mkdir -p /data/logs/emotion-museum
|
|
mkdir -p /data/config/emotion-museum
|
|
"
|
|
log_success "远程目录创建完成"
|
|
}
|
|
|
|
# 创建Docker网络
|
|
create_docker_network() {
|
|
log_info "创建Docker网络..."
|
|
ssh 'root@47.111.10.27' "
|
|
docker network create emotion-network 2>/dev/null || true
|
|
"
|
|
log_success "Docker网络创建完成"
|
|
}
|
|
|
|
# 部署单个服务到远程
|
|
deploy_service_to_remote() {
|
|
local service_name=$1
|
|
local service_port=$2
|
|
local start_time=$(date +%s)
|
|
|
|
log_info "部署服务到远程: $service_name"
|
|
DEPLOYMENT_STATUS[$service_name]="DEPLOYING"
|
|
|
|
# 验证远程jar包存在
|
|
if ! ssh 'root@47.111.10.27' "test -f $REMOTE_BUILD_DIR/${service_name}-1.0.0.jar"; then
|
|
local error_msg="远程jar包不存在"
|
|
log_error "$error_msg"
|
|
DEPLOYMENT_STATUS[$service_name]="FAILED"
|
|
DEPLOYMENT_ERRORS[$service_name]="$error_msg"
|
|
return 1
|
|
fi
|
|
|
|
# 创建Dockerfile
|
|
create_dockerfile $service_name $service_port
|
|
|
|
# 停止并删除旧容器
|
|
log_info "停止旧容器: $service_name"
|
|
ssh 'root@47.111.10.27' "
|
|
docker stop ${service_name} 2>/dev/null || true
|
|
docker rm ${service_name} 2>/dev/null || true
|
|
docker rmi ${PROJECT_NAME}/${service_name}:latest 2>/dev/null || true
|
|
"
|
|
|
|
# 构建Docker镜像
|
|
log_info "构建Docker镜像: $service_name"
|
|
ssh 'root@47.111.10.27' "
|
|
# 复制jar包到Docker构建目录
|
|
cp $REMOTE_BUILD_DIR/${service_name}-1.0.0.jar $REMOTE_DOCKER_COMPOSE_DIR/
|
|
|
|
# 构建镜像
|
|
cd $REMOTE_DOCKER_COMPOSE_DIR
|
|
docker build -t ${PROJECT_NAME}/${service_name}:latest -f Dockerfile.${service_name} .
|
|
|
|
# 清理临时文件
|
|
rm -f ${service_name}-1.0.0.jar
|
|
"
|
|
|
|
# 启动新容器
|
|
log_info "启动新容器: $service_name"
|
|
ssh 'root@47.111.10.27' "
|
|
docker run -d \\
|
|
--name ${service_name} \\
|
|
--network emotion-network \\
|
|
-p ${service_port}:${service_port} \\
|
|
-v /data/logs/emotion-museum:/app/logs \\
|
|
-e SPRING_PROFILES_ACTIVE=${PROFILE} \\
|
|
-e MYSQL_HOST=47.111.10.27 \\
|
|
-e MYSQL_PORT=3306 \\
|
|
-e MYSQL_DATABASE=emotion_museum \\
|
|
-e MYSQL_USERNAME=root \\
|
|
-e MYSQL_PASSWORD='EmotionMuseum2025*#' \\
|
|
-e REDIS_HOST=47.111.10.27 \\
|
|
-e REDIS_PORT=6379 \\
|
|
-e REDIS_PASSWORD= \\
|
|
-e REDIS_DATABASE=0 \\
|
|
-e NACOS_SERVER_ADDR=47.111.10.27:8848 \\
|
|
-e NACOS_USERNAME=nacos \\
|
|
-e NACOS_PASSWORD='Peanut2817*#' \\
|
|
--restart unless-stopped \\
|
|
${PROJECT_NAME}/${service_name}:latest
|
|
"
|
|
|
|
# 等待服务启动
|
|
log_info "等待服务启动: $service_name"
|
|
sleep 10
|
|
|
|
# 检查容器状态
|
|
if ssh 'root@47.111.10.27' "docker ps | grep ${service_name}" > /dev/null 2>&1; then
|
|
log_success "服务 $service_name 启动成功"
|
|
|
|
# 显示容器日志
|
|
log_info "显示服务日志 最后10行: $service_name"
|
|
ssh 'root@47.111.10.27' "docker logs --tail 10 ${service_name}" 2>/dev/null || true
|
|
|
|
# 记录成功状态
|
|
local end_time=$(date +%s)
|
|
local duration=$((end_time - start_time))
|
|
DEPLOYMENT_STATUS[$service_name]="SUCCESS"
|
|
DEPLOYMENT_TIMES[$service_name]="${duration}s"
|
|
return 0
|
|
else
|
|
local error_msg="服务启动失败"
|
|
log_error "服务 $service_name 启动失败"
|
|
local error_logs=$(ssh 'root@47.111.10.27' "docker logs ${service_name}" 2>&1 || echo "无法获取日志")
|
|
echo "$error_logs"
|
|
|
|
# 记录失败状态
|
|
local end_time=$(date +%s)
|
|
local duration=$((end_time - start_time))
|
|
DEPLOYMENT_STATUS[$service_name]="FAILED"
|
|
DEPLOYMENT_ERRORS[$service_name]="$error_msg: $error_logs"
|
|
DEPLOYMENT_TIMES[$service_name]="${duration}s"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# 创建Dockerfile
|
|
create_dockerfile() {
|
|
local service_name=$1
|
|
local service_port=$2
|
|
|
|
log_info "创建Dockerfile: $service_name"
|
|
|
|
ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${service_name} << 'EOF'
|
|
# 使用Java 17 Alpine镜像
|
|
FROM openjdk:17-alpine
|
|
|
|
WORKDIR /app
|
|
|
|
# 安装必要的工具 (Alpine Linux使用apk)
|
|
RUN apk add --no-cache curl
|
|
|
|
COPY ${service_name}-1.0.0.jar app.jar
|
|
|
|
RUN mkdir -p /app/logs
|
|
|
|
ENV TZ=Asia/Shanghai
|
|
RUN ln -snf /usr/share/zoneinfo/\$TZ /etc/localtime && echo \$TZ > /etc/timezone
|
|
|
|
EXPOSE ${service_port}
|
|
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \\
|
|
CMD curl -f http://localhost:${service_port}/actuator/health || exit 1
|
|
|
|
ENTRYPOINT [\"java\", \"-Djava.security.egd=file:/dev/./urandom\", \"-Xms512m\", \"-Xmx1024m\", \"-jar\", \"app.jar\"]
|
|
EOF"
|
|
}
|
|
|
|
# 主函数
|
|
main() {
|
|
local start_time=$(date +%s)
|
|
|
|
log_info "🚀 开始远程部署任务..."
|
|
log_info "目标服务器: $REMOTE_HOST"
|
|
log_info "部署环境: $PROFILE"
|
|
log_info "服务总数: $TOTAL_SERVICES"
|
|
|
|
# 检查远程连接
|
|
check_remote_connection
|
|
|
|
# 检查本地jar包
|
|
check_local_jars
|
|
|
|
# 创建远程目录和网络
|
|
create_remote_directories
|
|
create_docker_network
|
|
|
|
# 传输所有jar包
|
|
if ! transfer_all_jars; then
|
|
log_error "jar包传输失败,部署终止"
|
|
exit 1
|
|
fi
|
|
|
|
# 部署所有服务
|
|
log_info "开始逐个部署服务..."
|
|
for service_info in "${SERVICES[@]}"; do
|
|
service_name=$(echo $service_info | cut -d':' -f1)
|
|
service_port=$(echo $service_info | cut -d':' -f2)
|
|
|
|
echo ""
|
|
log_info "[$((SUCCESSFUL_DEPLOYMENTS + FAILED_DEPLOYMENTS + 1))/$TOTAL_SERVICES] 部署服务: $service_name"
|
|
|
|
if deploy_service_to_remote $service_name $service_port; then
|
|
SUCCESSFUL_DEPLOYMENTS=$((SUCCESSFUL_DEPLOYMENTS + 1))
|
|
log_success "✅ 服务 $service_name 部署成功"
|
|
else
|
|
FAILED_DEPLOYMENTS=$((FAILED_DEPLOYMENTS + 1))
|
|
log_error "❌ 服务 $service_name 部署失败,继续部署其他服务..."
|
|
fi
|
|
done
|
|
|
|
# 计算总耗时
|
|
local end_time=$(date +%s)
|
|
local total_time=$((end_time - start_time))
|
|
|
|
log_info "部署统计: 成功 $SUCCESSFUL_DEPLOYMENTS, 失败 $FAILED_DEPLOYMENTS"
|
|
|
|
# 根据部署结果设置退出码
|
|
if [ $FAILED_DEPLOYMENTS -eq 0 ]; then
|
|
log_success "🎉 远程部署任务完成!总耗时: ${total_time}s"
|
|
exit 0
|
|
else
|
|
log_warning "⚠️ 部分服务部署失败,总耗时: ${total_time}s"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# 执行主函数
|
|
main "$@"
|