Files
smartClean/docs/自动化部署方案-无Docker版.md
xqzp2026 8373460096 feat: 添加自动化部署方案(Docker + 远程服务器两套方案)
- 新增 deploy/docker/:Docker 本机模拟部署,含 Dockerfile、docker-compose、deploy.sh 一键脚本
- 新增 deploy/remote/:远程服务器部署,含 SSH 自动上传、重启、回滚脚本
- 新增 deploy/README.md:完整使用手册,含现状分析、落地调整工作清单、命令速查
- 新增 build.sh/start.sh:本地构建和启动脚本(含飞书通知)
- 新增前端 .env.docker 环境配置,API 指向测试服务器
- 前端 package.json 新增 build-docker 命令
- 更新 .gitignore:排除 IDE 配置、SQL 数据、Docker 敏感文件
- 前端 UI 样式优化(多个页面组件)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 18:41:15 +09:30

23 KiB
Raw Blame History

SmartClean 自动化打包部署方案(无 Docker 版)

一、目标

基于现有 build.sh 构建能力,实现 一键构建 → 远程备份 → 上传部署 → 服务重启 → 健康检查 → 失败回滚 → 飞书通知 全流程自动化。不依赖 Docker直接操作远程服务器。

二、前提条件

条件 说明
SSH 免密登录 本机 → 182 服务器配好 SSH Key免输密码
服务器目录约定 统一部署路径,脚本按约定操作
现有构建脚本 复用已有的 build.sh

SSH 免密配置(一次性)

# 生成密钥(如已有可跳过)
ssh-keygen -t ed25519

# 将公钥复制到服务器
ssh-copy-id root@192.168.1.182

# 验证
ssh root@192.168.1.182 "echo ok"

三、整体架构

本机 (Mac)                                   远程服务器 (192.168.1.182)
┌──────────────────────┐                    ┌──────────────────────────────┐
│                      │                    │                              │
│  源码 → build.sh 构建 │                    │  /opt/smartclean/            │
│                      │   SCP 上传          │  ├── web/                    │
│  产物:               │ ──────────────→    │  │   └── ROOT.war            │
│  - ROOT.war          │                    │  ├── task/                   │
│  - task.jar          │   SSH 远程执行      │  │   └── task.jar            │
│  - dist/             │ ──────────────→    │  ├── front/                  │
│                      │                    │  │   └── dist/               │
│  deploy.sh 控制全流程  │                    │  ├── backups/                │
│                      │                    │  │   ├── 20260415-153000/    │
│                      │                    │  │   └── 20260415-140000/    │
│                      │                    │  └── scripts/                │
│                      │                    │      ├── restart-web.sh      │
│                      │                    │      ├── restart-task.sh     │
│                      │                    │      └── restart-front.sh    │
└──────────────────────┘                    └──────────────────────────────┘

四、服务器目录规划

/opt/smartclean/                    # 部署根目录
├── web/
│   ├── tomcat/                     # Tomcat 安装目录
│   │   └── webapps/
│   │       └── ROOT.war            # Web 服务 WAR 包
│   └── logs/
├── task/
│   ├── task.jar                    # Task 服务 JAR 包
│   ├── task.pid                    # 进程 PID 文件
│   └── logs/
├── front/
│   └── dist/                       # 前端静态文件Nginx 指向此目录)
├── backups/                        # 版本备份(自动保留最近 5 个)
│   ├── 20260415-153000/
│   │   ├── ROOT.war
│   │   ├── task.jar
│   │   └── dist/
│   └── 20260415-140000/
│       └── ...
└── scripts/                        # 服务器端管理脚本
    ├── restart-web.sh
    ├── restart-task.sh
    └── restart-front.sh

五、新增文件结构

smartclean/
├── build.sh                          # 已有,构建脚本
└── deploy/
    ├── deploy.sh                     # 一键部署主脚本(本机执行)
    ├── rollback.sh                   # 一键回滚脚本(本机执行)
    ├── config.sh                     # 部署配置(服务器地址、路径等)
    ├── .env                          # 敏感信息(密码等,不入 git
    └── remote/                       # 服务器端脚本(首次部署时自动上传)
        ├── setup.sh                  # 服务器初始化(创建目录结构,一次性)
        ├── restart-web.sh            # 重启 Web 服务Tomcat
        ├── restart-task.sh           # 重启 Task 服务JAR
        └── restart-front.sh          # 重新加载前端Nginx reload

