| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- #!/bin/bash
- # --- Harbor 配置 ---
- HARBOR_HOST="10.192.72.12:5000"
- HARBOR_USER="admin"
- HARBOR_PASS="Harbor12345"
- PROJECT_NAME="default"
- REPO_NAME="yusys_ai_web-yusys-ai-web"
- HARBOR_URL="http://${HARBOR_HOST}"
- # --- Portainer 配置 ---
- PORTAINER_URL="https://10.192.72.12:9443"
- PORTAINER_TOKEN="ptr_S0ynFUayDlFCGptUhIcfEuv+3FMKdz90CAb2x3YEUKw="
- STACK_ID="13"
- ENDPOINT_ID="2"
- # --- 从 Harbor 查询最新 tag ---
- echo "→ 正在从 Harbor 查询最新镜像标签..."
- # 获取所有 artifacts 的 JSON 响应
- ARTIFACTS_JSON=$(curl -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
- "${HARBOR_URL}/api/v2.0/projects/${PROJECT_NAME}/repositories/${REPO_NAME}/artifacts" 2>/dev/null)
- # 检查是否成功获取数据
- if [ -z "$ARTIFACTS_JSON" ] || echo "$ARTIFACTS_JSON" | grep -qE '"code"|"errors"'; then
- echo "⚠️ 无法连接到 Harbor 或仓库不存在,使用默认标签 1.0.0"
- TAG="1.0.0"
- else
- # 提取所有 tags 部分,然后从中提取 name 字段的值(只匹配语义化版本号格式 x.y.z)
- # 方法:先提取所有 "tags":[...] 部分,然后从中提取 "name":"x.y.z"
- 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)
-
- if [ -z "$ALL_TAGS" ]; then
- echo "⚠️ 未找到符合格式的标签,使用默认标签 1.0.0"
- TAG="1.0.0"
- else
- # 显示所有找到的标签(用于调试)
- echo "→ 找到的标签列表:"
- echo "$ALL_TAGS" | while read tag; do
- echo " - $tag"
- done
-
- # 获取最新的标签(按版本号排序后的最后一个)
- LATEST_TAG=$(echo "$ALL_TAGS" | tail -1)
- echo "→ 最新标签: ${LATEST_TAG}"
-
- # 小版本号加1 (例如: 1.0.9 -> 1.0.10)
- MAJOR=$(echo "$LATEST_TAG" | cut -d. -f1)
- MINOR=$(echo "$LATEST_TAG" | cut -d. -f2)
- PATCH=$(echo "$LATEST_TAG" | cut -d. -f3)
- PATCH=$((PATCH + 1))
- TAG="${MAJOR}.${MINOR}.${PATCH}"
- echo "→ 新标签: ${TAG}"
- fi
- fi
- IMAGE="${HARBOR_HOST}/${PROJECT_NAME}/${REPO_NAME}:${TAG}"
- # --- 分支检查 ---
- CUR_BRANCH=$(git symbolic-ref --quiet --short HEAD 2>/dev/null || git rev-parse --abbrev-ref HEAD)
- [ "$CUR_BRANCH" = "test" ] || { echo "❌ 仅允许在 test 分支打包!"; exit 1; }
- # --- 交互式拉代码 ---
- echo "→ 正在 git pull,请输入用户名/密码 ..."
- git pull origin test || { echo "❌ git pull 失败"; exit 1; }
- # --- 后续流程 ---
- npm run build || { echo "❌ npm run build 失败"; exit 1; }
- docker build -t "${IMAGE}" . &&
- docker push "${IMAGE}" && {
- # 从 Harbor API 获取镜像的 digest
- echo "→ 正在获取镜像 SHA256..."
- ARTIFACT_INFO=$(curl -s -u "${HARBOR_USER}:${HARBOR_PASS}" \
- "${HARBOR_URL}/api/v2.0/projects/${PROJECT_NAME}/repositories/${REPO_NAME}/artifacts/${TAG}")
- SHA256=$(printf '%s' "$ARTIFACT_INFO" | grep -o '"digest":"sha256:[^"]*' | cut -d'"' -f4 | cut -d':' -f2)
- echo "📦 Image SHA256: ${SHA256}"
-
- # 更新 Portainer 堆栈中的镜像 SHA256
- if [ -n "$SHA256" ]; then
- echo "→ 正在更新 Portainer 堆栈..."
-
- # 获取当前的堆栈文件内容
- STACK_FILE_RESPONSE=$(curl -s -k -X GET -H "X-API-Key: ${PORTAINER_TOKEN}" \
- "${PORTAINER_URL}/api/stacks/${STACK_ID}/file")
- echo "→ Portainer 堆栈文件:${STACK_FILE_RESPONSE}"
-
- if [ -z "$STACK_FILE_RESPONSE" ] || echo "$STACK_FILE_RESPONSE" | grep -qE '"message"|"error"'; then
- echo "⚠️ 无法获取 Portainer 堆栈文件,跳过更新"
- else
- # 直接在 JSON 字符串中替换 SHA256(SHA256 只包含十六进制字符,无需转义)
- UPDATE_JSON=$(printf '%s' "$STACK_FILE_RESPONSE" | sed -E "s/@sha256:[0-9a-fA-F]{64}/@sha256:${SHA256}/g")
-
- echo "→ 修改后的 Portainer 堆栈文件:${UPDATE_JSON}"
- BODY_PREFIX=${UPDATE_JSON%\}}
- FINAL_PAYLOAD="${BODY_PREFIX}, \"prune\": false, \"pullImage\": true }"
- # 更新堆栈文件
- UPDATE_RESPONSE=$(curl -s -k -X PUT \
- -H "X-API-Key: ${PORTAINER_TOKEN}" \
- -H "Content-Type: application/json" \
- -d "${FINAL_PAYLOAD}" \
- "${PORTAINER_URL}/api/stacks/${STACK_ID}?endpointId=${ENDPOINT_ID}")
-
- # 3. 检查结果
- # 成功时,Portainer 会返回更新后的 Stack 对象(包含 "Id" 字段)
- if echo "$UPDATE_RESPONSE" | grep -q '"Id":'; then
- echo "✅ 堆栈更新并重部署成功!"
- else
- echo "⚠️ 更新失败"
- echo "响应: ${UPDATE_RESPONSE}"
- fi
- fi
- else
- echo "⚠️ 未获取到 SHA256,跳过 Portainer 更新"
- fi
- }
- echo "✅ All done: ${IMAGE}"
|