|
@@ -1,17 +1,20 @@
|
|
|
/**
|
|
/**
|
|
|
- * 预生产(UAT):Checkout → Maven 打包 → 将 jar/lib 拷到 UAT 部署目录并 docker restart。
|
|
|
|
|
|
|
+ * UAT: Checkout -> Maven -> (optional) push images to Harbor -> deploy jar + docker restart.
|
|
|
*
|
|
*
|
|
|
- * Jenkins Job:Pipeline script from SCM 时 Script Path 填 docs/jenkins/Jenkinsfile-uat-build-deploy.groovy
|
|
|
|
|
|
|
+ * Jenkins Job: Pipeline script from SCM
|
|
|
|
|
+ * Script Path: docs/jenkins/Jenkinsfile-uat-build-deploy.groovy
|
|
|
*
|
|
*
|
|
|
- * 构建分支:在「Build with Parameters」中填写 GIT_BRANCH,默认 uat-20260202;须与 Gitea 远端分支名完全一致(连字符/下划线不要混用)。
|
|
|
|
|
|
|
+ * 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>.
|
|
|
*/
|
|
*/
|
|
|
pipeline {
|
|
pipeline {
|
|
|
agent any
|
|
agent any
|
|
|
|
|
|
|
|
options {
|
|
options {
|
|
|
- buildDiscarder(logRotator(numToKeepStr: '2', artifactNumToKeepStr: '2'))
|
|
|
|
|
|
|
+ buildDiscarder(logRotator(numToKeepStr: '15'))
|
|
|
timestamps()
|
|
timestamps()
|
|
|
- timeout(time: 60, unit: 'MINUTES')
|
|
|
|
|
|
|
+ timeout(time: 90, unit: 'MINUTES')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
parameters {
|
|
parameters {
|
|
@@ -19,18 +22,32 @@ pipeline {
|
|
|
name: 'GIT_BRANCH',
|
|
name: 'GIT_BRANCH',
|
|
|
defaultValue: 'uat-20260202',
|
|
defaultValue: 'uat-20260202',
|
|
|
trim: true,
|
|
trim: true,
|
|
|
- description: '要构建的 Git 分支名,须与远端一致,例如 uat-20260202、main'
|
|
|
|
|
|
|
+ description: 'Git branch, must match remote (e.g. uat-20260202)'
|
|
|
)
|
|
)
|
|
|
- booleanParam(name: 'FORCE_UPDATE', defaultValue: true, description: '是否强制更新依赖(mvn -U)')
|
|
|
|
|
- booleanParam(name: 'ALLOW_SNAPSHOTS', defaultValue: true, description: '是否允许 SNAPSHOT 依赖')
|
|
|
|
|
|
|
+ booleanParam(name: 'FORCE_UPDATE', defaultValue: true, description: 'mvn -U')
|
|
|
|
|
+ booleanParam(name: 'ALLOW_SNAPSHOTS', defaultValue: true, description: 'allow SNAPSHOT deps')
|
|
|
|
|
+ booleanParam(
|
|
|
|
|
+ name: 'PUSH_TO_HARBOR',
|
|
|
|
|
+ defaultValue: false,
|
|
|
|
|
+ description: 'After Maven: docker build + push to 39.105.153.68/alien_cloud (tag uat-build-<BUILD_NUMBER>)'
|
|
|
|
|
+ )
|
|
|
|
|
+ choice(
|
|
|
|
|
+ name: 'HARBOR_PUSH_SCOPE',
|
|
|
|
|
+ choices: ['gateway-only', 'all-java-services'],
|
|
|
|
|
+ description: 'Only used when PUSH_TO_HARBOR=true'
|
|
|
|
|
+ )
|
|
|
|
|
+ string(name: 'HARBOR_REGISTRY', defaultValue: '39.105.153.68', trim: true)
|
|
|
|
|
+ string(name: 'HARBOR_PROJECT', defaultValue: 'alien_cloud', trim: true)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
environment {
|
|
environment {
|
|
|
MAVEN_HOME = tool '3.6.3'
|
|
MAVEN_HOME = tool '3.6.3'
|
|
|
PATH = "${MAVEN_HOME}/bin:${env.PATH}"
|
|
PATH = "${MAVEN_HOME}/bin:${env.PATH}"
|
|
|
-
|
|
|
|
|
GIT_URL = 'http://8.152.195.41:3000/alien/alien_cloud'
|
|
GIT_URL = 'http://8.152.195.41:3000/alien/alien_cloud'
|
|
|
GIT_CREDENTIALS = 'zhanghaomimapingzheng'
|
|
GIT_CREDENTIALS = 'zhanghaomimapingzheng'
|
|
|
|
|
+ HARBOR_CREDENTIALS = 'harbor-robot-alien'
|
|
|
|
|
+ UAT_HARBOR_IMAGE_TAG = "uat-build-${env.BUILD_NUMBER}"
|
|
|
|
|
+ DOCKERFILE_JAVA = 'docs/jenkins/produ/docker/Dockerfile.java-service'
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
stages {
|
|
stages {
|
|
@@ -39,10 +56,10 @@ pipeline {
|
|
|
script {
|
|
script {
|
|
|
def branch = (params.GIT_BRANCH ?: 'uat-20260202').trim()
|
|
def branch = (params.GIT_BRANCH ?: 'uat-20260202').trim()
|
|
|
if (!branch) {
|
|
if (!branch) {
|
|
|
- error('GIT_BRANCH 不能为空')
|
|
|
|
|
|
|
+ error('GIT_BRANCH is required')
|
|
|
}
|
|
}
|
|
|
env.GIT_BRANCH = branch
|
|
env.GIT_BRANCH = branch
|
|
|
- echo ">>> 正在拉取代码... 分支: ${env.GIT_BRANCH}"
|
|
|
|
|
|
|
+ echo ">>> Checkout branch: ${env.GIT_BRANCH}"
|
|
|
git branch: "${env.GIT_BRANCH}",
|
|
git branch: "${env.GIT_BRANCH}",
|
|
|
credentialsId: "${env.GIT_CREDENTIALS}",
|
|
credentialsId: "${env.GIT_CREDENTIALS}",
|
|
|
url: "${env.GIT_URL}"
|
|
url: "${env.GIT_URL}"
|
|
@@ -50,9 +67,7 @@ pipeline {
|
|
|
set -e
|
|
set -e
|
|
|
git fetch origin
|
|
git fetch origin
|
|
|
git reset --hard origin/${env.GIT_BRANCH}
|
|
git reset --hard origin/${env.GIT_BRANCH}
|
|
|
- echo ">>> 当前构建使用的提交:"
|
|
|
|
|
git log -1 --oneline
|
|
git log -1 --oneline
|
|
|
- git rev-parse HEAD
|
|
|
|
|
"""
|
|
"""
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -112,7 +127,6 @@ pipeline {
|
|
|
</settings>
|
|
</settings>
|
|
|
"""
|
|
"""
|
|
|
}
|
|
}
|
|
|
- echo ">>> 已生成 settings.xml(包含 Spring 官方仓库)"
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -120,26 +134,16 @@ pipeline {
|
|
|
steps {
|
|
steps {
|
|
|
script {
|
|
script {
|
|
|
def updateFlag = params.FORCE_UPDATE ? '-U' : ''
|
|
def updateFlag = params.FORCE_UPDATE ? '-U' : ''
|
|
|
- echo ">>> 开始 Maven 打包(FORCE_UPDATE=${params.FORCE_UPDATE})"
|
|
|
|
|
-
|
|
|
|
|
retry(2) {
|
|
retry(2) {
|
|
|
sh """
|
|
sh """
|
|
|
set -e
|
|
set -e
|
|
|
mvn -version
|
|
mvn -version
|
|
|
-
|
|
|
|
|
- echo ">>> [1/3] 清理代理环境变量 (防止 HTTP 劫持)..."
|
|
|
|
|
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY all_proxy no_proxy NO_PROXY || true
|
|
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY all_proxy no_proxy NO_PROXY || true
|
|
|
-
|
|
|
|
|
- echo ">>> [2/3] 启用 SSL 证书绕过 (防止证书不匹配)..."
|
|
|
|
|
export MAVEN_OPTS="-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true"
|
|
export MAVEN_OPTS="-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true"
|
|
|
-
|
|
|
|
|
- echo ">>> [3/3] 清理本地仓库缓存 (防止 404 缓存)..."
|
|
|
|
|
rm -rf /root/.m2/repository/org/springframework/cloud/spring-cloud-dependencies/Hoxton.SR1 || true
|
|
rm -rf /root/.m2/repository/org/springframework/cloud/spring-cloud-dependencies/Hoxton.SR1 || true
|
|
|
rm -rf /root/.m2/repository/org/springframework/boot/spring-boot-dependencies/2.3.2.RELEASE || true
|
|
rm -rf /root/.m2/repository/org/springframework/boot/spring-boot-dependencies/2.3.2.RELEASE || true
|
|
|
rm -rf ${WORKSPACE}/.m2/repository/org/springframework/cloud/spring-cloud-dependencies/Hoxton.SR1 || true
|
|
rm -rf ${WORKSPACE}/.m2/repository/org/springframework/cloud/spring-cloud-dependencies/Hoxton.SR1 || true
|
|
|
rm -rf ${WORKSPACE}/.m2/repository/org/springframework/boot/spring-boot-dependencies/2.3.2.RELEASE || true
|
|
rm -rf ${WORKSPACE}/.m2/repository/org/springframework/boot/spring-boot-dependencies/2.3.2.RELEASE || true
|
|
|
-
|
|
|
|
|
- echo ">>> 执行 Maven 打包..."
|
|
|
|
|
mvn clean package -DskipTests -s settings.xml ${updateFlag} -e -Dmaven.repo.local=${WORKSPACE}/.m2/repository
|
|
mvn clean package -DskipTests -s settings.xml ${updateFlag} -e -Dmaven.repo.local=${WORKSPACE}/.m2/repository
|
|
|
"""
|
|
"""
|
|
|
}
|
|
}
|
|
@@ -147,47 +151,108 @@ pipeline {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ stage('Push images to Harbor') {
|
|
|
|
|
+ when { expression { return params.PUSH_TO_HARBOR == true } }
|
|
|
|
|
+ steps {
|
|
|
|
|
+ script {
|
|
|
|
|
+ def reg = params.HARBOR_REGISTRY.trim()
|
|
|
|
|
+ def proj = params.HARBOR_PROJECT.trim()
|
|
|
|
|
+ def tag = env.UAT_HARBOR_IMAGE_TAG
|
|
|
|
|
+ def baseImage = "${reg}/${proj}/base/openjdk8-ffmpeg:v1"
|
|
|
|
|
+ def dockerfile = env.DOCKERFILE_JAVA
|
|
|
|
|
+
|
|
|
|
|
+ def harborServices = [
|
|
|
|
|
+ [module: 'alien-gateway', repo: 'gateway', port: '8000', withLib: false],
|
|
|
|
|
+ [module: 'alien-store', repo: 'store', port: '50014', withLib: true],
|
|
|
|
|
+ [module: 'alien-second', repo: 'second', port: '50015', withLib: false],
|
|
|
|
|
+ [module: 'alien-store-platform', repo: 'store-platform', port: '50016', withLib: false],
|
|
|
|
|
+ [module: 'alien-lawyer', repo: 'lawyer', port: '50017', withLib: true],
|
|
|
|
|
+ [module: 'alien-job', repo: 'job', port: '50108', withLib: false],
|
|
|
|
|
+ [module: 'alien-dining', repo: 'dining', port: '50019', withLib: false],
|
|
|
|
|
+ ]
|
|
|
|
|
+ if (params.HARBOR_PUSH_SCOPE == 'gateway-only') {
|
|
|
|
|
+ harborServices = harborServices.findAll { it.repo == 'gateway' }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ withCredentials([usernamePassword(
|
|
|
|
|
+ credentialsId: env.HARBOR_CREDENTIALS,
|
|
|
|
|
+ usernameVariable: 'HARBOR_USER',
|
|
|
|
|
+ passwordVariable: 'HARBOR_PASS',
|
|
|
|
|
+ )]) {
|
|
|
|
|
+ sh """
|
|
|
|
|
+ set -e
|
|
|
|
|
+ echo "\${HARBOR_PASS}" | docker login ${reg} -u "\${HARBOR_USER}" --password-stdin
|
|
|
|
|
+ """
|
|
|
|
|
+ harborServices.each { svc ->
|
|
|
|
|
+ def jarName = "${svc.module}-1.0.0.jar"
|
|
|
|
|
+ def imageRef = "${reg}/${proj}/${svc.repo}:${tag}"
|
|
|
|
|
+ sh """
|
|
|
|
|
+ set -e
|
|
|
|
|
+ test -f ${WORKSPACE}/${svc.module}/target/${jarName}
|
|
|
|
|
+ cd ${WORKSPACE}/${svc.module}
|
|
|
|
|
+ rm -rf .jenkins_docker_ctx && mkdir -p .jenkins_docker_ctx/lib
|
|
|
|
|
+ cp -f target/${jarName} .jenkins_docker_ctx/${jarName}
|
|
|
|
|
+ if [ -d target/lib ]; then
|
|
|
|
|
+ cp -rf target/lib/. .jenkins_docker_ctx/lib/
|
|
|
|
|
+ else
|
|
|
|
|
+ touch .jenkins_docker_ctx/lib/.keep
|
|
|
|
|
+ fi
|
|
|
|
|
+ cd .jenkins_docker_ctx
|
|
|
|
|
+ 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}"
|
|
|
|
|
+ """
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ echo ">>> Harbor tag for prod promote: SOURCE_TAG=${tag}"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
stage('Deploy Services') {
|
|
stage('Deploy Services') {
|
|
|
steps {
|
|
steps {
|
|
|
script {
|
|
script {
|
|
|
def services = [
|
|
def services = [
|
|
|
- "alien-gateway:gateway-uat",
|
|
|
|
|
- "alien-job:job-uat",
|
|
|
|
|
- "alien-lawyer:lawyer-uat",
|
|
|
|
|
- "alien-second:second-uat",
|
|
|
|
|
- "alien-store:store-uat",
|
|
|
|
|
- "alien-dining:dining-uat",
|
|
|
|
|
- "alien-store-platform:store-platform-uat"
|
|
|
|
|
|
|
+ 'alien-gateway:gateway-uat',
|
|
|
|
|
+ 'alien-job:job-uat',
|
|
|
|
|
+ 'alien-lawyer:lawyer-uat',
|
|
|
|
|
+ 'alien-second:second-uat',
|
|
|
|
|
+ 'alien-store:store-uat',
|
|
|
|
|
+ 'alien-dining:dining-uat',
|
|
|
|
|
+ 'alien-store-platform:store-platform-uat',
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
for (item in services) {
|
|
for (item in services) {
|
|
|
- def (moduleName, dirName) = item.split(':')
|
|
|
|
|
|
|
+ def parts = item.split(':')
|
|
|
|
|
+ def moduleName = parts[0]
|
|
|
|
|
+ def dirName = parts[1]
|
|
|
def sourceJar = "${env.WORKSPACE}/${moduleName}/target/${moduleName}-1.0.0.jar"
|
|
def sourceJar = "${env.WORKSPACE}/${moduleName}/target/${moduleName}-1.0.0.jar"
|
|
|
def sourceLib = "${env.WORKSPACE}/${moduleName}/target/lib"
|
|
def sourceLib = "${env.WORKSPACE}/${moduleName}/target/lib"
|
|
|
def targetDir = "/app_deploy_uat/${dirName}"
|
|
def targetDir = "/app_deploy_uat/${dirName}"
|
|
|
|
|
|
|
|
sh """
|
|
sh """
|
|
|
set -e
|
|
set -e
|
|
|
- echo ">>> 正在处理模块: ${moduleName}"
|
|
|
|
|
-
|
|
|
|
|
|
|
+ echo ">>> Deploy module: ${moduleName}"
|
|
|
if [ -f "${sourceJar}" ]; then
|
|
if [ -f "${sourceJar}" ]; then
|
|
|
mkdir -p "${targetDir}"
|
|
mkdir -p "${targetDir}"
|
|
|
-
|
|
|
|
|
if [ -d "${sourceLib}" ]; then
|
|
if [ -d "${sourceLib}" ]; then
|
|
|
rm -rf "${targetDir}/lib"
|
|
rm -rf "${targetDir}/lib"
|
|
|
cp -rf "${sourceLib}" "${targetDir}"
|
|
cp -rf "${sourceLib}" "${targetDir}"
|
|
|
fi
|
|
fi
|
|
|
-
|
|
|
|
|
cp -f "${sourceJar}" "${targetDir}/"
|
|
cp -f "${sourceJar}" "${targetDir}/"
|
|
|
-
|
|
|
|
|
if docker ps -a --format '{{.Names}}' | grep -wq "${dirName}"; then
|
|
if docker ps -a --format '{{.Names}}' | grep -wq "${dirName}"; then
|
|
|
docker restart "${dirName}"
|
|
docker restart "${dirName}"
|
|
|
- echo ">>> [${dirName}] 重启成功"
|
|
|
|
|
|
|
+ echo ">>> [${dirName}] restarted"
|
|
|
else
|
|
else
|
|
|
- echo ">>> [${dirName}] 容器不存在,仅完成文件拷贝"
|
|
|
|
|
|
|
+ echo ">>> [${dirName}] container missing, jar copied only"
|
|
|
fi
|
|
fi
|
|
|
else
|
|
else
|
|
|
- echo ">>> [${dirName}] 未发现 Jar 包,跳过"
|
|
|
|
|
|
|
+ echo ">>> [${dirName}] jar missing, skip"
|
|
|
fi
|
|
fi
|
|
|
"""
|
|
"""
|
|
|
}
|
|
}
|
|
@@ -198,14 +263,15 @@ pipeline {
|
|
|
|
|
|
|
|
post {
|
|
post {
|
|
|
always {
|
|
always {
|
|
|
- echo ">>> 构建任务结束"
|
|
|
|
|
- sh "rm -f settings.xml || true"
|
|
|
|
|
|
|
+ sh 'rm -f settings.xml || true'
|
|
|
}
|
|
}
|
|
|
success {
|
|
success {
|
|
|
- echo ">>> 流水线执行成功"
|
|
|
|
|
- }
|
|
|
|
|
- failure {
|
|
|
|
|
- echo ">>> 流水线执行失败,请检查 Maven 日志中是否仍有 Download 失败"
|
|
|
|
|
|
|
+ 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}"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|