六、配置文件

6.1 部署配置

# deploy/config.sh

# ===== 服务器配置 =====
DEPLOY_HOST="192.168.1.182"
DEPLOY_USER="root"
DEPLOY_BASE="/opt/smartclean"

# ===== 服务器目录 =====
REMOTE_WEB_DIR="$DEPLOY_BASE/web"
REMOTE_TASK_DIR="$DEPLOY_BASE/task"
REMOTE_FRONT_DIR="$DEPLOY_BASE/front"
REMOTE_BACKUP_DIR="$DEPLOY_BASE/backups"
REMOTE_SCRIPTS_DIR="$DEPLOY_BASE/scripts"

# ===== Tomcat 配置 =====
TOMCAT_HOME="/opt/smartclean/web/tomcat"
TOMCAT_WEBAPPS="$TOMCAT_HOME/webapps"

# ===== Nginx 配置 =====
NGINX_HTML="/opt/smartclean/front/dist"

# ===== Task 服务配置 =====
TASK_JAR_NAME="xiaoqu-intellectual-task-0.0.1-SNAPSHOT.jar"
TASK_PROFILE="prod"
TASK_JVM_OPTS="-Xms256m -Xmx512m"

# ===== 本地构建产物路径 =====
LOCAL_WAR="backend/xiaoqu-intellectual-web/target/ROOT.war"
LOCAL_TASK_JAR="backend/xiaoqu-intellectual-task/target/$TASK_JAR_NAME"
LOCAL_FRONT_DIST="frontend/witcleansystem/dist"

# ===== 备份保留数量 =====
MAX_BACKUPS=5

# ===== 健康检查 =====
HEALTHCHECK_URL="http://$DEPLOY_HOST:8095/dropDown/districtTree"
HEALTHCHECK_RETRIES=20
HEALTHCHECK_INTERVAL=5

# ===== 飞书通知 =====
FEISHU_WEBHOOK="https://open.feishu.cn/open-apis/bot/v2/hook/5703e8cc-6998-46a6-af9d-8c5102cc8c1e"

七、服务器端脚本

7.1 服务器初始化脚本(一次性执行)

# deploy/remote/setup.sh
#!/bin/bash
# 在服务器上创建标准目录结构,仅需执行一次

DEPLOY_BASE="/opt/smartclean"

mkdir -p "$DEPLOY_BASE"/{web/logs,task/logs,front,backups,scripts}

echo "目录结构创建完成:"
find "$DEPLOY_BASE" -maxdepth 2 -type d

7.2 重启 Web 服务

# deploy/remote/restart-web.sh
#!/bin/bash
# 重启 Tomcat部署 ROOT.war

TOMCAT_HOME="/opt/smartclean/web/tomcat"

echo "[INFO] 停止 Tomcat..."
"$TOMCAT_HOME/bin/shutdown.sh" 2>/dev/null
sleep 3

# 确保进程已停
TOMCAT_PID=$(ps -ef | grep "catalina" | grep -v grep | awk '{print $2}')
if [ -n "$TOMCAT_PID" ]; then
    echo "[WARN] Tomcat 未正常关闭,强制终止 PID=$TOMCAT_PID"
    kill -9 $TOMCAT_PID
    sleep 1
fi

# 清理旧的解压目录,保留 WAR
rm -rf "$TOMCAT_HOME/webapps/ROOT"
rm -rf "$TOMCAT_HOME/work/Catalina"

echo "[INFO] 启动 Tomcat..."
"$TOMCAT_HOME/bin/startup.sh"

echo "[INFO] Tomcat 已启动"

7.3 重启 Task 服务

# deploy/remote/restart-task.sh
#!/bin/bash
# 重启 Task 服务Spring Boot JAR

TASK_DIR="/opt/smartclean/task"
JAR_FILE="$TASK_DIR/task.jar"
PID_FILE="$TASK_DIR/task.pid"
LOG_FILE="$TASK_DIR/logs/task.log"
PROFILE="${1:-prod}"
JVM_OPTS="${2:--Xms256m -Xmx512m}"

