From 50c63f1b1ad5dbd0b0d8cd108055f4610a1f8408 Mon Sep 17 00:00:00 2001 From: huazhongmin Date: Mon, 21 Jul 2025 13:00:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8DJava=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=85=BC=E5=AE=B9=E6=80=A7=E5=B9=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E9=94=AE=E9=83=A8=E7=BD=B2=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐛 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 # 健康检查 --- .env | 4 +- backend/deploy-all.sh | 18 +- backend/deploy-remote.sh | 6 +- backend/deploy-test.sh | 594 ++++++++++++++++++++++++++++ backend/emotion-ai/deploy.sh | 9 +- backend/emotion-auth/deploy.sh | 9 +- backend/emotion-explore/deploy.sh | 9 +- backend/emotion-gateway/deploy.sh | 9 +- backend/emotion-growth/deploy.sh | 9 +- backend/emotion-record/deploy.sh | 9 +- backend/emotion-reward/deploy.sh | 9 +- backend/emotion-stats/deploy.sh | 9 +- backend/emotion-user/deploy.sh | 9 +- backend/emotion-websocket/deploy.sh | 9 +- one-click-deploy.sh | 289 ++++++++++++++ 15 files changed, 964 insertions(+), 37 deletions(-) create mode 100755 backend/deploy-test.sh create mode 100755 one-click-deploy.sh diff --git a/.env b/.env index 59090e0..0287730 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ # 数据库配置 -MYSQL_ROOT_PASSWORD=123456 +MYSQL_ROOT_PASSWORD=EmotionMuseum2025*# MYSQL_DATABASE=emotion_museum -MYSQL_USER=emotion-museum +MYSQL_USER=root MYSQL_PASSWORD=EmotionMuseum2025# # Redis配置 diff --git a/backend/deploy-all.sh b/backend/deploy-all.sh index c8e9f11..bd4a0bc 100755 --- a/backend/deploy-all.sh +++ b/backend/deploy-all.sh @@ -61,6 +61,17 @@ SERVICES=( "emotion-stats:19009" ) +# 如果设置了TEST_SINGLE_SERVICE环境变量,只部署指定服务 +if [ -n "$TEST_SINGLE_SERVICE" ]; then + case $TEST_SINGLE_SERVICE in + "gateway") SERVICES=("emotion-gateway:19000") ;; + "user") SERVICES=("emotion-user:19001") ;; + "ai") SERVICES=("emotion-ai:19002") ;; + *) echo "未知的测试服务: $TEST_SINGLE_SERVICE"; exit 1 ;; + esac + echo "测试模式: 仅部署 $TEST_SINGLE_SERVICE 服务" +fi + # 部署状态跟踪 declare -A DEPLOYMENT_STATUS declare -A DEPLOYMENT_ERRORS @@ -316,13 +327,14 @@ create_dockerfile() { log_info "创建Dockerfile: $service_name" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${service_name} << 'EOF' -FROM openjdk:17-jre-slim +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine # 设置工作目录 WORKDIR /app -# 安装必要的工具 -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl # 复制jar包 (使用相对路径) COPY ${service_name}-1.0.0.jar app.jar diff --git a/backend/deploy-remote.sh b/backend/deploy-remote.sh index f404fbf..b86c7ac 100755 --- a/backend/deploy-remote.sh +++ b/backend/deploy-remote.sh @@ -280,11 +280,13 @@ create_dockerfile() { log_info "创建Dockerfile: $service_name" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${service_name} << 'EOF' -FROM openjdk:17-jre-slim +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${service_name}-1.0.0.jar app.jar diff --git a/backend/deploy-test.sh b/backend/deploy-test.sh new file mode 100755 index 0000000..c8e9f11 --- /dev/null +++ b/backend/deploy-test.sh @@ -0,0 +1,594 @@ +#!/bin/bash + +# 情感博物馆 - 全服务容器化部署脚本 +# 作者: emotion-museum +# 日期: 2025-07-18 +# 支持Jenkins CI/CD部署 + +# 不要在遇到错误时立即退出,让所有模块都尝试部署 +set +e + +# 配置变量 - 支持Jenkins环境变量覆盖 +REMOTE_HOST="${DEPLOY_HOST:-'root@47.111.10.27'}" +REMOTE_BUILD_DIR="${REMOTE_BUILD_DIR:-/data/builds}" +REMOTE_DOCKER_COMPOSE_DIR="${REMOTE_DOCKER_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:-}" + +# 部署模式配置 +DEPLOY_MODE="${DEPLOY_MODE:-full}" # full: 完整部署, build: 仅构建, deploy: 仅部署 + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 +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 +} + +# 创建远程目录 +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 "远程目录创建完成" +} + +# 构建所有服务 (Jenkins阶段) +build_all_services() { + log_info "开始在Jenkins服务器上构建所有微服务..." + + # 检查是否在Jenkins环境中 + if [ -n "$JENKINS_HOME" ] || [ -n "$BUILD_NUMBER" ]; then + log_info "检测到Jenkins环境,执行完整构建流程" + else + log_info "本地环境,执行构建流程" + fi + + # 先构建父项目 + log_info "构建父项目..." + if mvn clean install -DskipTests -q; then + log_success "父项目构建成功" + else + log_error "父项目构建失败" + exit 1 + fi + + # 构建各个微服务 + for service_info in "${SERVICES[@]}"; do + service_name=$(echo $service_info | cut -d':' -f1) + log_info "构建服务: $service_name" + + cd $service_name + if mvn clean package -DskipTests -P${PROFILE} -q; then + # 检查jar包是否生成 + if [ -f "target/${service_name}-1.0.0.jar" ]; then + local jar_size=$(du -h "target/${service_name}-1.0.0.jar" | cut -f1) + log_success "服务 $service_name 构建成功 (大小: $jar_size)" + else + log_error "服务 $service_name jar包未生成" + cd .. + exit 1 + fi + else + log_error "服务 $service_name 构建失败" + cd .. + exit 1 + fi + cd .. + done + + log_success "所有服务在Jenkins服务器构建完成" +} + +# 部署所有服务到远程服务器 +deploy_all_services_to_remote() { + 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 $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 +} + +# 传输jar包到远程服务器 +transfer_jar_to_remote() { + local service_name=$1 + + log_info "传输jar包到远程服务器: $service_name" + + # 检查本地jar包是否存在 + local jar_file="${service_name}/target/${service_name}-1.0.0.jar" + if [ ! -f "$jar_file" ]; then + log_error "本地JAR包不存在: $jar_file" + return 1 + fi + + # 显示jar包信息 + local jar_size=$(du -h "$jar_file" | cut -f1) + log_info "准备传输jar包: $jar_file (大小: $jar_size)" + + # 删除远程旧jar包 + log_info "清理远程旧jar包: $service_name" + ssh 'root@47.111.10.27' "rm -f $REMOTE_BUILD_DIR/${service_name}-*.jar" + + # 上传新jar包 + log_info "上传jar包到远程服务器..." + if scp "$jar_file" 'root@47.111.10.27':$REMOTE_BUILD_DIR/${service_name}-1.0.0.jar; then + log_success "jar包传输成功: $service_name" + + # 验证远程jar包 + local remote_size=$(ssh 'root@47.111.10.27' "du -h $REMOTE_BUILD_DIR/${service_name}-1.0.0.jar | cut -f1") + log_info "远程jar包大小: $remote_size" + return 0 + else + log_error "jar包传输失败: $service_name" + return 1 + fi +} + +# 部署单个服务 (远程服务器阶段) +deploy_service() { + local service_name=$1 + local service_port=$2 + local start_time=$(date +%s) + + log_info "开始部署服务到远程服务器: $service_name" + DEPLOYMENT_STATUS[$service_name]="DEPLOYING" + + # 先传输jar包 + if ! transfer_jar_to_remote $service_name; then + local error_msg="jar包传输失败" + DEPLOYMENT_STATUS[$service_name]="FAILED" + DEPLOYMENT_ERRORS[$service_name]="$error_msg" + return 1 + fi + + # 验证远程jar包存在 + log_info "验证远程jar包: $service_name" + 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 启动失败" + log_error "错误日志:" + 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' +FROM openjdk:17-jre-slim + +# 设置工作目录 +WORKDIR /app + +# 安装必要的工具 +RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* + +# 复制jar包 (使用相对路径) +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" +} + +# 创建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网络创建完成" +} + +# 健康检查 +health_check() { + log_info "执行服务健康检查..." + + for service_info in "${SERVICES[@]}"; do + service_name=$(echo $service_info | cut -d':' -f1) + service_port=$(echo $service_info | cut -d':' -f2) + + log_info "检查服务健康状态: $service_name" + + # 等待服务完全启动 + sleep 5 + + if ssh 'root@47.111.10.27' "curl -f -s http://localhost:${service_port}/actuator/health" > /dev/null 2>&1; then + log_success "服务 $service_name 健康检查通过" + else + log_warning "服务 $service_name 健康检查失败,可能仍在启动中" + fi + done +} + +# 显示详细部署报告 +show_deployment_report() { + local total_time=$1 + + echo "" + echo "========================================" + echo " 部署完成报告" + echo "========================================" + echo "项目名称: $PROJECT_NAME" + echo "部署环境: $PROFILE" + echo "目标服务器: $REMOTE_HOST" + echo "部署时间: $(date '+%Y-%m-%d %H:%M:%S')" + echo "总耗时: ${total_time}s" + if [ "$BUILD_NUMBER" != "manual" ]; then + echo "Jenkins构建: #$BUILD_NUMBER" + echo "Jenkins任务: $JOB_NAME" + [ -n "$BUILD_URL" ] && echo "构建链接: $BUILD_URL" + fi + echo "========================================" + + echo "" + echo "📊 部署统计:" + echo " 总服务数: $TOTAL_SERVICES" + echo " 成功部署: $SUCCESSFUL_DEPLOYMENTS" + echo " 失败部署: $FAILED_DEPLOYMENTS" + echo " 成功率: $(( SUCCESSFUL_DEPLOYMENTS * 100 / TOTAL_SERVICES ))%" + echo "" + + echo "📋 服务部署详情:" + printf "%-20s %-10s %-10s %s\n" "服务名称" "状态" "耗时" "备注" + echo "----------------------------------------" + + for service_info in "${SERVICES[@]}"; do + service_name=$(echo $service_info | cut -d':' -f1) + service_port=$(echo $service_info | cut -d':' -f2) + status=${DEPLOYMENT_STATUS[$service_name]:-"UNKNOWN"} + time=${DEPLOYMENT_TIMES[$service_name]:-"N/A"} + + case $status in + "SUCCESS") + printf "%-20s ${GREEN}%-10s${NC} %-10s %s\n" "$service_name" "✅ 成功" "$time" "http://47.111.10.27:$service_port" + ;; + "FAILED") + printf "%-20s ${RED}%-10s${NC} %-10s %s\n" "$service_name" "❌ 失败" "$time" "查看错误日志" + ;; + *) + printf "%-20s ${YELLOW}%-10s${NC} %-10s %s\n" "$service_name" "⚠️ 未知" "$time" "状态异常" + ;; + esac + done + + echo "" + + # 显示失败服务的错误信息 + if [ $FAILED_DEPLOYMENTS -gt 0 ]; then + echo "❌ 失败服务错误详情:" + echo "----------------------------------------" + for service_info in "${SERVICES[@]}"; do + service_name=$(echo $service_info | cut -d':' -f1) + if [ "${DEPLOYMENT_STATUS[$service_name]}" = "FAILED" ]; then + echo "🔸 $service_name:" + echo " ${DEPLOYMENT_ERRORS[$service_name]}" | head -3 + echo "" + fi + done + fi + + # 显示当前运行的容器状态 + echo "🐳 当前容器运行状态:" + echo "----------------------------------------" + ssh 'root@47.111.10.27' "docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' | grep emotion || echo '没有运行的emotion相关容器'" + + echo "" + echo "========================================" + + # 根据部署结果设置退出码 + if [ $FAILED_DEPLOYMENTS -eq 0 ]; then + echo "🎉 所有服务部署成功!" + return 0 + else + echo "⚠️ 部分服务部署失败,请检查错误日志" + return 1 + fi +} + +# 主函数 +main() { + local start_time=$(date +%s) + + log_info "🚀 开始全服务容器化部署..." + log_info "目标服务器: $REMOTE_HOST" + log_info "部署环境: $PROFILE" + log_info "部署模式: $DEPLOY_MODE" + log_info "服务总数: $TOTAL_SERVICES" + + # 根据部署模式执行不同的流程 + case $DEPLOY_MODE in + "build") + log_info "🔨 执行构建模式 - 仅在Jenkins服务器构建jar包" + execute_build_only + ;; + "deploy") + log_info "🚀 执行部署模式 - 仅部署到远程服务器" + execute_deploy_only + ;; + "full"|*) + log_info "🔄 执行完整模式 - 构建+部署" + execute_full_deployment + ;; + esac +} + +# 仅构建模式 +execute_build_only() { + local start_time=$(date +%s) + + log_info "开始构建所有服务..." + + # 构建服务 + if ! build_all_services; then + log_error "服务构建失败" + exit 1 + fi + + # 显示构建结果 + log_info "📦 构建产物信息:" + 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_success "✅ $service_name: $jar_size" + else + log_error "❌ $service_name: jar包未生成" + fi + done + + local end_time=$(date +%s) + local total_time=$((end_time - start_time)) + log_success "🎉 构建完成!总耗时: ${total_time}s" +} + +# 仅部署模式 +execute_deploy_only() { + local start_time=$(date +%s) + + log_info "开始部署到远程服务器..." + + # 检查连接 + if ! check_remote_connection; then + log_error "远程服务器连接失败,部署终止" + exit 1 + fi + + # 创建目录和网络 + create_remote_directories + create_docker_network + + # 部署所有服务 + deploy_all_services_to_remote + + # 健康检查和报告 + health_check + local end_time=$(date +%s) + local total_time=$((end_time - start_time)) + show_deployment_report $total_time +} + +# 完整部署模式 +execute_full_deployment() { + local start_time=$(date +%s) + + # 检查连接 + if ! check_remote_connection; then + log_error "远程服务器连接失败,部署终止" + exit 1 + fi + + # 创建目录 + create_remote_directories + + # 创建Docker网络 + create_docker_network + + # 构建服务 + if ! build_all_services; then + log_error "服务构建失败,部署终止" + exit 1 + fi + + # 部署所有服务 + deploy_all_services_to_remote + + # 健康检查 + log_info "执行服务健康检查..." + health_check + + # 计算总耗时 + local end_time=$(date +%s) + local total_time=$((end_time - start_time)) + + # 显示详细报告 + show_deployment_report $total_time + + # 根据部署结果设置退出码 + if [ $FAILED_DEPLOYMENTS -eq 0 ]; then + log_success "🎉 全服务容器化部署完成!" + exit 0 + else + log_warning "⚠️ 部分服务部署失败,请查看详细报告" + exit 1 + fi +} + +# 执行主函数 +main "$@" diff --git a/backend/emotion-ai/deploy.sh b/backend/emotion-ai/deploy.sh index 4646715..edc64aa 100755 --- a/backend/emotion-ai/deploy.sh +++ b/backend/emotion-ai/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-ai # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-auth/deploy.sh b/backend/emotion-auth/deploy.sh index 61b0667..c6e6bf9 100755 --- a/backend/emotion-auth/deploy.sh +++ b/backend/emotion-auth/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-auth # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-explore/deploy.sh b/backend/emotion-explore/deploy.sh index 2b96202..b9d640f 100755 --- a/backend/emotion-explore/deploy.sh +++ b/backend/emotion-explore/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-explore # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-gateway/deploy.sh b/backend/emotion-gateway/deploy.sh index 2463116..4b6f044 100755 --- a/backend/emotion-gateway/deploy.sh +++ b/backend/emotion-gateway/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-gateway # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-growth/deploy.sh b/backend/emotion-growth/deploy.sh index d6a7f46..668054d 100755 --- a/backend/emotion-growth/deploy.sh +++ b/backend/emotion-growth/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-growth # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-record/deploy.sh b/backend/emotion-record/deploy.sh index af4bc0a..99788fa 100755 --- a/backend/emotion-record/deploy.sh +++ b/backend/emotion-record/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-record # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-reward/deploy.sh b/backend/emotion-reward/deploy.sh index 9a91418..a263c9f 100755 --- a/backend/emotion-reward/deploy.sh +++ b/backend/emotion-reward/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-reward # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-stats/deploy.sh b/backend/emotion-stats/deploy.sh index 3df2637..14e7c44 100755 --- a/backend/emotion-stats/deploy.sh +++ b/backend/emotion-stats/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-stats # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-user/deploy.sh b/backend/emotion-user/deploy.sh index 2561138..c875c0c 100755 --- a/backend/emotion-user/deploy.sh +++ b/backend/emotion-user/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-user # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/backend/emotion-websocket/deploy.sh b/backend/emotion-websocket/deploy.sh index 0ddd09d..1b8749f 100755 --- a/backend/emotion-websocket/deploy.sh +++ b/backend/emotion-websocket/deploy.sh @@ -57,7 +57,7 @@ build_service() { # 构建父项目依赖 cd .. mvn clean install -DskipTests -q - cd $SERVICE_NAME + cd emotion-websocket # 构建当前服务 if mvn clean package -DskipTests -Ptest -q; then @@ -73,11 +73,14 @@ create_dockerfile() { log_info "创建Dockerfile: $SERVICE_NAME" ssh 'root@47.111.10.27' "cat > $REMOTE_DOCKER_COMPOSE_DIR/Dockerfile.${SERVICE_NAME} << 'EOF' -FROM openjdk:17-jre-slim +# 使用阿里云镜像源的OpenJDK +# 使用Java 17 Alpine镜像 +FROM openjdk:17-alpine WORKDIR /app -RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* +# 安装必要的工具 (Alpine Linux使用apk) +RUN apk add --no-cache curl COPY ${SERVICE_NAME}-1.0.0.jar app.jar diff --git a/one-click-deploy.sh b/one-click-deploy.sh new file mode 100755 index 0000000..8c5b66a --- /dev/null +++ b/one-click-deploy.sh @@ -0,0 +1,289 @@ +#!/bin/bash + +# 情感博物馆一键部署脚本 +# 作者: emotion-museum +# 日期: 2025-07-21 +# 用途: 本地构建并部署前后端到远程服务器 + +set -e + +# 配置变量 +REMOTE_HOST="root@47.111.10.27" +DEPLOY_ENV="${DEPLOY_ENV:-test}" +PROJECT_NAME="emotion-museum" + +# 颜色输出 +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" +} + +# 检查环境 +check_environment() { + log_info "检查本地环境..." + + # 检查Node.js + if ! command -v node &> /dev/null; then + log_error "Node.js未安装,请先安装Node.js" + exit 1 + fi + log_info "Node.js版本: $(node --version)" + + # 检查npm + if ! command -v npm &> /dev/null; then + log_error "npm未安装,请先安装npm" + exit 1 + fi + log_info "npm版本: $(npm --version)" + + # 检查Java + if ! command -v java &> /dev/null; then + log_error "Java未安装,请先安装Java 17" + exit 1 + fi + log_info "Java版本: $(java --version | head -1)" + + # 检查Maven + if ! command -v mvn &> /dev/null; then + log_error "Maven未安装,请先安装Maven" + exit 1 + fi + log_info "Maven版本: $(mvn --version | head -1)" + + # 检查SSH连接 + log_info "检查远程服务器连接..." + if ssh -o ConnectTimeout=10 "$REMOTE_HOST" "echo 'SSH连接成功'" > /dev/null 2>&1; then + log_success "远程服务器连接正常" + else + log_error "无法连接到远程服务器: $REMOTE_HOST" + log_error "请检查SSH密钥配置或网络连接" + exit 1 + fi + + log_success "环境检查通过" +} + +# 构建前端 +build_frontend() { + log_info "开始构建前端..." + + cd web-flowith + + # 安装依赖 + log_info "安装前端依赖..." + npm install + + # 构建前端 + log_info "构建前端项目..." + npm run build + + # 检查构建结果 + if [ ! -d "dist" ]; then + log_error "前端构建失败,dist目录不存在" + exit 1 + fi + + log_success "前端构建完成" + cd .. +} + +# 构建后端 +build_backend() { + log_info "开始构建后端..." + + cd backend + + # 使用我们优化的构建脚本 + log_info "使用优化的构建脚本..." + ./build-all.sh + + log_success "后端构建完成" + cd .. +} + +# 部署前端 +deploy_frontend() { + log_info "开始部署前端..." + + cd web-flowith + ./deploy.sh + cd .. + + log_success "前端部署完成" +} + +# 部署后端 +deploy_backend() { + log_info "开始部署后端..." + + cd backend + + # 使用远程部署脚本 + log_info "使用优化的远程部署脚本..." + ./deploy-remote.sh + + log_success "后端部署完成" + cd .. +} + +# 健康检查 +health_check() { + log_info "执行健康检查..." + + # 等待服务启动 + log_info "等待服务启动..." + sleep 30 + + # 检查关键服务 + local services=( + "19000:emotion-gateway" + "19001:emotion-user" + "19002:emotion-ai" + "19008:emotion-auth" + ) + + local success_count=0 + local total_count=${#services[@]} + + for service in "${services[@]}"; do + port=$(echo $service | cut -d':' -f1) + name=$(echo $service | cut -d':' -f2) + + log_info "检查服务: $name (端口:$port)" + if curl -f -s "http://$REMOTE_HOST:$port/actuator/health" > /dev/null 2>&1; then + log_success "✅ $name 服务健康" + success_count=$((success_count + 1)) + else + log_warning "❌ $name 服务健康检查失败" + fi + done + + log_info "健康检查结果: $success_count/$total_count 服务正常" + + if [ $success_count -eq $total_count ]; then + log_success "所有关键服务健康检查通过" + else + log_warning "部分服务健康检查失败,请检查日志" + fi +} + +# 显示部署结果 +show_result() { + local end_time=$(date +%s) + local total_time=$((end_time - start_time)) + + echo "" + echo "========================================" + echo " 部署完成报告" + echo "========================================" + echo "项目名称: $PROJECT_NAME" + echo "部署环境: $DEPLOY_ENV" + echo "目标服务器: $REMOTE_HOST" + echo "部署时间: $(date '+%Y-%m-%d %H:%M:%S')" + echo "总耗时: ${total_time}s" + echo "========================================" + echo "" + echo "🌐 访问地址:" + echo " 前端应用: http://$REMOTE_HOST/emotion-museum" + echo " API网关: http://$REMOTE_HOST:19000" + echo " 用户服务: http://$REMOTE_HOST:19001" + echo " AI服务: http://$REMOTE_HOST:19002" + echo " 认证服务: http://$REMOTE_HOST:19008" + echo "" + echo "🔧 管理命令:" + echo " 查看容器: ssh $REMOTE_HOST 'docker ps'" + echo " 查看日志: ssh $REMOTE_HOST 'docker logs '" + echo " 重启服务: ssh $REMOTE_HOST 'docker restart '" + echo "" + echo "📋 健康检查:" + echo " curl http://$REMOTE_HOST:19000/actuator/health" + echo "" + echo "========================================" + echo "🎉 一键部署完成!" +} + +# 主函数 +main() { + local start_time=$(date +%s) + + echo "🚀 开始情感博物馆一键部署..." + echo "目标服务器: $REMOTE_HOST" + echo "部署环境: $DEPLOY_ENV" + echo "" + + # 检查环境 + check_environment + + # 构建前端 + build_frontend + + # 构建后端 + build_backend + + # 部署前端 + deploy_frontend + + # 部署后端 + deploy_backend + + # 健康检查 + health_check + + # 显示结果 + show_result +} + +# 处理命令行参数 +case "${1:-}" in + "frontend") + log_info "仅部署前端" + check_environment + build_frontend + deploy_frontend + ;; + "backend") + log_info "仅部署后端" + check_environment + build_backend + deploy_backend + ;; + "check") + log_info "仅执行健康检查" + health_check + ;; + "help"|"-h"|"--help") + echo "情感博物馆一键部署脚本" + echo "" + echo "用法:" + echo " ./one-click-deploy.sh # 完整部署前后端" + echo " ./one-click-deploy.sh frontend # 仅部署前端" + echo " ./one-click-deploy.sh backend # 仅部署后端" + echo " ./one-click-deploy.sh check # 仅健康检查" + echo " ./one-click-deploy.sh help # 显示帮助" + echo "" + echo "环境变量:" + echo " DEPLOY_ENV=test|prod # 部署环境(默认:test)" + echo "" + ;; + *) + main + ;; +esac