deploy.sh 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #!/bin/bash
  2. # ================= 配置区域 =================
  3. # 源代码路径
  4. SOURCE_DIR="/home/lq/lq_workspace/source/LQAgentPlatform"
  5. # Docker Compose 运行路径
  6. DOCKER_APP_DIR="/home/lq/lq_workspace/app/LqAgentServer/docker"
  7. # 配置文件名称
  8. COMPOSE_FILE="docker-compose.yml"
  9. # 镜像名称 (Repository)
  10. IMAGE_NAME="lq_agent_platform_server"
  11. # Git 凭证
  12. GIT_USER="WangXuMing"
  13. GIT_PASS="123456"
  14. # ================= 辅助函数 =================
  15. # 打印带时间戳的日志
  16. log_info() {
  17. echo -e "\033[32m[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1\033[0m"
  18. }
  19. log_error() {
  20. echo -e "\033[31m[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $1\033[0m"
  21. }
  22. # 检查命令执行状态,如果失败则退出
  23. check_status() {
  24. if [ $? -ne 0 ]; then
  25. log_error "$1 执行失败,脚本终止。"
  26. exit 1
  27. fi
  28. }
  29. # ================= 步骤 1: Git 拉取代码 (带重试+强制拉取) =================
  30. log_info "步骤 1: 进入源码目录并拉取最新代码..."
  31. if [ ! -d "$SOURCE_DIR" ]; then
  32. log_error "源码目录不存在: $SOURCE_DIR"
  33. exit 1
  34. fi
  35. # 检查目录进入权限并修复
  36. if [ ! -x "$SOURCE_DIR" ]; then
  37. log_error "源码目录无进入权限!正在修复..."
  38. sudo chmod +x "$SOURCE_DIR"
  39. sudo chown -R lq:lq "$SOURCE_DIR"
  40. fi
  41. cd "$SOURCE_DIR" || {
  42. log_error "进入源码目录失败!路径:$SOURCE_DIR"
  43. log_error "可能原因:1. 目录权限不足 2. 路径含特殊字符 3. 目录被删除"
  44. exit 1
  45. }
  46. check_status "进入源码目录" # 双重保障
  47. # 检查是否为 Git 仓库
  48. if [ ! -d ".git" ]; then
  49. log_error "当前目录不是 Git 仓库!路径:$SOURCE_DIR"
  50. exit 1
  51. fi
  52. log_info "检查本地是否存在可能与远程冲突的已修改文件..."
  53. HAS_CONFLICT_FILES=$(git status --porcelain | grep -v "^??")
  54. if [ -n "$HAS_CONFLICT_FILES" ]; then
  55. log_info "发现以下文件存在本地修改(将被远程最新代码覆盖):"
  56. echo "$HAS_CONFLICT_FILES" | awk '{print " - " $2}'
  57. log_info "正在强制丢弃本地修改,确保同步远程最新代码..."
  58. # 强制丢弃修改
  59. git checkout -- . # 仅丢弃已跟踪文件的本地修改(冲突风险文件)
  60. log_info "本地冲突文件修改已丢弃,准备拉取远程最新代码..."
  61. else
  62. log_info "本地无可能冲突的已修改文件,直接拉取远程最新代码..."
  63. fi
  64. # 组装 Git 认证 URL(保留原逻辑)
  65. ORIGIN_URL=$(git remote get-url origin 2>/dev/null)
  66. if [ $? -ne 0 ]; then
  67. log_error "获取 Git 远程地址失败!请检查 remote 配置"
  68. exit 1
  69. fi
  70. CLEAN_URL=${ORIGIN_URL#*://}
  71. AUTH_URL="http://${GIT_USER}:${GIT_PASS}@${CLEAN_URL}"
  72. MAX_RETRIES=3
  73. COUNT=0
  74. GIT_SUCCESS=0
  75. while [ $COUNT -lt $MAX_RETRIES ]; do
  76. log_info "正在执行 Git Pull (第 $((COUNT+1)) 次尝试) - 强制拉取 test 分支最新代码..."
  77. # 核心修改:明确分支+强制拉取+兼容历史差异
  78. git pull "$AUTH_URL" test --force --allow-unrelated-histories
  79. if [ $? -eq 0 ]; then
  80. GIT_SUCCESS=1
  81. # 拉取成功后,打印最新 commit 信息(验证是否为最新)
  82. LATEST_COMMIT=$(git log -1 --format="%h - %s ")
  83. log_info "Git Pull 成功!当前部署提交版本:$LATEST_COMMIT"
  84. break
  85. else
  86. log_error "Git Pull 失败,准备重试..."
  87. COUNT=$((COUNT+1))
  88. sleep 3 # 延长重试间隔,避免频繁请求
  89. fi
  90. done
  91. if [ $GIT_SUCCESS -eq 0 ]; then
  92. log_error "Git Pull 达到最大重试次数,无法更新代码。"
  93. exit 1
  94. fi
  95. # ================= 步骤 2: 关闭当前容器 =================
  96. log_info "步骤 2: 关闭正在运行的容器..."
  97. if [ ! -d "$DOCKER_APP_DIR" ]; then
  98. log_error "Docker 运行目录不存在: $DOCKER_APP_DIR"
  99. exit 1
  100. fi
  101. cd "$DOCKER_APP_DIR"
  102. check_status "进入 Docker 运行目录"
  103. docker compose down
  104. # 即使 down 失败(例如没启动),也继续执行,只记录错误
  105. if [ $? -ne 0 ]; then
  106. log_error "警告: Docker Compose Down 返回非零状态,尝试继续..."
  107. fi
  108. # ================= 步骤 3: 提取版本号并删除旧镜像 =================
  109. log_info "步骤 3: 查找旧镜像并计算新版本号..."
  110. # 获取镜像信息,例如: lq_agent_platform_server v0.13 76d87fcfb5e5
  111. IMAGE_INFO=$(docker images | grep "^${IMAGE_NAME} " | awk '{print $2, $3}' | head -n 1)
  112. NEW_TAG="v0.01" # 默认初始版本
  113. if [ -n "$IMAGE_INFO" ]; then
  114. OLD_TAG=$(echo "$IMAGE_INFO" | awk '{print $1}')
  115. IMAGE_ID=$(echo "$IMAGE_INFO" | awk '{print $2}')
  116. log_info "找到旧镜像: Tag=$OLD_TAG, ID=$IMAGE_ID"
  117. # 提取版本号数字 (去掉 'v'),例如 v0.13 -> 0.13
  118. VERSION_NUM=$(echo "$OLD_TAG" | sed 's/v//')
  119. # 计算新版本号 (这里设置为 +0.01,即 0.13 -> 0.14)
  120. NEW_VERSION_NUM=$(echo "$VERSION_NUM" | awk '{printf "%.2f", $1 + 0.01}')
  121. NEW_TAG="v$NEW_VERSION_NUM"
  122. log_info "计算出的新版本号为: $NEW_TAG"
  123. log_info "正在删除旧镜像 ID: $IMAGE_ID ..."
  124. docker rmi -f "$IMAGE_ID"
  125. if [ $? -ne 0 ]; then
  126. log_error "警告: 删除旧镜像失败,可能被占用,将继续构建。"
  127. else
  128. log_info "旧镜像删除成功。"
  129. fi
  130. else
  131. log_info "未找到旧镜像,将使用默认版本 $NEW_TAG 构建。"
  132. fi
  133. # ================= 步骤 4: 构建新镜像 =================
  134. log_info "步骤 4: 构建新镜像 $IMAGE_NAME:$NEW_TAG ..."
  135. cd "$SOURCE_DIR"
  136. check_status "返回源码目录"
  137. docker build -t "${IMAGE_NAME}:${NEW_TAG}" .
  138. check_status "镜像构建"
  139. log_info "镜像构建成功: ${IMAGE_NAME}:${NEW_TAG}"
  140. # ================= 步骤 5: 修改 docker-compose.yml 版本号 =================
  141. log_info "步骤 5: 更新 docker-compose.yml 中的版本号..."
  142. cd "$DOCKER_APP_DIR"
  143. check_status "进入 Docker 运行目录"
  144. if [ ! -f "$COMPOSE_FILE" ]; then
  145. log_error "找不到配置文件: $COMPOSE_FILE"
  146. exit 1
  147. fi
  148. # 使用 sed 正则替换
  149. # 匹配: image: lq_agent_platform_server:任意字符
  150. # 替换为: image: lq_agent_platform_server:新版本号
  151. sed -i "s|image: ${IMAGE_NAME}:.*|image: ${IMAGE_NAME}:${NEW_TAG}|" "$COMPOSE_FILE"
  152. check_status "修改 docker-compose.yml"
  153. # 验证修改结果
  154. MATCH_LINE=$(grep "image: ${IMAGE_NAME}:" "$COMPOSE_FILE")
  155. log_info "配置文件已更新: $MATCH_LINE"
  156. # ================= 步骤 6: 启动容器 =================
  157. log_info "步骤 6: 启动 Docker Compose..."
  158. docker compose up -d
  159. check_status "启动容器"
  160. log_info "========================================"
  161. log_info "生产端部署成功!当前运行版本: $NEW_TAG"
  162. log_info "========================================"