# 停止旧进程
if [ -f "$PID_FILE" ]; then
    OLD_PID=$(cat "$PID_FILE")
    if kill -0 "$OLD_PID" 2>/dev/null; then
        echo "[INFO] 停止旧进程 PID=$OLD_PID"
        kill "$OLD_PID"
        sleep 3
        # 强制终止
        if kill -0 "$OLD_PID" 2>/dev/null; then
            kill -9 "$OLD_PID"
        fi
    fi
    rm -f "$PID_FILE"
fi

# 启动新进程
echo "[INFO] 启动 Task 服务 (profile=$PROFILE)..."
nohup java $JVM_OPTS \
    -jar "$JAR_FILE" \
    --spring.profiles.active=$PROFILE \
    > "$LOG_FILE" 2>&1 &

echo $! > "$PID_FILE"
echo "[INFO] Task 服务已启动, PID=$(cat "$PID_FILE")"

7.4 重新加载前端

# deploy/remote/restart-front.sh
#!/bin/bash
# 重新加载 Nginx前端静态文件已更新

echo "[INFO] 测试 Nginx 配置..."
nginx -t 2>&1
if [ $? -ne 0 ]; then
    echo "[ERROR] Nginx 配置有误"
    exit 1
fi

echo "[INFO] 重新加载 Nginx..."
nginx -s reload

echo "[INFO] Nginx 已重新加载"

八、一键部署主脚本

# deploy/deploy.sh
#!/bin/bash
#
# SmartClean 一键部署脚本(无 Docker 版)
#
# 用法:
#   ./deploy.sh              # 构建并部署所有服务
#   ./deploy.sh web          # 仅构建部署 Web 服务
#   ./deploy.sh task         # 仅构建部署 Task 服务
#   ./deploy.sh front        # 仅构建部署前端
#   ./deploy.sh front-test   # 构建测试环境前端并部署
#   ./deploy.sh backend      # 构建部署后端web + task
#   ./deploy.sh rollback     # 回滚到上一版本
#   ./deploy.sh setup        # 首次初始化服务器目录

set -e

DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$(dirname "$DEPLOY_DIR")"
source "$DEPLOY_DIR/config.sh"

# ===== 版本号 =====
GIT_HASH=$(cd "$ROOT_DIR" && git rev-parse --short HEAD)
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
VERSION="${TIMESTAMP}-${GIT_HASH}"
BRANCH=$(cd "$ROOT_DIR" && git rev-parse --abbrev-ref HEAD)
COMMIT=$(cd "$ROOT_DIR" && git log -1 --format='%h %s')

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

log_info()  { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

SSH_CMD="ssh $DEPLOY_USER@$DEPLOY_HOST"
SCP_CMD="scp"

# ===== 飞书通知 =====
notify_feishu() {
    local title="$1" content="$2" color="$3"
    curl -s -X POST "$FEISHU_WEBHOOK" \
      -H "Content-Type: application/json" \
      -d "{
        \"msg_type\": \"interactive\",
        \"card\": {
          \"header\": {\"title\":{\"tag\":\"plain_text\",\"content\":\"$title\"},\"template\":\"$color\"},
          \"elements\": [{\"tag\":\"markdown\",\"content\":\"$content\"}]
        }
      }" > /dev/null 2>&1
}

# ===== 检查 SSH 连接 =====
check_ssh() {
    log_info "检查 SSH 连接..."
    if ! $SSH_CMD "echo ok" > /dev/null 2>&1; then
        log_error "无法连接到 $DEPLOY_USER@$DEPLOY_HOST"
        log_error "请先配置 SSH 免密登录: ssh-copy-id $DEPLOY_USER@$DEPLOY_HOST"
        exit 1
    fi
    log_info "SSH 连接正常"
}

# ===== 首次初始化服务器 =====
setup_server() {
    log_info "初始化服务器目录结构..."
    $SCP_CMD "$DEPLOY_DIR/remote/setup.sh" "$DEPLOY_USER@$DEPLOY_HOST:/tmp/setup.sh"
    $SSH_CMD "bash /tmp/setup.sh"

    log_info "上传服务器端管理脚本..."
    $SCP_CMD "$DEPLOY_DIR/remote/restart-web.sh" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_SCRIPTS_DIR/"
    $SCP_CMD "$DEPLOY_DIR/remote/restart-task.sh" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_SCRIPTS_DIR/"
    $SCP_CMD "$DEPLOY_DIR/remote/restart-front.sh" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_SCRIPTS_DIR/"
    $SSH_CMD "chmod +x $REMOTE_SCRIPTS_DIR/*.sh"

    log_info "服务器初始化完成"
}

