fix(jenkins): poll from Harbor API instead of k8s yaml, add FORCE_DEPLOY param

This commit is contained in:
wwweww
2026-05-04 02:55:19 +08:00
parent 590e5b0cd2
commit 4bdd040e91
+44 -27
View File
@@ -40,11 +40,15 @@ pipeline {
defaultValue: 'latest', defaultValue: 'latest',
description: '要监听的镜像 Tag' description: '要监听的镜像 Tag'
) )
// 逗号分隔,留空则自动扫描所有服务
string( string(
name: 'TARGET_SERVICES', name: 'TARGET_SERVICES',
defaultValue: '', 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()) { if (params.TARGET_SERVICES?.trim()) {
env.SERVICE_LIST = params.TARGET_SERVICES.trim() env.SERVICE_LIST = params.TARGET_SERVICES.trim()
echo "使用指定服务列表: ${env.SERVICE_LIST}"
} else { } else {
// 自动从 deploy/k8s/service 目录扫描所有 Deployment 名称 // 直接查询 Harbor API,只监控实际存在的仓库
// 命名规律:{service}-{api|rpc|mq} // 避免扫描 k8s yaml 导致检查大量不存在的镜像
def services = sh( withCredentials([
script: ''' usernamePassword(
find deploy/k8s/service -name "*.yaml" \ credentialsId: 'harbor-credentials',
| xargs grep -l "kind: Deployment" \ usernameVariable: 'HARBOR_USER',
| xargs -I{} sh -c 'grep "^ name:" {} | head -1 | awk "{print \\$2}"' \ passwordVariable: 'HARBOR_PASS'
| sort -u \ )
| tr "\\n" "," ]) {
''', def services = sh(
returnStdout: true script: """
).trim().replaceAll(/,$/, '') curl -s -u "\${HARBOR_USER}:\${HARBOR_PASS}" \\
env.SERVICE_LIST = services --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}" echo "检查镜像: ${svc}:${params.IMAGE_TAG}"
// 调用 Harbor API 获取最新 digest
def digestResult = sh( def digestResult = sh(
script: """ script: """
curl -s -u "\${HARBOR_USER}:\${HARBOR_PASS}" \\ curl -s -u "\${HARBOR_USER}:\${HARBOR_PASS}" \\
@@ -133,31 +152,29 @@ pipeline {
).trim() ).trim()
if (!digestResult) { if (!digestResult) {
echo " ⚠️ 无法获取 ${svc} 的 digest,跳过(服务可能尚未推送)" echo " ⚠️ 无法获取 ${svc} 的 digest,跳过"
return return
} }
// 读取上次记录的 digest
def stateFile = "${DIGEST_STATE_DIR}/${svc}.digest" def stateFile = "${DIGEST_STATE_DIR}/${svc}.digest"
def lastDigest = "" def lastDigest = fileExists(stateFile) ? readFile(stateFile).trim() : ""
if (fileExists(stateFile)) {
lastDigest = readFile(stateFile).trim()
}
echo " 当前 digest: ${digestResult}" echo " 当前 digest: ${digestResult}"
echo " 上次 digest: ${lastDigest ?: '(首次检测)'}" echo " 上次 digest: ${lastDigest ?: '(首次检测)'}"
if (digestResult != lastDigest) { if (params.FORCE_DEPLOY || digestResult != lastDigest) {
echo " ✅ 检测到变化,加入部署队列" if (params.FORCE_DEPLOY) {
echo " 🔄 强制部署模式,加入部署队列"
} else {
echo " ✅ 检测到变化,加入部署队列"
}
changedServices << svc changedServices << svc
// 立即更新 digest 记录,防止重复触发
writeFile file: stateFile, text: digestResult writeFile file: stateFile, text: digestResult
} else { } else {
echo " — 无变化,跳过" echo " — 无变化,跳过"
} }
} }
// 将变化列表传递给下一个 Stage
env.CHANGED_SERVICES = changedServices.join(',') env.CHANGED_SERVICES = changedServices.join(',')
echo "需要更新的服务: ${env.CHANGED_SERVICES ?: '(无变化)'}" echo "需要更新的服务: ${env.CHANGED_SERVICES ?: '(无变化)'}"
} }