prod.sh 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/bin/bash
  2. # --- Harbor 配置 ---
  3. HARBOR_HOST="10.192.72.12:5000"
  4. HARBOR_USER="admin"
  5. HARBOR_PASS="Harbor12345"
  6. PROJECT_NAME="default"
  7. REPO_NAME="yusys_ai_web-yusys-ai-web"
  8. HARBOR_URL="http://${HARBOR_HOST}"
  9. # --- Portainer 配置 ---
  10. PORTAINER_URL="https://10.192.72.12:9443"
  11. PORTAINER_TOKEN="ptr_S0ynFUayDlFCGptUhIcfEuv+3FMKdz90CAb2x3YEUKw="
  12. STACK_ID="13"
  13. ENDPOINT_ID="2"
  14. # --- 从 Harbor 查询最新 tag ---
  15. echo "→ 正在从 Harbor 查询最新镜像标签..."
  16. # 获取所有 artifacts 的 JSON 响应
  17. ARTIFACTS_JSON=$(curl -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
  18. "${HARBOR_URL}/api/v2.0/projects/${PROJECT_NAME}/repositories/${REPO_NAME}/artifacts" 2>/dev/null)
  19. # 检查是否成功获取数据
  20. if [ -z "$ARTIFACTS_JSON" ] || echo "$ARTIFACTS_JSON" | grep -qE '"code"|"errors"'; then
  21. echo "⚠️ 无法连接到 Harbor 或仓库不存在,使用默认标签 1.0.0"
  22. TAG="1.0.0"
  23. else
  24. # 提取所有 tags 部分,然后从中提取 name 字段的值(只匹配语义化版本号格式 x.y.z)
  25. # 方法:先提取所有 "tags":[...] 部分,然后从中提取 "name":"x.y.z"
  26. ALL_TAGS=$(echo "$ARTIFACTS_JSON" | grep -o '"tags":[^]]*' | grep -o '"name":"[0-9]\+\.[0-9]\+\.[0-9]\+"' | sed 's/"name":"\([0-9]\+\.[0-9]\+\.[0-9]\+\)"/\1/' | sort -V | uniq)
  27. if [ -z "$ALL_TAGS" ]; then
  28. echo "⚠️ 未找到符合格式的标签,使用默认标签 1.0.0"
  29. TAG="1.0.0"
  30. else
  31. # 显示所有找到的标签(用于调试)
  32. echo "→ 找到的标签列表:"
  33. echo "$ALL_TAGS" | while read tag; do
  34. echo " - $tag"
  35. done
  36. # 获取最新的标签(按版本号排序后的最后一个)
  37. LATEST_TAG=$(echo "$ALL_TAGS" | tail -1)
  38. echo "→ 最新标签: ${LATEST_TAG}"
  39. # 小版本号加1 (例如: 1.0.9 -> 1.0.10)
  40. MAJOR=$(echo "$LATEST_TAG" | cut -d. -f1)
  41. MINOR=$(echo "$LATEST_TAG" | cut -d. -f2)
  42. PATCH=$(echo "$LATEST_TAG" | cut -d. -f3)
  43. PATCH=$((PATCH + 1))
  44. TAG="${MAJOR}.${MINOR}.${PATCH}"
  45. echo "→ 新标签: ${TAG}"
  46. fi
  47. fi
  48. IMAGE="${HARBOR_HOST}/${PROJECT_NAME}/${REPO_NAME}:${TAG}"
  49. # --- 分支检查 ---
  50. CUR_BRANCH=$(git symbolic-ref --quiet --short HEAD 2>/dev/null || git rev-parse --abbrev-ref HEAD)
  51. [ "$CUR_BRANCH" = "test" ] || { echo "❌ 仅允许在 test 分支打包!"; exit 1; }
  52. # --- 交互式拉代码 ---
  53. echo "→ 正在 git pull,请输入用户名/密码 ..."
  54. git pull origin test || { echo "❌ git pull 失败"; exit 1; }
  55. # --- 后续流程 ---
  56. npm run build || { echo "❌ npm run build 失败"; exit 1; }
  57. docker build -t "${IMAGE}" . &&
  58. docker push "${IMAGE}" && {
  59. # 从 Harbor API 获取镜像的 digest
  60. echo "→ 正在获取镜像 SHA256..."
  61. ARTIFACT_INFO=$(curl -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
  62. "${HARBOR_URL}/api/v2.0/projects/${PROJECT_NAME}/repositories/${REPO_NAME}/artifacts/${TAG}")
  63. SHA256=$(printf '%s' "$ARTIFACT_INFO" | grep -o '"digest":"sha256:[^"]*' | cut -d'"' -f4 | cut -d':' -f2)
  64. echo "📦 Image SHA256: ${SHA256}"
  65. # 更新 Portainer 堆栈中的镜像 SHA256
  66. if [ -n "$SHA256" ]; then
  67. echo "→ 正在更新 Portainer 堆栈..."
  68. # 获取当前的堆栈文件内容
  69. STACK_FILE_RESPONSE=$(curl -s -k -X GET -H "X-API-Key: ${PORTAINER_TOKEN}" \
  70. "${PORTAINER_URL}/api/stacks/${STACK_ID}/file")
  71. echo "→ Portainer 堆栈文件:${STACK_FILE_RESPONSE}"
  72. if [ -z "$STACK_FILE_RESPONSE" ] || echo "$STACK_FILE_RESPONSE" | grep -qE '"message"|"error"'; then
  73. echo "⚠️ 无法获取 Portainer 堆栈文件,跳过更新"
  74. else
  75. # 直接在 JSON 字符串中替换 SHA256(SHA256 只包含十六进制字符,无需转义)
  76. UPDATE_JSON=$(printf '%s' "$STACK_FILE_RESPONSE" | sed -E "s/@sha256:[0-9a-fA-F]{64}/@sha256:${SHA256}/g")
  77. echo "→ 修改后的 Portainer 堆栈文件:${UPDATE_JSON}"
  78. BODY_PREFIX=${UPDATE_JSON%\}}
  79. FINAL_PAYLOAD="${BODY_PREFIX}, \"prune\": false, \"pullImage\": true }"
  80. # 更新堆栈文件
  81. UPDATE_RESPONSE=$(curl -s -k -X PUT \
  82. -H "X-API-Key: ${PORTAINER_TOKEN}" \
  83. -H "Content-Type: application/json" \
  84. -d "${FINAL_PAYLOAD}" \
  85. "${PORTAINER_URL}/api/stacks/${STACK_ID}?endpointId=${ENDPOINT_ID}")
  86. # 3. 检查结果
  87. # 成功时,Portainer 会返回更新后的 Stack 对象(包含 "Id" 字段)
  88. if echo "$UPDATE_RESPONSE" | grep -q '"Id":'; then
  89. echo "✅ 堆栈更新并重部署成功!"
  90. else
  91. echo "⚠️ 更新失败"
  92. echo "响应: ${UPDATE_RESPONSE}"
  93. fi
  94. fi
  95. else
  96. echo "⚠️ 未获取到 SHA256,跳过 Portainer 更新"
  97. fi
  98. }
  99. echo "✅ All done: ${IMAGE}"