pipeline { agent any environment { // GitLab配置 GITLAB_URL = 'https://gitlab.xpaas.lenovo.com' GITLAB_REPO = 'artificial-intelligence-platform/lenovo-ipc' GITLAB_CREDENTIALS_ID = 'git-ipc' // 镜像仓库配置 (10.128.62.130:8843) REGISTRY_URL = '10.128.62.130:8843' REGISTRY_CREDENTIALS_ID = 'docker-registry-130' // 镜像配置 IMAGE_NAME = 'more_dots' FULL_IMAGE_NAME = "${REGISTRY_URL}/${IMAGE_NAME}" // 是否跳过构建(运行时赋值) SKIP_BUILD = 'false' K8S_NAMESPACE = 'more-dots' } parameters { choice(name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: '选择部署环境') choice(name: 'TARGET_CLUSTER', choices: ['cluster1', 'cluster2', 'both'], description: '选择目标集群') } stages { stage('Checkout') { steps { git( url: "${GITLAB_URL}/${GITLAB_REPO}.git", credentialsId: GITLAB_CREDENTIALS_ID, branch: 'master' ) script { env.GIT_COMMIT = sh(script: 'git rev-parse HEAD', returnStdout: true).trim() env.SOURCE_TREE = sh(script: 'git rev-parse HEAD:more_dots', returnStdout: true).trim() env.IMAGE_TAG = env.SOURCE_TREE.take(12) echo "GIT_COMMIT: ${env.GIT_COMMIT}" echo "SOURCE_TREE: ${env.SOURCE_TREE}" echo "IMAGE_TAG: ${env.IMAGE_TAG}" echo "FULL_IMAGE_NAME: ${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" } } } stage('Check Code Changes') { steps { script { def prev = env.GIT_PREVIOUS_SUCCESSFUL_COMMIT ?: '' if (!prev?.trim()) { echo "未找到上次成功构建提交,默认执行构建" env.SKIP_BUILD = 'false' } else { int rc = sh( script: "git diff --quiet ${prev} HEAD -- more_dots", returnStatus: true ) env.SKIP_BUILD = (rc == 0) ? 'true' : 'false' } echo "代码变更检查结果: SKIP_BUILD=${env.SKIP_BUILD}" } } } stage('Build Docker Image') { when { expression { env.SKIP_BUILD != 'true' } } steps { dir('more_dots') { sh """ docker build --progress=plain \ --build-arg PIP_OPTIONS="--no-hash-check" \ -t ${IMAGE_NAME}:${env.IMAGE_TAG} . """ } } } stage('Push to Registry') { when { expression { env.SKIP_BUILD != 'true' } } steps { script { withCredentials([usernamePassword( credentialsId: REGISTRY_CREDENTIALS_ID, usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASS' )]) { sh """ set -eux echo "登录到镜像仓库 ${REGISTRY_URL}..." echo "${REGISTRY_PASS}" | docker login ${REGISTRY_URL} -u ${REGISTRY_USER} --password-stdin """ } sh """ set -eux echo "打标签: ${IMAGE_NAME}:${IMAGE_TAG} -> ${FULL_IMAGE_NAME}:${IMAGE_TAG}" docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${FULL_IMAGE_NAME}:${IMAGE_TAG} echo "推送镜像到仓库..." docker push ${FULL_IMAGE_NAME}:${IMAGE_TAG} echo "镜像推送完成: ${FULL_IMAGE_NAME}:${IMAGE_TAG}" """ } } } stage('Deploy to k3s') { steps { script { // 检查 k8s 配置文件是否存在 if (!fileExists('more_dots/k8s/deployment.yaml')) { error "错误: more_dots/k8s/deployment.yaml 文件不存在于代码仓库中" } def fullImageWithTag = "${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" def cluster = params.TARGET_CLUSTER if (cluster == 'cluster1' || cluster == 'both') { deployToCluster('k3s-cluster1-config', fullImageWithTag, params.DEPLOY_ENV) } if (cluster == 'cluster2' || cluster == 'both') { deployToCluster('k3s-cluster2-config', fullImageWithTag, params.DEPLOY_ENV) } } } } } post { always { script { sh """ docker logout ${REGISTRY_URL} || true docker rmi ${FULL_IMAGE_NAME}:${env.IMAGE_TAG} || true """ } cleanWs() echo "构建结束。镜像标签: ${env.IMAGE_TAG}" echo "完整镜像: ${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" echo "是否跳过构建: ${env.SKIP_BUILD}" echo "部署环境: ${params.DEPLOY_ENV}" echo "目标集群: ${params.TARGET_CLUSTER}" } failure { echo "构建失败,请检查日志" } } } // 部署函数 def deployToCluster(String clusterConfigId, String fullImageWithTag, String deployEnv) { withCredentials([ file(credentialsId: clusterConfigId, variable: 'KUBECONFIG'), usernamePassword(credentialsId: REGISTRY_CREDENTIALS_ID, usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASS') ]) { sh """ set -eux # 查找kubectl路径 KUBECTL_PATH=\$(command -v kubectl 2>/dev/null || true) if [ -z "\$KUBECTL_PATH" ]; then for p in /usr/local/bin/kubectl /usr/bin/kubectl /bin/kubectl; do if [ -x "\$p" ]; then KUBECTL_PATH="\$p" break fi done fi if [ -z "\$KUBECTL_PATH" ]; then echo "kubectl 未找到,请检查 Jenkins 节点环境" exit 1 fi echo "使用kubectl路径: \$KUBECTL_PATH" echo "部署到集群: ${clusterConfigId}" echo "部署环境: ${deployEnv}" echo "镜像: ${fullImageWithTag}" echo "命名空间: ${K8S_NAMESPACE}" # 定义kubectl函数 k() { sudo \$KUBECTL_PATH --kubeconfig=${KUBECONFIG} "\$@" } # 检查命名空间 k get namespace ${K8S_NAMESPACE} || k create namespace ${K8S_NAMESPACE} # 创建imagePullSecret k create secret docker-registry regcred-130 \\ --docker-server=${REGISTRY_URL} \\ --docker-username=${REGISTRY_USER} \\ --docker-password=${REGISTRY_PASS} \\ --namespace=${K8S_NAMESPACE} \\ --dry-run=client -o yaml | k apply -f - # 替换镜像标签和环境变量并部署 sed -e "s|image:.*more_dots:.*|image: ${fullImageWithTag}|g" \\ -e "s|value: \".*\"|value: \"${deployEnv}\"|g" \\ more_dots/k8s/deployment.yaml > /tmp/deployment-${K8S_NAMESPACE}.yaml echo "部署配置:" cat /tmp/deployment-${K8S_NAMESPACE}.yaml # 应用配置到 more-dots 命名空间 k apply -f /tmp/deployment-${K8S_NAMESPACE}.yaml -n ${K8S_NAMESPACE} # 等待部署完成 echo "等待部署完成..." k rollout status deployment/more-dots -n ${K8S_NAMESPACE} --timeout=300s # 显示部署状态 echo "部署完成,查看pod状态:" k get pods -n ${K8S_NAMESPACE} -l app=more-dots """ } }