Просмотр исходного кода

流水线优化 - 最后推送到Harbor 制品库

dujian 1 неделя назад
Родитель
Сommit
a262220989

+ 29 - 18
docs/jenkins/Jenkinsfile-uat-build-deploy.groovy

@@ -5,8 +5,9 @@
  * Script Path: docs/jenkins/Jenkinsfile-uat-build-deploy.groovy
  *
  * Harbor (153.68): when PUSH_TO_HARBOR=true, push e.g.
- *   39.105.153.68/alien_cloud/gateway:uat-build-<BUILD_NUMBER>
- * Production promote jobs use SOURCE_TAG=uat-build-<same number>.
+ *   39.105.153.68/alien_cloud/gateway:uat-latest
+ * Before push: existing uat-latest is archived as uat-build-<BUILD_NUMBER> (same digest).
+ * New image is pushed only as uat-latest. Prod promote: SOURCE_TAG=uat-latest.
  */
 
 /** HARBOR_PUSH_SCOPE: all-java-services | <repo>-only */
@@ -26,8 +27,8 @@ def filterHarborPushScope(List allServices, String scope) {
     error("Unknown HARBOR_PUSH_SCOPE: ${scope}")
 }
 
-/** Delete oldest uat-build-* tags in Harbor, keep newest KEEP (never deletes CURRENT_TAG). */
-def pruneHarborUatTags(def script, String reg, String proj, List repoNames, int keepCount, String tagPrefix, String currentTag) {
+/** Delete oldest uat-build-* tags in Harbor, keep newest KEEP. Never deletes uat-latest or current build tag. */
+def pruneHarborUatTags(def script, String reg, String proj, List repoNames, int keepCount, String tagPrefix, String currentBuildTag, String latestTag) {
     if (repoNames == null || repoNames.isEmpty() || keepCount < 1) {
         return
     }
@@ -38,7 +39,8 @@ def pruneHarborUatTags(def script, String reg, String proj, List repoNames, int
         PROJ='${proj}'
         KEEP=${keepCount}
         PREFIX='${tagPrefix}'
-        CURRENT='${currentTag}'
+        CURRENT='${currentBuildTag}'
+        LATEST='${latestTag}'
         if ! command -v jq >/dev/null 2>&1; then
           echo '>>> Harbor prune skipped: jq not installed on Jenkins agent'
           exit 0
@@ -57,7 +59,7 @@ def pruneHarborUatTags(def script, String reg, String proj, List repoNames, int
           i=0
           while [ "\${i}" -lt "\${del_count}" ]; do
             t="\${tags[\$i]}"
-            if [ "\${t}" = "\${CURRENT}" ]; then
+            if [ "\${t}" = "\${CURRENT}" ] || [ "\${t}" = "\${LATEST}" ]; then
               i=\$((i + 1))
               continue
             fi
@@ -93,7 +95,7 @@ pipeline {
         booleanParam(
                 name: 'PUSH_TO_HARBOR',
                 defaultValue: true,
-                description: 'After Maven: docker build + push to Harbor (tag uat-build-<BUILD_NUMBER>). Uncheck for jar-only UAT deploy.'
+                description: 'After Maven: docker build + push to Harbor (tags uat-latest and uat-build-<N>). Uncheck for jar-only UAT deploy.'
         )
         choice(
                 name: 'HARBOR_PUSH_SCOPE',
@@ -114,7 +116,7 @@ pipeline {
         booleanParam(
                 name: 'HARBOR_PRUNE_OLD_TAGS',
                 defaultValue: true,
-                description: 'After push: delete old uat-build-* tags in Harbor, keep last N per repo (not base/*)'
+                description: 'After push: delete old uat-build-* tags in Harbor, keep last N per repo (never deletes uat-latest)'
         )
         string(name: 'HARBOR_KEEP_TAG_COUNT', defaultValue: '10', trim: true,
                 description: 'How many uat-build-* tags to keep per repository')
@@ -126,7 +128,8 @@ pipeline {
         GIT_URL = 'http://8.152.195.41:3000/alien/alien_cloud'
         GIT_CREDENTIALS = 'zhanghaomimapingzheng'
         HARBOR_CREDENTIALS = 'harbor-robot-alien'
-        UAT_HARBOR_IMAGE_TAG = "uat-build-${env.BUILD_NUMBER}"
+        UAT_HARBOR_LATEST_TAG = 'uat-latest'
+        UAT_HARBOR_BUILD_TAG = "uat-build-${env.BUILD_NUMBER}"
         DOCKERFILE_JAVA = 'docs/jenkins/produ/docker/Dockerfile.java-service'
     }
 
@@ -239,7 +242,8 @@ pipeline {
                 script {
                     def reg = params.HARBOR_REGISTRY.trim()
                     def proj = params.HARBOR_PROJECT.trim()
-                    def tag = env.UAT_HARBOR_IMAGE_TAG
+                    def latestTag = env.UAT_HARBOR_LATEST_TAG
+                    def buildTag = env.UAT_HARBOR_BUILD_TAG
                     def baseImage = "${reg}/${proj}/base/openjdk8-ffmpeg:v1"
                     def dockerfile = env.DOCKERFILE_JAVA
 
@@ -266,7 +270,8 @@ pipeline {
                         """
                         harborServices.each { svc ->
                             def jarName = "${svc.module}-1.0.0.jar"
-                            def imageRef = "${reg}/${proj}/${svc.repo}:${tag}"
+                            def imageLatest = "${reg}/${proj}/${svc.repo}:${latestTag}"
+                            def imageBuild = "${reg}/${proj}/${svc.repo}:${buildTag}"
                             sh """
                                 set -e
                                 test -f ${WORKSPACE}/${svc.module}/target/${jarName}
@@ -279,25 +284,31 @@ pipeline {
                                   touch .jenkins_docker_ctx/lib/.keep
                                 fi
                                 cd .jenkins_docker_ctx
+                                if docker pull ${imageLatest} 2>/dev/null; then
+                                  echo ">>> archive previous ${latestTag} -> ${buildTag}"
+                                  docker tag ${imageLatest} ${imageBuild}
+                                  docker push ${imageBuild}
+                                fi
                                 docker build -f ${WORKSPACE}/${dockerfile} \\
                                   --build-arg BASE_IMAGE=${baseImage} \\
                                   --build-arg JAR_FILE=${jarName} \\
                                   --build-arg SERVER_PORT=${svc.port} \\
                                   --build-arg WITH_LIB=${svc.withLib} \\
-                                  -t ${imageRef} .
-                                docker push ${imageRef}
-                                echo ">>> pushed ${imageRef}"
+                                  -t ${imageLatest} .
+                                docker push ${imageLatest}
+                                echo ">>> pushed ${imageLatest} (archived prior latest as ${buildTag} if any)"
                             """
                         }
                         if (params.HARBOR_PRUNE_OLD_TAGS == true) {
                             def keepN = (params.HARBOR_KEEP_TAG_COUNT ?: '10').trim() as int
                             pruneHarborUatTags(
                                 this, reg, proj, harborServices*.repo,
-                                keepN, 'uat-build-', tag,
+                                keepN, 'uat-build-', buildTag, latestTag,
                             )
                         }
                     }
-                    echo ">>> Harbor tag for prod promote: SOURCE_TAG=${tag}"
+                    echo ">>> Harbor latest: ${env.UAT_HARBOR_LATEST_TAG}; archived tag this run: ${env.UAT_HARBOR_BUILD_TAG}"
+                    echo ">>> Prod promote: SOURCE_TAG=${env.UAT_HARBOR_LATEST_TAG}"
                 }
             }
         }
@@ -361,8 +372,8 @@ pipeline {
         success {
             script {
                 if (params.PUSH_TO_HARBOR) {
-                    echo ">>> Harbor images tagged: ${env.UAT_HARBOR_IMAGE_TAG}"
-                    echo ">>> Prod promote: SOURCE_TAG=${env.UAT_HARBOR_IMAGE_TAG}"
+                    echo ">>> Harbor latest: ${env.UAT_HARBOR_LATEST_TAG}"
+                    echo ">>> Prod promote: SOURCE_TAG=${env.UAT_HARBOR_LATEST_TAG}"
                 }
             }
         }

+ 32 - 18
docs/jenkins/README-UAT-HARBOR-PUSH.md

@@ -3,10 +3,11 @@
 在现有 **UAT Maven + jar 部署** 流水线上增加可选阶段,把业务镜像推到:
 
 ```text
-39.105.153.68/alien_cloud/<服务名>:uat-build-<Jenkins构建号>
+39.105.153.68/alien_cloud/<服务名>:uat-latest          # 当前预生产最新
+39.105.153.68/alien_cloud/<服务名>:uat-build-<N>       # 被本次构建顶替的旧 uat-latest(归档)
 ```
 
-生产侧 **Gateway-K8s / Alien-Cloud-K8s-Whole** 使用同一 tag 作为 `SOURCE_TAG` 做晋升
+生产侧 **Gateway-K8s / Alien-Cloud-K8s-Whole** 推荐使用 **`SOURCE_TAG=uat-latest`** 做晋升;需要固定某一版快照时用 `uat-build-<N>`
 
 脚本:`docs/jenkins/Jenkinsfile-uat-build-deploy.groovy`
 
@@ -19,15 +20,24 @@ UAT Jenkins Job(88:30003)
   1. Checkout(拉 alien_cloud 预生产分支)
   2. Maven Build(mvn clean package)
   3. Push images to Harbor(PUSH_TO_HARBOR=true 时)
-       docker build → push 39.105.153.68/alien_cloud/gateway:uat-build-42
+       若已有 uat-latest:pull → 再打 tag uat-build-<本次构建号> → push
+       docker build → push ...:uat-latest
   4. Deploy Services(拷 jar 到 /app_deploy_uat + docker restart,与现网一致)
 
-Harbor Web(153.68)出现 gateway 仓库
+Harbor Web(153.68)gateway 仓库有 uat-latest + 若干 uat-build-*
 
 生产 Jenkins(同机,另一文件夹)
-  Gateway-K8s / Whole:SOURCE_TAG=uat-build-42 → produ-xxx → ACK
+  Gateway-K8s / Whole:SOURCE_TAG=uat-latest → produ-xxx → ACK
 ```
 
+**标签规则(以构建 #49 为例)**
+
+| 步骤 | 说明 |
+|------|------|
+| 推送前 | 若存在 `uat-latest`,将其归档为 `uat-build-49`(与本次 Jenkins 构建号一致) |
+| 推送后 | 新镜像仅打 `uat-latest` |
+| 生产晋升 | `SOURCE_TAG=uat-latest` 即「当前 UAT 最新」 |
+
 ---
 
 ## 二、一次性准备(运维 / Jenkins 管理员)
@@ -117,17 +127,16 @@ echo '<TOKEN>' | docker login 39.105.153.68 -u 'robot$alien_cloud+jenkins-k8s' -
 构建成功后日志末尾应有:
 
 ```text
->>> pushed 39.105.153.68/alien_cloud/gateway:uat-build-<N>
->>> Prod promote: SOURCE_TAG=uat-build-<N>
+>>> archive previous uat-latest -> uat-build-<N>   # 非首次构建才有
+>>> pushed 39.105.153.68/alien_cloud/gateway:uat-latest
+>>> Prod promote: SOURCE_TAG=uat-latest
 ```
 
-记下 **`<N>`** = Jenkins 构建号。
-
 ---
 
 ## 五、验证 Harbor
 
-浏览器打开:`http://39.105.153.68/harbor/` → 项目 **alien_cloud** → 镜像仓库应出现 **`gateway`**,标签 **`uat-build-<N>`**。
+浏览器打开:`http://39.105.153.68/harbor/` → 项目 **alien_cloud** → 镜像仓库应出现 **`gateway`**,标签 **`uat-latest`**,以及若干 **`uat-build-*`**。
 
 或命令行:
 
@@ -144,7 +153,7 @@ curl -s -u 'robot$alien_cloud+jenkins-k8s:<TOKEN>' \
 
 | 参数 | 值 |
 |------|-----|
-| `SOURCE_TAG` | `uat-build-<N>`(与 UAT 构建号一致) |
+| `SOURCE_TAG` | **`uat-latest`**(推荐);或指定历史 `uat-build-<N>` |
 | `DEPLOY_STRATEGY` | 先 `skip`(只晋升 Harbor),再 `rolling` |
 | `DEPLOY_MODE` | 单服务用 `single` + `gateway` |
 
@@ -156,17 +165,21 @@ curl -s -u 'robot$alien_cloud+jenkins-k8s:<TOKEN>' \
 |------|------|
 | `PUSH_TO_HARBOR` | 默认 **`true`**(推 Harbor);仅 jar 部署 UAT 时 **取消勾选** |
 | `HARBOR_PUSH_SCOPE` | 默认 **`all-java-services`**(七个);**`gateway-only`** 等只推一个;Maven 须对所选模块打出 jar |
-| `HARBOR_PRUNE_OLD_TAGS` | 默认 **true**:每个仓库只保留最近 **10** 个 `uat-build-*` tag,删更旧的(不删 `base/*`) |
-| `HARBOR_KEEP_TAG_COUNT` | 保留 tag 个数,默认 `10` |
+| `HARBOR_PRUNE_OLD_TAGS` | 默认 **true**:每个仓库只保留最近 **10** 个 `uat-build-*` tag,删更旧的(**不删 `uat-latest`**) |
+| `HARBOR_KEEP_TAG_COUNT` | 保留 `uat-build-*` 个数,默认 `10` |
 
 ### 旧镜像清理说明
 
-- 每次 push 的是**新 tag**(`uat-build-<构建号>`),Harbor **不会**自动删旧 tag
-- 脚本在 push 后调 Harbor API 删除最老的 `uat-build-*`,**保留最近 N 个**(含本次)
-- 机器人需有 **删除制品** 权限;若删除失败,日志会有 `WARN: delete failed`,可在 Harbor 项目里开「标记可删除」或使用项目 **标签保留策略**
+- 每次 push 更新 **`uat-latest`**;被顶替的旧 `uat-latest` 会归档为 **`uat-build-<本次 Jenkins 构建号>`**
+- 脚本在 push 后调 Harbor API 删除最老的 `uat-build-*`,**保留最近 N 个**;**永不删除 `uat-latest`**
+- 机器人需有 **删除制品** 权限;若删除失败,日志会有 `WARN: delete failed`。
 - **不会**删除 `base/openjdk8-ffmpeg` 等基础镜像。
 - Jenkins 本机 `docker images` 可用 `docker image prune` 另行清理,与 Harbor 无关。
-| `UAT_HARBOR_IMAGE_TAG` | 自动 `uat-build-${BUILD_NUMBER}`,无需手填 |
+
+| 环境变量 | 说明 |
+|----------|------|
+| `UAT_HARBOR_LATEST_TAG` | 固定 `uat-latest` |
+| `UAT_HARBOR_BUILD_TAG` | 本次归档名 `uat-build-${BUILD_NUMBER}`(仅在有旧 `uat-latest` 时 push) |
 
 ---
 
@@ -178,7 +191,8 @@ curl -s -u 'robot$alien_cloud+jenkins-k8s:<TOKEN>' \
 | `Login Succeeded` 后 push 失败 | 机器人是否有项目 push 权限 |
 | `x509` / 证书错误 | 88 上 `insecure-registries` 或 HTTPS + ca.crt |
 | Harbor 仍无 gateway | 是否勾选了 `PUSH_TO_HARBOR`;Maven 是否打出 `alien-gateway/target/*.jar` |
-| 生产 Whole 仍 not found | `SOURCE_TAG` 必须与 UAT 构建日志中的 `uat-build-<N>` 完全一致 |
+| 生产 Whole `uat-latest: not found` | 先跑一轮 UAT 推 Harbor;`SOURCE_TAG` 填 **`uat-latest`** |
+| 需要回滚到上一版 UAT | 在 Harbor 查 `uat-build-<N>`,生产 Job 填该 tag 作 `SOURCE_TAG` |
 
 ---
 

+ 1 - 1
docs/jenkins/produ/README-HARBOR-SETUP.md

@@ -89,7 +89,7 @@ Harbor Web → **alien_cloud** → 应看到 `base/openjdk8-ffmpeg`。
 
 ## 三.1、UAT 首次推送 gateway 镜像(方案 A)
 
-见 **[README-UAT-HARBOR-PUSH.md](../README-UAT-HARBOR-PUSH.md)**:在 UAT Job 勾选 `PUSH_GATEWAY_TO_HARBOR`,产出 `gateway:uat-build-<构建号>` 后,再跑生产晋升 Job
+见 **[README-UAT-HARBOR-PUSH.md](../README-UAT-HARBOR-PUSH.md)**:在 UAT Job 勾选 `PUSH_TO_HARBOR`,产出 `gateway:uat-latest` 后,生产晋升 Job 填 `SOURCE_TAG=uat-latest`
 
 ---
 

+ 1 - 1
docs/jenkins/produ/README-JOB-GATEWAY.md

@@ -50,7 +50,7 @@ Harbor / ACK 凭据不在 SCM 里配,在 Jenkins **凭据管理**:
 
 | 参数 | 示例 |
 |------|------|
-| `SOURCE_TAG` | `uat-build-42`(UAT 已推到 Harbor 的 tag) |
+| `SOURCE_TAG` | `uat-latest`(推荐)或 `uat-build-<N>` |
 | `TARGET_TAG` | 留空 → `produ-<构建号>` |
 | `DEPLOY_STRATEGY` | 先试 **`skip`**(只晋升 Harbor);确认后再 `rolling` |
 | `DRY_RUN` | 第一次可勾,只看计划 |

+ 1 - 1
docs/jenkins/produ/README-JOB-WHOLE.md

@@ -65,7 +65,7 @@ Deploy to ACK   → DEPLOY_STRATEGY≠skip 且非 DRY_RUN 时 kubectl set image
 
 | 参数 | 说明 |
 |------|------|
-| `SOURCE_TAG` | UAT 已在 Harbor 的 tag,如 `uat-build-42` |
+| `SOURCE_TAG` | UAT 已在 Harbor 的 tag,推荐 `uat-latest`;历史 `uat-build-<N>` |
 | `TARGET_TAG` | 留空 → `produ-<构建号>`;七个服务打**同一**生产 tag |
 | `DEPLOY_STRATEGY` | `skip` 只推 Harbor;`rolling` 滚更 ACK;`canary` 灰度 |
 | `DRY_RUN` | 只 Plan,不 pull/push |

+ 3 - 3
docs/jenkins/produ/README-PROMOTE-IMAGE.md

@@ -41,7 +41,7 @@ Harbor 机器人在 Jenkins **凭据管理**里单独建 **Username with passwor
 | 参数 | 说明 |
 |------|------|
 | `DEPLOY_MODE` | `whole` / `single` / `multi` |
-| `SOURCE_TAG` | 预生产镜像在 Harbor 上的 tag,如 `uat-build-42` |
+| `SOURCE_TAG` | 预生产镜像 tag,推荐 `uat-latest`;历史快照 `uat-build-<N>` |
 | `TARGET_TAG` | 生产 tag,默认 `produ-${BUILD_NUMBER}` |
 | `HARBOR_REGISTRY` | `39.105.153.68` |
 | `HARBOR_PROJECT` | `alien_cloud` |
@@ -54,7 +54,7 @@ Harbor 机器人在 Jenkins **凭据管理**里单独建 **Username with passwor
 
 现网 **88 上 UAT** 若只打 jar 到 `/alien_uat/java`、**未**推 Harbor,需先有一次:
 
-- UAT 构建后 `docker build` + `push` 到 `39.105.153.68/alien_cloud/<服务>:uat-build-<号>`,或  
+- UAT 构建后 `push` 到 `39.105.153.68/alien_cloud/<服务>:uat-latest`(旧 latest 归档为 `uat-build-<号>`,或  
 - 在 153.68 上从现网 jar 打镜像 push(一次性迁移)
 
 之后本 Job 只做 **tag 晋升**,不再拉 Git 代码。
@@ -63,4 +63,4 @@ Harbor 机器人在 Jenkins **凭据管理**里单独建 **Username with passwor
 
 单服务 Job(如 **Gateway-K8s**)与 **promote-image** 均为仅晋升镜像;界面配置见 [README-JOB-GATEWAY.md](./README-JOB-GATEWAY.md)。
 
-生产发版推荐:**UAT 构建推 `uat-build-*` → Gateway-K8s / promote-image 晋升 → ACK**。
+生产发版推荐:**UAT 推 `uat-latest` → Gateway-K8s / promote-image(`SOURCE_TAG=uat-latest`)→ ACK**。

+ 1 - 4
docs/jenkins/produ/_shared/k8s-produ-lib.groovy

@@ -10,10 +10,7 @@ def resolveTargetTag(def script, String targetTagParam) {
 def requireSourceTag(def script, String sourceTag) {
     def srcTag = (sourceTag ?: '').trim()
     if (!srcTag) {
-        script.error('SOURCE_TAG is required (e.g. uat-build-42). Check Harbor for an existing tag.')
-    }
-    if (srcTag == 'uat-latest') {
-        script.echo 'WARNING: SOURCE_TAG=uat-latest is usually not in Harbor; use the real UAT build tag.'
+        script.error('SOURCE_TAG is required (e.g. uat-latest or uat-build-42). Check Harbor for an existing tag.')
     }
     return srcTag
 }

+ 1 - 1
docs/jenkins/produ/gateway/Jenkinsfile

@@ -30,7 +30,7 @@ pipeline {
     }
     parameters {
         string(name: 'SOURCE_TAG', defaultValue: '', trim: true,
-            description: '必填:Harbor 已有 UAT tag,如 uat-build-42')
+            description: '必填:Harbor UAT tag,推荐 uat-latest;历史可用 uat-build-<N>')
         string(name: 'TARGET_TAG', defaultValue: '', trim: true,
             description: '留空则 produ-${BUILD_NUMBER}')
         string(name: 'HARBOR_REGISTRY', defaultValue: '39.105.153.68', trim: true)

+ 1 - 1
docs/jenkins/produ/whole/Jenkinsfile

@@ -48,7 +48,7 @@ pipeline {
         booleanParam(name: 'MULTI_job', defaultValue: false)
         booleanParam(name: 'MULTI_dining', defaultValue: false)
         string(name: 'SOURCE_TAG', defaultValue: '', trim: true,
-            description: '必填:Harbor 上已存在的 UAT tag,如 uat-build-42(勿用 uat-latest)')
+            description: '必填:Harbor UAT tag,推荐 uat-latest;历史快照可用 uat-build-<N>')
         string(name: 'TARGET_TAG', defaultValue: '', trim: true,
             description: '留空则 produ-${BUILD_NUMBER}')
         string(name: 'HARBOR_REGISTRY', defaultValue: '39.105.153.68', trim: true)