# ===== 本地构建 =====
build_local() {
    local target="$1"
    log_info "开始本地构建 (目标: $target)..."

    cd "$ROOT_DIR"
    bash build.sh "$target"

    # 验证产物存在
    case "$target" in
        web|backend|all)
            if [ ! -f "$ROOT_DIR/$LOCAL_WAR" ]; then
                log_error "构建产物不存在: $LOCAL_WAR"
                exit 1
            fi
            ;;
    esac

    case "$target" in
        task|backend|all)
            if [ ! -f "$ROOT_DIR/$LOCAL_TASK_JAR" ]; then
                log_error "构建产物不存在: $LOCAL_TASK_JAR"
                exit 1
            fi
            ;;
    esac

    case "$target" in
        front|front-test|all)
            if [ ! -d "$ROOT_DIR/$LOCAL_FRONT_DIST" ]; then
                log_error "构建产物不存在: $LOCAL_FRONT_DIST"
                exit 1
            fi
            ;;
    esac

    log_info "本地构建完成"
}

# ===== 远程备份 =====
backup_remote() {
    local target="$1"
    log_info "备份服务器当前版本 ($VERSION)..."

    $SSH_CMD bash <<EOF
        BACKUP="$REMOTE_BACKUP_DIR/$VERSION"
        mkdir -p "\$BACKUP"

        # 按目标备份
        case "$target" in
            web|backend|all)
                cp "$TOMCAT_WEBAPPS/ROOT.war" "\$BACKUP/" 2>/dev/null && echo "已备份 ROOT.war" || echo "ROOT.war 不存在,跳过"
                ;;
        esac

        case "$target" in
            task|backend|all)
                cp "$REMOTE_TASK_DIR/task.jar" "\$BACKUP/" 2>/dev/null && echo "已备份 task.jar" || echo "task.jar 不存在,跳过"
                ;;
        esac

        case "$target" in
            front|front-test|all)
                if [ -d "$REMOTE_FRONT_DIR/dist" ]; then
                    cp -r "$REMOTE_FRONT_DIR/dist" "\$BACKUP/"
                    echo "已备份 front/dist"
                fi
                ;;
        esac

        # 清理过期备份,保留最近 $MAX_BACKUPS 个
        cd "$REMOTE_BACKUP_DIR"
        ls -dt */ 2>/dev/null | tail -n +\$(($MAX_BACKUPS + 1)) | xargs rm -rf 2>/dev/null
        echo "当前备份列表:"
        ls -dt */ 2>/dev/null | head -5
EOF

    log_info "远程备份完成"
}

# ===== 上传产物 =====
upload_artifacts() {
    local target="$1"

    case "$target" in
        web|backend|all)
            log_info "上传 ROOT.war..."
            $SCP_CMD "$ROOT_DIR/$LOCAL_WAR" "$DEPLOY_USER@$DEPLOY_HOST:$TOMCAT_WEBAPPS/ROOT.war"
            ;;
    esac

    case "$target" in
        task|backend|all)
            log_info "上传 task.jar..."
            $SCP_CMD "$ROOT_DIR/$LOCAL_TASK_JAR" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_TASK_DIR/task.jar"
            ;;
    esac

    case "$target" in
        front|front-test|all)
            log_info "上传前端文件..."
            # 先清空远程 dist再上传
            $SSH_CMD "rm -rf $REMOTE_FRONT_DIR/dist"
            $SCP_CMD -r "$ROOT_DIR/$LOCAL_FRONT_DIST" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_FRONT_DIR/dist"
            ;;
    esac

    log_info "产物上传完成"
}

# ===== 远程重启服务 =====
restart_services() {
    local target="$1"

    case "$target" in
        web|backend|all)
            log_info "重启 Web 服务..."
            $SSH_CMD "bash $REMOTE_SCRIPTS_DIR/restart-web.sh"
            ;;
    esac

    case "$target" in
        task|backend|all)
            log_info "重启 Task 服务..."
            $SSH_CMD "bash $REMOTE_SCRIPTS_DIR/restart-task.sh $TASK_PROFILE '$TASK_JVM_OPTS'"
            ;;
    esac

    case "$target" in
        front|front-test|all)
            log_info "重新加载前端..."
            $SSH_CMD "bash $REMOTE_SCRIPTS_DIR/restart-front.sh"
            ;;
    esac
}

