From 6b9b74c9e477308a7812da89fa92842dac39cfb3 Mon Sep 17 00:00:00 2001 From: huazhongmin Date: Sun, 21 Dec 2025 18:07:31 +0800 Subject: [PATCH] =?UTF-8?q?=E9=83=A8=E7=BD=B2=E8=84=9A=E6=9C=AC=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend-single/deploy-server.sh | 24 +++- backend-single/deploy.sh | 2 +- course-web/deploy.sh | 191 +++++++++++++++++++------------- 3 files changed, 135 insertions(+), 82 deletions(-) diff --git a/backend-single/deploy-server.sh b/backend-single/deploy-server.sh index 428295f..cd2f92a 100755 --- a/backend-single/deploy-server.sh +++ b/backend-single/deploy-server.sh @@ -47,6 +47,7 @@ check_jar() { # 停止旧服务 stop_service() { + # 1. 尝试通过 PID 文件停止 if [ -f "$PID_FILE" ]; then PID=$(cat "$PID_FILE") if ps -p "$PID" > /dev/null 2>&1; then @@ -71,8 +72,27 @@ stop_service() { log_warn "PID 文件存在但进程不存在,清理 PID 文件" fi rm -f "$PID_FILE" - else - log_info "没有找到 PID 文件,服务可能未运行" + fi + + # 2. 双重检查:通过进程名查找并停止(防止 PID 文件丢失的情况) + PIDS=$(ps aux | grep "$JAR_NAME" | grep -v grep | awk '{print $2}') + if [ -n "$PIDS" ]; then + log_warn "检测到残留进程 (PIDs: $PIDS),正在清理..." + for PID in $PIDS; do + log_info "停止残留进程 $PID" + kill "$PID" 2>/dev/null || true + done + + sleep 5 + + # 再次检查并强制停止 + PIDS=$(ps aux | grep "$JAR_NAME" | grep -v grep | awk '{print $2}') + if [ -n "$PIDS" ]; then + for PID in $PIDS; do + log_warn "强制停止残留进程 $PID" + kill -9 "$PID" 2>/dev/null || true + done + fi fi } diff --git a/backend-single/deploy.sh b/backend-single/deploy.sh index 270904c..f2079d4 100755 --- a/backend-single/deploy.sh +++ b/backend-single/deploy.sh @@ -275,7 +275,7 @@ show_remote_info() { # 检查远程服务状态 log_info "检查远程服务状态..." - ssh $REMOTE_USER@$REMOTE_HOST "ps aux | grep $JAR_NAME | grep -v grep" || log_info "远程服务未运行" + ssh $REMOTE_USER@$REMOTE_HOST "ps aux | grep $REMOTE_JAR_NAME | grep -v grep" || log_info "远程服务未运行" } # 本地部署 - 主函数 diff --git a/course-web/deploy.sh b/course-web/deploy.sh index 24ba62d..a103507 100755 --- a/course-web/deploy.sh +++ b/course-web/deploy.sh @@ -1,100 +1,133 @@ #!/bin/bash -# 部署脚本 - 将构建好的 course-web 前端项目上传到服务器 -# 支持版本管理和回滚 -# 使用方法: ./deploy.sh [deploy|rollback] +# course-web 部署脚本 +# 功能:项目构建、文件传输、原子切换、历史版本管理、回滚支持 SERVER_IP="101.200.208.45" USERNAME="root" -REMOTE_ROOT="/data/www" -APP_NAME="course-of-life" -DEPLOY_ROOT="${REMOTE_ROOT}/${APP_NAME}-releases" -SYMLINK_PATH="${REMOTE_ROOT}/${APP_NAME}" +APP_NAME="course-web" +DEPLOY_BASE="/data/www/course-web-deploy" +RELEASES_DIR="${DEPLOY_BASE}/releases" +LINK_PATH="/data/www/course-of-life" +MAX_RELEASES=5 -TIMESTAMP=$(date +%Y%m%d%H%M%S) -RELEASE_PATH="${DEPLOY_ROOT}/${TIMESTAMP}" - -function deploy() { - echo "🚀 开始部署 ${APP_NAME} 到服务器..." - - # 1. 环境检查 - if ! command -v npm &> /dev/null; then - echo "❌ 错误: 未找到npm命令" - exit 1 - fi - - # 2. 项目构建 - echo "🧹 清理旧构建..." - rm -rf dist - - echo "📦 开始构建..." - if ! npm run build; then - echo "❌ 构建失败" - exit 1 - fi - - if [ ! -d "dist" ]; then - echo "❌ 错误: dist目录不存在" - exit 1 - fi - - # 3. 准备远程目录 - echo "📁 准备远程目录: ${RELEASE_PATH}" - ssh "${USERNAME}@${SERVER_IP}" "mkdir -p ${RELEASE_PATH}" || { - echo "❌ 无法创建远程目录" - exit 1 - } - - # 4. 上传文件 - echo "📤 上传文件..." - if scp -r dist/* "${USERNAME}@${SERVER_IP}:${RELEASE_PATH}/"; then - echo "✅ 文件上传成功" - else - echo "❌ 文件上传失败" - # 清理失败的发布目录 - ssh "${USERNAME}@${SERVER_IP}" "rm -rf ${RELEASE_PATH}" - exit 1 - fi - - # 5. 切换版本 (原子操作) - echo "🔄 切换当前版本..." - # ln -sfn: force update symlink - ssh "${USERNAME}@${SERVER_IP}" "ln -sfn ${RELEASE_PATH} ${SYMLINK_PATH}" || { - echo "❌ 版本切换失败" - exit 1 - } - - # 6. 权限修正 - ssh "${USERNAME}@${SERVER_IP}" "chmod -R 755 ${RELEASE_PATH}" - - # 7. 清理旧版本 (保留最近5个) - echo "🧹 清理旧版本..." - ssh "${USERNAME}@${SERVER_IP}" "cd ${DEPLOY_ROOT} && ls -t | tail -n +6 | xargs -I {} rm -rf {}" - - echo "✅ 部署完成!" - echo "🌍 访问地址: http://${SERVER_IP}/${APP_NAME}/" +# 打印带颜色的信息 +function log_info() { + echo -e "\033[32m[INFO] $1\033[0m" } +function log_error() { + echo -e "\033[31m[ERROR] $1\033[0m" +} + +# 检查环境 +function check_env() { + log_info "检查本地环境..." + if ! command -v npm &> /dev/null; then + log_error "未找到npm命令,请先安装Node.js" + exit 1 + fi + if ! command -v scp &> /dev/null; then + log_error "未找到scp命令" + exit 1 + fi +} + +# 构建项目 +function build_project() { + log_info "开始构建项目..." + # 清理旧构建 + rm -rf dist + + # 安装依赖并构建 + # npm install # 视情况开启,为了速度暂时注释,假设依赖已安装 + if npm run build; then + log_info "项目构建成功" + else + log_error "项目构建失败" + exit 1 + fi + + if [ ! -d "dist" ]; then + log_error "dist目录不存在" + exit 1 + fi +} + +# 部署到服务器 +function deploy() { + TIMESTAMP=$(date +%Y%m%d%H%M%S) + RELEASE_PATH="${RELEASES_DIR}/${TIMESTAMP}" + + log_info "准备部署版本: ${TIMESTAMP}" + + # 1. 创建远程目录结构 + ssh "${USERNAME}@${SERVER_IP}" "mkdir -p ${RELEASE_PATH}" + + # 2. 上传文件 + log_info "上传文件到服务器..." + if scp -r dist/* "${USERNAME}@${SERVER_IP}:${RELEASE_PATH}/"; then + log_info "文件上传成功" + else + log_error "文件上传失败" + exit 1 + fi + + # 3. 设置权限 + ssh "${USERNAME}@${SERVER_IP}" "chmod -R 755 ${RELEASE_PATH}" + + # 4. 原子切换软链接 + log_info "切换服务版本..." + # 检查目标路径是否为普通目录(非软链接),如果是则备份并移除,防止ln失败 + ssh "${USERNAME}@${SERVER_IP}" " + if [ -d '${LINK_PATH}' ] && [ ! -L '${LINK_PATH}' ]; then + echo '检测到目标路径为普通目录,进行备份...' + mv '${LINK_PATH}' '${LINK_PATH}_backup_$(date +%s)' + fi + ln -snf '${RELEASE_PATH}' '${LINK_PATH}' + " + + log_info "部署完成!当前版本指向: ${RELEASE_PATH}" + + # 5. 清理旧版本 + clean_old_releases +} + +# 清理旧版本,只保留最近的N个 +function clean_old_releases() { + log_info "清理旧版本(保留最近${MAX_RELEASES}个)..." + ssh "${USERNAME}@${SERVER_IP}" " + cd ${RELEASES_DIR} && ls -t | tail -n +$((${MAX_RELEASES} + 1)) | xargs -I {} rm -rf {} + " +} + +# 回滚到上一个版本 function rollback() { - echo "Reverting to previous version..." - # 获取倒数第二个版本目录 - PREV_VERSION=$(ssh "${USERNAME}@${SERVER_IP}" "cd ${DEPLOY_ROOT} && ls -t | head -n 2 | tail -n 1") + log_info "开始回滚操作..." + # 获取当前指向的版本 + CURRENT_LINK=$(ssh "${USERNAME}@${SERVER_IP}" "readlink ${LINK_PATH}") + log_info "当前版本: ${CURRENT_LINK}" + + # 获取上一个版本目录 + PREV_VERSION=$(ssh "${USERNAME}@${SERVER_IP}" "ls -dt ${RELEASES_DIR}/* | grep -v '${CURRENT_LINK}' | head -n 1") if [ -z "$PREV_VERSION" ]; then - echo "❌ 没有可回滚的版本" + log_error "没有找到可回滚的历史版本" exit 1 fi - - echo "🔄 回滚到版本: ${PREV_VERSION}" - ssh "${USERNAME}@${SERVER_IP}" "ln -sfn ${DEPLOY_ROOT}/${PREV_VERSION} ${SYMLINK_PATH}" && \ - echo "✅ 回滚成功" || echo "❌ 回滚失败" + + log_info "回滚目标版本: ${PREV_VERSION}" + ssh "${USERNAME}@${SERVER_IP}" "ln -snf ${PREV_VERSION} ${LINK_PATH}" + log_info "回滚成功!" } -# 主逻辑 +# 主流程 case "$1" in - rollback) + "rollback") rollback ;; *) + check_env + build_project deploy ;; esac