pipeline { agent any options { // 构建记录保留策略 buildDiscarder(logRotator( artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '2', numToKeepStr: '2' )) // 防止并发构建冲突 disableConcurrentBuilds() // 设置构建超时时间(30分钟) timeout(time: 30, unit: 'MINUTES') } // 定义构建参数 parameters { string( name: 'PROFILES', defaultValue: getDefaultProfile(), // 根据分支自动设置默认值 description: '编译环境参数(dev/test/prod)', trim: true ) } stages { // 阶段1:环境配置和参数设置 stage('Setup Parameters & ENV') { steps { // 从Jenkins配置管理获取配置文件 configFileProvider([configFile(fileId: 'xiaomayi-web', variable: 'settingsFile')]) { script { setupEnvironment() // 调用环境设置函数 } } } } // 阶段2:代码编译构建 stage('Build') { agent { label { label "${env.JENKINS_AGENT}" // 使用动态指定的Jenkins agent } } steps { // 使用指定的Maven配置进行构建 configFileProvider([configFile(fileId: "${env.MAVEN_SET}", variable: 'MAVEN_SETTINGS_XML')]) { sh """ # 使用Maven进行依赖清理和项目构建 /usr/local/maven/bin/mvn --settings ${MAVEN_SETTINGS_XML} \ dependency:purge-local-repository -Dinclude=com.xiaomayi \ -f pom.xml clean package -P${params.PROFILES} \ -Dmaven.test.skip=true """ // 验证构建产物 sh "ls -lsh ${env.JAR_FILE_PATH}/${env.JAR_FILE}" sh "md5sum ${env.JAR_FILE_PATH}/${env.JAR_FILE}" } } post { always { // 归档构建产物以便后续使用和审计 archiveArtifacts artifacts: "${env.JAR_FILE_PATH}/${env.JAR_FILE}", fingerprint: true } } } // 阶段3:Docker镜像构建和推送 stage('Container Build') { agent { label { label "${env.JENKINS_AGENT}" } } steps { script { buildAndPushDockerImage() // 调用镜像构建函数 } } post { always { cleanDockerImages() // 清理本地Docker镜像节省空间 } } } // 阶段4:部署到目标服务器 stage('Deploy') { agent { label { label "${env.JENKINS_AGENT}" } } steps { script { deployToServer() // 调用部署函数 } } } } // 构建后处理 post { success { echo "✅ Pipeline执行成功 - 分支: ${env.BRANCH_NAME} - 构建ID: ${env.BUILD_ID} - 环境: ${params.PROFILES}" } failure { echo "❌ Pipeline执行失败 - 分支: ${env.BRANCH_NAME} - 构建ID: ${env.BUILD_ID}" // 此处可以添加邮件通知、钉钉通知等 } aborted { echo "⚠️ Pipeline被中止 - 分支: ${env.BRANCH_NAME} - 构建ID: ${env.BUILD_ID}" } cleanup { cleanWs() // 清理工作空间,释放磁盘空间 } } } /** * 根据当前分支获取默认的Profile参数 * @return 对应的环境参数(dev/test/prod) */ def getDefaultProfile() { def branch = env.BRANCH_NAME ?: 'dev' switch(branch) { case 'dev': return 'dev' case 'test': return 'test' case 'master': return 'prod' default: return 'dev' // 默认使用dev环境 } } /** * 设置构建环境变量和配置参数 * 从配置文件中读取分支和服务的具体配置 */ def setupEnvironment() { // 读取JSON配置文件 def config = readJSON file: "${settingsFile}" // 解析任务名称(处理多级目录结构) def jobNameStr = env.JOB_NAME.tokenize('/') def jobName = jobNameStr[0] // 获取分支配置和服务配置 def branchConfig = config.branchConfig."${env.BRANCH_NAME}" def serviceConfig = config.serviceConfig."${jobName}" // 验证配置是否存在 if (!branchConfig || !serviceConfig) { error("❌ 无法获取分支 ${env.BRANCH_NAME} 或服务 ${jobName} 的配置") } // 设置分支相关环境变量 env.MAVEN_SET = branchConfig.MAVEN_SET env.REGISTRY = branchConfig.registry env.REGISTRY_CREDENTIAL = branchConfig.registryCredential env.NAMESPACE = branchConfig.namespace env.JENKINS_AGENT = branchConfig.jenkinsAgent env.SERVER_PORT = branchConfig.serverPort // 设置服务相关环境变量 env.PROJECT_NAME = serviceConfig.containerName env.SERVICE_PATH = serviceConfig.servicePath env.JAR_PACKAGE_NAME = serviceConfig.jarPackageName env.BASE_IMAGE = "${env.REGISTRY}/xiaomayi-base/jdk:17.0.16-rocky8-dos" env.PORT = serviceConfig.port env.JAR_FILE = "${env.JAR_PACKAGE_NAME}" env.JAR_FILE_PATH = "${env.SERVICE_PATH}/target" env.SERVER_HOST_01 = serviceConfig.serverHost01 // 根据分支设置服务器IP地址 if (['dev', 'test', 'master'].contains(env.BRANCH_NAME)) { env.SERVER_IP_01 = branchConfig."${env.SERVER_HOST_01}" if (!env.SERVER_IP_01) { error("❌ 无法获取服务器IP地址配置: ${env.SERVER_HOST_01}") } } else { error("❌ 不支持的分支: ${env.BRANCH_NAME}") } // 打印环境配置信息用于调试和验证 echo """ 📋 ============ 环境配置信息 ============ 🔹 分支: ${env.BRANCH_NAME} 🔹 项目: ${jobName} 🔹 环境参数: ${params.PROFILES} 🔹 Maven配置: ${env.MAVEN_SET} 🔹 镜像仓库: ${env.REGISTRY} 🔹 命名空间: ${env.NAMESPACE} 🔹 项目名称: ${env.PROJECT_NAME} 🔹 JAR文件: ${env.JAR_FILE} 🔹 目标服务器: ${env.SERVER_IP_01}:${env.SERVER_PORT} 🔹 Jenkins Agent: ${env.JENKINS_AGENT} ==================================== """ } /** * 构建并推送Docker镜像到镜像仓库 */ def buildAndPushDockerImage() { // 打印镜像构建参数 echo """ 🐳 ============ 镜像构建参数 ============ 🔹 基础镜像: ${env.BASE_IMAGE} 🔹 暴露端口: ${env.PORT} 🔹 JAR文件: ${env.JAR_FILE} 🔹 JAR文件路径: ${env.JAR_FILE_PATH} 🔹 镜像标签: ${env.NAMESPACE}/${env.PROJECT_NAME}:${params.PROFILES}-${env.BUILD_ID} ==================================== """ // 使用Docker凭证连接到镜像仓库 docker.withRegistry("https://${env.REGISTRY}", env.REGISTRY_CREDENTIAL) { def dockerImage = docker.build( "${env.NAMESPACE}/${env.PROJECT_NAME}:${params.PROFILES}-${env.BUILD_ID}", // 构建参数传递 "--build-arg VAR_PROFILES=${params.PROFILES} " + "--build-arg VAR_BASE_IMAGE=${env.BASE_IMAGE} " + "--build-arg VAR_PORT=${env.PORT} " + "--build-arg VAR_JARFILE=${env.JAR_FILE} " + "--build-arg VAR_JARFILE_PATH=${env.JAR_FILE_PATH} " + "-f .jenkinsfile/Dockerfile ./" // 指定Dockerfile路径 ) // 推送镜像到仓库 dockerImage.push() echo "✅ Docker镜像推送成功: ${env.NAMESPACE}/${env.PROJECT_NAME}:${params.PROFILES}-${env.BUILD_ID}" } } /** * 清理本地Docker镜像,释放磁盘空间 */ def cleanDockerImages() { echo "🧹 开始清理本地Docker镜像..." try { // 删除本地构建的镜像 sh """ docker rmi -f ${env.NAMESPACE}/${env.PROJECT_NAME}:${params.PROFILES}-${env.BUILD_ID} || true docker rmi -f ${env.REGISTRY}/${env.NAMESPACE}/${env.PROJECT_NAME}:${params.PROFILES}-${env.BUILD_ID} || true """ // 清理悬空镜像(不再被任何容器引用的镜像) sh "docker image prune -f || true" echo "✅ Docker镜像清理完成" } catch (Exception e) { echo "⚠️ 镜像清理过程中出现警告: ${e.message}" // 镜像清理失败不影响主要流程,继续执行 } } /** * 部署应用到目标服务器 * 通过SSH连接到服务器执行部署脚本 */ def deployToServer() { // 构建部署命令 def deployCmd = """ ssh -o StrictHostKeyChecking=no \ -o ConnectTimeout=30 \ -o ServerAliveInterval=60 \ esxi@${env.SERVER_IP_01} -p ${env.SERVER_PORT} \ 'cd /usr/local/docker/xiaomayi-web/; ./deploy.sh deploy ${env.PROJECT_NAME} ${params.PROFILES}-${env.BUILD_ID}' """ echo """ 🚀 ============ 开始部署 ============ 🔹 目标服务器: ${env.SERVER_IP_01}:${env.SERVER_PORT} 🔹 服务名称: ${env.PROJECT_NAME} 🔹 镜像版本: ${params.PROFILES}-${env.BUILD_ID} ==================================== """ echo "执行部署命令: ${deployCmd}" // 部署过程添加重试机制和超时控制 try { retry(3) { // 最多重试3次 timeout(time: 10, unit: 'MINUTES') { // 部署超时时间10分钟 sh deployCmd } } echo "✅ 部署成功完成" } catch (Exception e) { error("❌ 部署失败: ${e.message}") } } /** * 验证必要环境变量是否设置(可选,可用于前置检查) */ def validateEnvironment() { def requiredEnvVars = [ 'BRANCH_NAME', 'MAVEN_SET', 'REGISTRY', 'REGISTRY_CREDENTIAL', 'NAMESPACE', 'JENKINS_AGENT', 'PROJECT_NAME', 'SERVER_IP_01' ] def missingVars = [] requiredEnvVars.each { var -> if (!env."${var}") { missingVars.add(var) } } if (missingVars) { error("❌ 缺少必要环境变量: ${missingVars.join(', ')}") } }