# ===== 健康检查 =====
healthcheck() {
    local target="$1"

    # Web 服务检查
    if [ "$target" = "all" ] || [ "$target" = "web" ] || [ "$target" = "backend" ]; then
        log_info "健康检查 Web 服务 ($HEALTHCHECK_URL)..."
        for i in $(seq 1 $HEALTHCHECK_RETRIES); do
            if curl -sf "$HEALTHCHECK_URL" > /dev/null 2>&1; then
                log_info "✅ Web 服务健康 (第${i}次检查)"
                return 0
            fi
            echo -n "."
            sleep $HEALTHCHECK_INTERVAL
        done
        log_error "❌ Web 服务健康检查失败 (${HEALTHCHECK_RETRIES}次重试后)"
        return 1
    fi

    # 前端检查
    if [ "$target" = "front" ] || [ "$target" = "front-test" ]; then
        log_info "健康检查前端..."
        if curl -sf "http://$DEPLOY_HOST/" > /dev/null 2>&1; then
            log_info "✅ 前端服务健康"
            return 0
        else
            log_error "❌ 前端服务健康检查失败"
            return 1
        fi
    fi

    return 0
}

# ===== 回滚 =====
rollback() {
    log_info "查找最近的备份..."

    # 获取最近的备份目录名
    LATEST_BACKUP=$($SSH_CMD "ls -dt $REMOTE_BACKUP_DIR/*/ 2>/dev/null | head -1 | xargs basename 2>/dev/null")

    if [ -z "$LATEST_BACKUP" ]; then
        log_error "没有可回滚的备份"
        exit 1
    fi

    log_warn "回滚到版本: $LATEST_BACKUP"

    $SSH_CMD bash <<EOF
        BACKUP="$REMOTE_BACKUP_DIR/$LATEST_BACKUP"

        # 还原 WAR
        if [ -f "\$BACKUP/ROOT.war" ]; then
            cp "\$BACKUP/ROOT.war" "$TOMCAT_WEBAPPS/ROOT.war"
            echo "已还原 ROOT.war"
        fi

        # 还原 Task JAR
        if [ -f "\$BACKUP/task.jar" ]; then
            cp "\$BACKUP/task.jar" "$REMOTE_TASK_DIR/task.jar"
            echo "已还原 task.jar"
        fi

        # 还原前端
        if [ -d "\$BACKUP/dist" ]; then
            rm -rf "$REMOTE_FRONT_DIR/dist"
            cp -r "\$BACKUP/dist" "$REMOTE_FRONT_DIR/dist"
            echo "已还原 front/dist"
        fi
EOF

    # 重启所有服务
    restart_services "all"

    log_info "回滚完成"

    notify_feishu "⚠️ SmartClean 已回滚" \
      "**回滚版本:** $LATEST_BACKUP\\n**服务器:** $DEPLOY_HOST\\n**操作人:** $(whoami)@$(hostname)" \
      "yellow"
}

# ===== 主流程 =====
TARGET="${1:-all}"
DEPLOY_START=$(date +%s)

# 特殊命令
case "$TARGET" in
    setup)
        check_ssh
        setup_server
        exit 0
        ;;
    rollback)
        check_ssh
        rollback
        exit 0
        ;;
esac

log_info "======================================"
log_info "  SmartClean 自动化部署"
log_info "  版本:  $VERSION"
log_info "  分支:  $BRANCH"
log_info "  目标:  $TARGET"
log_info "  服务器: $DEPLOY_USER@$DEPLOY_HOST"
log_info "======================================"

# 1. 检查连接
check_ssh

# 2. 本地构建
build_local "$TARGET"

# 3. 远程备份当前版本
backup_remote "$TARGET"

# 4. 上传构建产物
upload_artifacts "$TARGET"

# 5. 远程重启服务
restart_services "$TARGET"

# 6. 健康检查
if healthcheck "$TARGET"; then
    ELAPSED=$(( $(date +%s) - DEPLOY_START ))
    log_info "======================================"
    log_info "  ✅ 部署成功!"
    log_info "  版本: $VERSION"
    log_info "  耗时: ${ELAPSED}s"
    log_info "  前端: http://$DEPLOY_HOST"
    log_info "  Web:  http://$DEPLOY_HOST:8095"
    log_info "  Task: http://$DEPLOY_HOST:8097"
    log_info "======================================"

    notify_feishu "✅ SmartClean 部署成功" \
      "**版本:** $VERSION\\n**分支:** $BRANCH\\n**提交:** $COMMIT\\n**目标:** $TARGET\\n**服务器:** $DEPLOY_HOST\\n**耗时:** ${ELAPSED}s\\n**操作人:** $(whoami)@$(hostname)" \
      "green"
