fix(jenkins): poll from Harbor API instead of k8s yaml, add FORCE_DEPLOY param
This commit is contained in:
@@ -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 导致检查大量不存在的镜像
|
||||||
|
withCredentials([
|
||||||
|
usernamePassword(
|
||||||
|
credentialsId: 'harbor-credentials',
|
||||||
|
usernameVariable: 'HARBOR_USER',
|
||||||
|
passwordVariable: 'HARBOR_PASS'
|
||||||
|
)
|
||||||
|
]) {
|
||||||
def services = sh(
|
def services = sh(
|
||||||
script: '''
|
script: """
|
||||||
find deploy/k8s/service -name "*.yaml" \
|
curl -s -u "\${HARBOR_USER}:\${HARBOR_PASS}" \\
|
||||||
| xargs grep -l "kind: Deployment" \
|
--connect-timeout 10 --max-time 30 \\
|
||||||
| xargs -I{} sh -c 'grep "^ name:" {} | head -1 | awk "{print \\$2}"' \
|
"${HARBOR_API}/projects/${params.HARBOR_PROJECT}/repositories?page_size=100" \\
|
||||||
| sort -u \
|
| python3 -c "
|
||||||
| tr "\\n" ","
|
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
|
returnStdout: true
|
||||||
).trim().replaceAll(/,$/, '')
|
).trim()
|
||||||
|
if (!services) {
|
||||||
|
error("无法从 Harbor 获取仓库列表,请检查 harbor-credentials 凭据和 Harbor 地址")
|
||||||
|
}
|
||||||
env.SERVICE_LIST = services
|
env.SERVICE_LIST = services
|
||||||
}
|
}
|
||||||
echo "监控服务列表: ${env.SERVICE_LIST}"
|
echo "从 Harbor 自动发现服务列表: ${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) {
|
||||||
|
if (params.FORCE_DEPLOY) {
|
||||||
|
echo " 🔄 强制部署模式,加入部署队列"
|
||||||
|
} else {
|
||||||
echo " ✅ 检测到变化,加入部署队列"
|
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 ?: '(无变化)'}"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user