Files
jenkins-pipeline/SCM/部署镜像/DM_s2_lessie_go_api.groovy
dxin 8cadbf8ba9 +
2025-11-15 18:18:21 +08:00

233 lines
9.4 KiB
Groovy
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

pipeline {
agent any
parameters {
booleanParam(
name: 'DEPLOY_AFTER_BUILD',
defaultValue: false,
description: '是否快速回滚上一个版本?'
)
imageTag(
name: 'IMAGE_NAME',
description: '此处是 sit 镜像仓库内的 go 服务镜像',
registry: 'https://uswccr.ccs.tencentyun.com',
image: 'lessiesit/go_lessie-sourcing-api',
credentialId: 'dxin_img_hub_auth',
filter: '.*',
defaultTag: '',
verifySsl: true
)
}
environment {
KUBECONFIG = credentials('k8s-test-config-admin') // k8s 凭证 ID, Jenkins 中配置的凭证名称
Deployment_yaml = "/opt-config/lessie-ai/s2/s2-lessie-go-api.yaml"
Deployment_name = "s2-lessie-go-api-deployment"
K8s_namespace = "sit"
Pod_container_name = "s2-lessie-go-api"
}
stages {
stage('快速回滚上一版本') {
when {
expression { return params.DEPLOY_AFTER_BUILD == true }
}
steps {
script {
sh """
echo "=== 开始回滚到上一个版本 ==="
kubectl rollout undo deployment/${Deployment_name} -n ${K8s_namespace}
echo "=== 回滚中... ==="
kubectl rollout status deployment/${Deployment_name} -n ${K8s_namespace} --timeout=180s
echo "=== 查看所使用的镜像 ==="
kubectl get deployment ${Deployment_name} -n ${K8s_namespace} -o=jsonpath='{.spec.template.spec.containers[*].image}'
echo "=== 回滚完成 ==="
"""
}
}
}
stage('拉取yaml') {
when {
expression { return params.DEPLOY_AFTER_BUILD == false }
}
steps {
git branch: "opt",
credentialsId: 'fly_gitlab_auth',
url: 'http://106.53.194.199/opt/opt-config.git'
}
}
stage('修改YAML镜像') {
when {
expression { return params.DEPLOY_AFTER_BUILD == false }
}
steps {
script {
echo "=== 所选择镜像 tag: ${params.IMAGE_NAME} ==="
sh """
echo "=== 修改 Deployment YAML 中的镜像版本 ==="
sed -i 's#image:.*#image: ${params.IMAGE_NAME}#' ${Deployment_yaml}
"""
}
}
}
stage('部署到k8s') {
when {
expression { return params.DEPLOY_AFTER_BUILD == false }
}
steps {
script {
sh """
kubectl apply -f ${Deployment_yaml} -n ${K8s_namespace}
kubectl rollout status deployment/${Deployment_name} -n ${K8s_namespace} --timeout=180s
"""
}
}
}
stage('获取信息') {
steps {
script {
}
}
}
stage('部署到K8S') {
when {
expression { return params.DEPLOY_AFTER_BUILD }
}
steps {
sh """
echo "=== 更新 Deployment 镜像 ==="
kubectl set image deployment/${Deployment_name} ${Pod_container_name}=${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG} -n ${K8s_namespace}
echo "=== 添加注解 ==="
kubectl annotate deployment/${Deployment_name} kubernetes.io/change-cause="${GIT_COMMIT_MSG}" --overwrite -n ${K8s_namespace}
echo "=== 查看历史版本 ==="
kubectl rollout history deployment/${Deployment_name} -n ${K8s_namespace}
echo "=== 查看所使用的镜像 ==="
kubectl get deployment ${Deployment_name} -n ${K8s_namespace} -o=jsonpath='{.spec.template.spec.containers[*].image}'
"""
}
}
stage('检查部署情况') {
when {
expression { return params.DEPLOY_AFTER_BUILD }
}
steps {
echo "检测部署状态并验证新版本运行情况"
sh """
echo "=== 检查 Deployment 滚动更新状态 ==="
kubectl rollout status deployment/${Deployment_name} -n ${K8s_namespace} --timeout=180s
if [ \$? -ne 0 ]; then
echo "❌ 部署超时或失败,开始收集诊断信息..."
echo "=== 查看当前 Pods 状态 ==="
kubectl get pods -l app=${Pod_container_name} -n ${K8s_namespace} -o wide
echo "=== 查看最近的事件 ==="
kubectl get events -n ${K8s_namespace} --sort-by=.metadata.creationTimestamp | tail -n 20
echo "=== 查看最近一个失败 Pod 的详细描述 ==="
FAILED_POD=\$(kubectl get pods -l app=${Pod_container_name} -n ${K8s_namespace} --field-selector=status.phase!=Running -o jsonpath='{.items[0].metadata.name}')
if [ ! -z "\$FAILED_POD" ]; then
kubectl describe pod \$FAILED_POD -n ${K8s_namespace} || true
kubectl logs \$FAILED_POD -n ${K8s_namespace} --tail=50 || true
fi
echo "=== 回滚到上一个版本 ==="
kubectl rollout undo deployment/${Deployment_name} -n ${K8s_namespace}
exit 1
fi
echo "=== 检查 Pods 是否全部 Ready ==="
kubectl get pods -l app=${Pod_container_name} -n ${K8s_namespace} -o wide
echo "=== 获取最新 Pod 名称 ==="
NEW_POD=\$(kubectl get pods -l app=${Pod_container_name} -n ${K8s_namespace} --sort-by=.metadata.creationTimestamp -o jsonpath='{.items[-1].metadata.name}')
echo "=== 新 Pod 启动日志(最近20行) ==="
kubectl logs \$NEW_POD -n ${K8s_namespace} --tail=20 || true
echo "✅ 部署成功:\$NEW_POD 已正常运行"
"""
}
}
}
post {
always {
script {
def keepCount = 2
echo "开始清理本地旧镜像,仅保留最近 ${keepCount} 个构建版本"
def imagePrefix = "${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}"
// 获取所有镜像(按创建时间排序,越新的越前)
// 格式Repository:Tag ImageID CreatedAt
def allImagesRaw = sh(script: "docker images ${imagePrefix} --format '{{.Repository}}:{{.Tag}} {{.ID}} {{.CreatedAt}}' | sort -rk3", returnStdout: true).trim()
if (!allImagesRaw) {
echo "未找到任何镜像,无需清理"
return
}
def allImages = allImagesRaw.split('\n')
if (allImages.size() <= keepCount) {
echo "当前镜像数未超过 ${keepCount} 个,无需清理"
return
}
def oldImages = allImages.drop(keepCount)
echo "发现 ${oldImages.size()} 个旧镜像需要清理"
oldImages.each { line ->
echo " ${line}"
}
oldImages.each { line ->
def parts = line.split(' ')
def imageTag = parts[0]
def imageId = parts.size() > 1 ? parts[1] : ""
// 对于标签为<none>的无效镜像使用镜像ID删除
if (imageTag.contains("<none>") && imageId) {
echo "删除无效镜像: ${imageId}"
sh(returnStatus: true, script: "docker rmi -f ${imageId} || true")
} else if (imageId) {
// 对于有标签的有效镜像优先使用镜像ID删除
echo "删除旧镜像: ${imageTag} (${imageId})"
sh(returnStatus: true, script: "docker rmi -f ${imageId} || true")
} else {
// 兜底方案,使用标签删除
echo "删除旧镜像: ${imageTag}"
sh(returnStatus: true, script: "docker rmi -f ${imageTag} || true")
}
}
echo "清理完成,当前镜像状态:"
sh """
docker images ${imagePrefix} --format 'table {{.Repository}}\\t{{.Tag}}\\t{{.CreatedAt}}\\t{{.Size}}'
"""
sh "docker logout ${REGISTRY}"
echo "容器仓库已登出,本地凭证已清理"
}
}
success {
// 输出构建结果
echo "成功!"
echo "镜像地址:${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG}"
echo "对应代码提交:${GIT_COMMIT_SHORT}${GIT_COMMIT_MSG}"
}
failure {
// 输出构建结果
echo "有步骤失败,请检查!"
}
}
}