else
    log_error "健康检查失败,自动回滚..."
    rollback

    ELAPSED=$(( $(date +%s) - DEPLOY_START ))
    notify_feishu "❌ SmartClean 部署失败(已回滚)" \
      "**版本:** $VERSION\\n**分支:** $BRANCH\\n**提交:** $COMMIT\\n**服务器:** $DEPLOY_HOST\\n**耗时:** ${ELAPSED}s\\n**状态:** 健康检查失败,已自动回滚" \
      "red"

    exit 1
fi

九、回滚脚本

# deploy/rollback.sh
#!/bin/bash
# 快捷回滚入口
DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)"
exec "$DEPLOY_DIR/deploy.sh" rollback

十、使用方式

首次使用(一次性设置)

# 1. 配置 SSH 免密登录
ssh-copy-id root@192.168.1.182

# 2. 初始化服务器目录结构 + 上传管理脚本
./deploy/deploy.sh setup

# 3. 根据实际情况修改 deploy/config.sh 中的路径配置
#    特别是 TOMCAT_HOME 要对应服务器上实际的 Tomcat 安装路径

日常部署

# 全量部署(构建全部 + 部署全部)
./deploy/deploy.sh

# 只改了后端 Web 代码
./deploy/deploy.sh web

# 只改了 Task 服务代码
./deploy/deploy.sh task

# 后端都改了
./deploy/deploy.sh backend

# 只改了前端(生产包)
./deploy/deploy.sh front

# 前端测试环境包
./deploy/deploy.sh front-test

# 出问题了,一键回滚
./deploy/deploy.sh rollback

查看服务器上的备份

ssh root@192.168.1.182 "ls -lt /opt/smartclean/backups/"

十一、部署流程图(以 ./deploy.sh web 为例)

本机                                    192.168.1.182
────                                    ─────────────

1. mvn clean package
   → ROOT.war 生成
                                    2. mkdir backups/20260415-153000/
                                       cp ROOT.war → backups/

3. scp ROOT.war ───────────────→   4. ROOT.war → tomcat/webapps/

                                    5. shutdown.sh → rm ROOT/ → startup.sh

6. curl http://182:8095/health
   ├── ✅ 成功 → 飞书通知"部署成功"
   └── ❌ 失败 → 触发回滚
                                    7. (回滚) cp backups/最新/ROOT.war → webapps/
                                       → restart tomcat
        飞书通知"已回滚" ←──────

十二、与 Docker 版方案对比

维度 本方案(无 Docker Docker 版
依赖 仅需 SSH + SCP 需要 Docker
环境一致性 依赖服务器已有环境JDK、Tomcat、Nginx 镜像自包含,环境完全一致
部署速度 快(只传产物,几十 MB 慢(构建镜像,几百 MB
适合场景 服务器少1-3 台),已有运行环境 多环境、多服务器、需要环境隔离
回滚 文件级回滚(还原备份文件) 镜像级回滚(切换镜像 tag
学习成本 Shell + SSH 中(需了解 Docker
改造成本 低(复用现有 build.sh + 服务器环境) 中(需编写 Dockerfile、调试容器配置

十三、后续演进

阶段 动作
当前 本方案:本机执行 deploy.shSSH 部署到 182
阶段 2 多环境config.sh 支持 --env test/prod 参数,切换不同服务器
阶段 3 CI/CD将 deploy.sh 逻辑搬到 Gitea Actionspush 自动触发
阶段 4 按需容器化:逐步将服务迁入 Dockerdeploy.sh 改为推送镜像

十四、安全注意事项

  1. deploy/.env 不入 git:在 .gitignore 中添加 deploy/.env
  2. SSH Key 管理:建议为部署专用创建独立 Key限制只能执行特定命令
  3. 备份清理:默认保留最近 5 个备份,可在 config.sh 中调整 MAX_BACKUPS
  4. 操作审计:每次部署的版本号、操作人、时间都会通过飞书通知记录