diff --git a/deploy/jenkins/Jenkinsfile.poll b/deploy/jenkins/Jenkinsfile.poll index 72c5846..6c17e3e 100644 --- a/deploy/jenkins/Jenkinsfile.poll +++ b/deploy/jenkins/Jenkinsfile.poll @@ -40,11 +40,15 @@ pipeline { defaultValue: 'latest', description: '要监听的镜像 Tag' ) - // 逗号分隔,留空则自动扫描所有服务 string( name: 'TARGET_SERVICES', defaultValue: '', - description: '指定要部署的服务(逗号分隔,如 user-api,user-rpc)。留空则部署所有有变化的服务' + description: '指定要部署的服务(逗号分隔,如 user-api,user-rpc)。留空则自动从 Harbor 查询实际存在的仓库' + ) + booleanParam( + name: 'FORCE_DEPLOY', + defaultValue: false, + description: '强制部署所有服务(忽略 digest 对比,用于手动触发全量更新)' ) } @@ -81,22 +85,38 @@ pipeline { // 构建要检查的服务列表 if (params.TARGET_SERVICES?.trim()) { env.SERVICE_LIST = params.TARGET_SERVICES.trim() + echo "使用指定服务列表: ${env.SERVICE_LIST}" } else { - // 自动从 deploy/k8s/service 目录扫描所有 Deployment 名称 - // 命名规律:{service}-{api|rpc|mq} - def services = sh( - script: ''' - find deploy/k8s/service -name "*.yaml" \ - | xargs grep -l "kind: Deployment" \ - | xargs -I{} sh -c 'grep "^ name:" {} | head -1 | awk "{print \\$2}"' \ - | sort -u \ - | tr "\\n" "," - ''', - returnStdout: true - ).trim().replaceAll(/,$/, '') - env.SERVICE_LIST = services + // 直接查询 Harbor API,只监控实际存在的仓库 + // 避免扫描 k8s yaml 导致检查大量不存在的镜像 + withCredentials([ + usernamePassword( + credentialsId: 'harbor-credentials', + usernameVariable: 'HARBOR_USER', + passwordVariable: 'HARBOR_PASS' + ) + ]) { + def services = sh( + script: """ + curl -s -u "\${HARBOR_USER}:\${HARBOR_PASS}" \\ + --connect-timeout 10 --max-time 30 \\ + "${HARBOR_API}/projects/${params.HARBOR_PROJECT}/repositories?page_size=100" \\ + | python3 -c " +import sys, json +repos = json.load(sys.stdin) +names = [r['name'].split('/')[-1] for r in repos if isinstance(repos, list)] +print(','.join(sorted(names))) +" 2>/dev/null || echo "" + """, + returnStdout: true + ).trim() + if (!services) { + error("无法从 Harbor 获取仓库列表,请检查 harbor-credentials 凭据和 Harbor 地址") + } + env.SERVICE_LIST = services + } + echo "从 Harbor 自动发现服务列表: ${env.SERVICE_LIST}" } - echo "监控服务列表: ${env.SERVICE_LIST}" } } } @@ -120,7 +140,6 @@ pipeline { echo "检查镜像: ${svc}:${params.IMAGE_TAG}" - // 调用 Harbor API 获取最新 digest def digestResult = sh( script: """ curl -s -u "\${HARBOR_USER}:\${HARBOR_PASS}" \\ @@ -133,31 +152,29 @@ pipeline { ).trim() if (!digestResult) { - echo " ⚠️ 无法获取 ${svc} 的 digest,跳过(服务可能尚未推送)" + echo " ⚠️ 无法获取 ${svc} 的 digest,跳过" return } - // 读取上次记录的 digest def stateFile = "${DIGEST_STATE_DIR}/${svc}.digest" - def lastDigest = "" - if (fileExists(stateFile)) { - lastDigest = readFile(stateFile).trim() - } + def lastDigest = fileExists(stateFile) ? readFile(stateFile).trim() : "" echo " 当前 digest: ${digestResult}" echo " 上次 digest: ${lastDigest ?: '(首次检测)'}" - if (digestResult != lastDigest) { - echo " ✅ 检测到变化,加入部署队列" + if (params.FORCE_DEPLOY || digestResult != lastDigest) { + if (params.FORCE_DEPLOY) { + echo " 🔄 强制部署模式,加入部署队列" + } else { + echo " ✅ 检测到变化,加入部署队列" + } changedServices << svc - // 立即更新 digest 记录,防止重复触发 writeFile file: stateFile, text: digestResult } else { echo " — 无变化,跳过" } } - // 将变化列表传递给下一个 Stage env.CHANGED_SERVICES = changedServices.join(',') echo "需要更新的服务: ${env.CHANGED_SERVICES ?: '(无变化)'}" }