// ============================================ // AIOT Platform - Jenkins Pipeline // 智能增量构建 + Docker 容器化部署 // ============================================ pipeline { agent any options { // 保留最近 10 次构建 buildDiscarder(logRotator(numToKeepStr: '10')) // 禁止并发构建 disableConcurrentBuilds() // 超时设置 timeout(time: 60, unit: 'MINUTES') } environment { // Gitea 仓库配置 GIT_REPO = 'http://172.17.16.14:3000/XW-AIOT/aiot-platform-cloud.git' // Docker Registry 配置 REGISTRY = 'localhost:5000' // Maven 配置 MAVEN_OPTS = '-Xmx2048m -Dmaven.repo.local=.m2/repository' // 镜像标签 IMAGE_TAG = "${env.BRANCH_NAME}-${env.BUILD_NUMBER}-${env.GIT_COMMIT?.take(8)}" // 服务列表(核心服务 - 不包括开发中的 ops-server) CORE_SERVICES = 'viewsh-gateway,viewsh-module-system-server,viewsh-module-infra-server,viewsh-module-iot-server,viewsh-module-iot-gateway' } stages { stage('Checkout') { steps { script { echo "=== 检出代码 ===" checkout scm // 获取 Git 提交信息 env.GIT_COMMIT_MSG = sh( script: 'git log -1 --pretty=%B', returnStdout: true ).trim() echo "Commit: ${env.GIT_COMMIT}" echo "Message: ${env.GIT_COMMIT_MSG}" } } } stage('Detect Changes') { steps { script { echo "=== 检测变更的服务 ===" // 获取变更的文件列表 def changedFiles = sh( script: ''' # 获取上一次成功构建的提交 PREV_COMMIT=$(git rev-parse HEAD~1 2>/dev/null || echo "") if [ -z "$PREV_COMMIT" ]; then # 首次构建或只有一个提交,构建所有核心服务 echo "all" else # 检测变更的文件 git diff --name-only $PREV_COMMIT HEAD fi ''', returnStdout: true ).trim() echo "Changed files:\n${changedFiles}" // 分析需要构建的服务 def servicesToBuild = [] if (changedFiles == 'all' || changedFiles.isEmpty()) { // 首次构建或强制全量构建 echo "首次构建或无法检测变更,构建所有核心服务" servicesToBuild = CORE_SERVICES.split(',') } else { // 检测每个服务是否有变更 CORE_SERVICES.split(',').each { service -> def modulePath = service.replace('-server', '').replace('viewsh-module-', 'viewsh-module-').replace('viewsh-', '') if (changedFiles.contains(modulePath) || changedFiles.contains('pom.xml') || changedFiles.contains('viewsh-framework') || changedFiles.contains('viewsh-dependencies') || changedFiles.contains('Jenkinsfile') || changedFiles.contains('docker/')) { servicesToBuild.add(service) } } // 如果没有检测到变更,但有代码提交,构建所有服务 if (servicesToBuild.isEmpty() && !changedFiles.isEmpty()) { echo "检测到代码变更但未匹配到具体服务,构建所有服务" servicesToBuild = CORE_SERVICES.split(',') } } env.SERVICES_TO_BUILD = servicesToBuild.join(',') echo "Services to build: ${env.SERVICES_TO_BUILD}" if (servicesToBuild.isEmpty()) { echo "No services need to be built. Skipping build." currentBuild.result = 'SUCCESS' error("No changes detected, skipping build") } } } } stage('Docker Build & Push') { when { expression { env.SERVICES_TO_BUILD != '' } } steps { script { echo "=== Docker 镜像构建与推送 ===" echo "使用 Docker 多阶段构建(包含 Maven 编译)" def services = env.SERVICES_TO_BUILD.split(',') // 串行构建,避免内存溢出 services.each { service -> def modulePath = getModulePath(service) def jarName = service echo "=========================================" echo "构建服务: ${service}" echo "模块路径: ${modulePath}" echo "=========================================" try { // Docker 多阶段构建(包含 Maven 编译和镜像打包) sh """ docker build \ -f docker/Dockerfile.template \ --build-arg MODULE_NAME=${modulePath} \ --build-arg JAR_NAME=${jarName} \ --build-arg SKIP_TESTS=true \ -t ${REGISTRY}/${service}:${IMAGE_TAG} \ -t ${REGISTRY}/${service}:latest \ . """ echo "推送镜像: ${service}" sh """ docker push ${REGISTRY}/${service}:${IMAGE_TAG} docker push ${REGISTRY}/${service}:latest """ echo "✓ ${service} 构建成功" } catch (Exception e) { echo "✗ ${service} 构建失败: ${e.message}" throw e } } // 清理悬空镜像 echo "清理悬空镜像..." sh "docker image prune -f || true" } } } stage('Deploy') { when { expression { env.SERVICES_TO_BUILD != '' && env.BRANCH_NAME == 'master' } } steps { script { echo "=== 部署到生产环境 ===" def services = env.SERVICES_TO_BUILD.split(',') services.each { service -> echo "Deploying ${service}..." // 通过 SSH 在宿主机上执行部署命令 // Jenkins 容器网络: 1panel-network, Gateway: 172.19.0.1 sh """ ssh -o StrictHostKeyChecking=no root@172.19.0.1 ' cd /opt/aiot-platform-cloud docker compose -f docker-compose.core.yml pull ${service} docker compose -f docker-compose.core.yml up -d ${service} ' """ // 等待服务健康检查 echo "Waiting for ${service} to be healthy..." sh """ ssh -o StrictHostKeyChecking=no root@172.19.0.1 ' timeout 120 sh -c "until docker inspect --format=\\"{{.State.Health.Status}}\\" aiot-${service} 2>/dev/null | grep -q healthy; do sleep 5; done" || true ' """ } echo "Deployment completed!" } } } } post { success { echo "=== 构建成功 ===" echo "Built services: ${env.SERVICES_TO_BUILD}" echo "Image tag: ${IMAGE_TAG}" } failure { echo "=== 构建失败 ===" echo "Please check the logs for details." } always { // 清理工作空间(可选) // cleanWs() // 显示磁盘使用情况 sh 'df -h' sh 'docker system df' } } } // ============================================ // 辅助函数 // ============================================ def getModulePath(String service) { // 根据服务名获取 Maven 模块路径 def moduleMap = [ 'viewsh-gateway': 'viewsh-gateway', 'viewsh-module-system-server': 'viewsh-module-system/viewsh-module-system-server', 'viewsh-module-infra-server': 'viewsh-module-infra/viewsh-module-infra-server', 'viewsh-module-iot-server': 'viewsh-module-iot/viewsh-module-iot-server', 'viewsh-module-iot-gateway': 'viewsh-module-iot/viewsh-module-iot-gateway' // viewsh-module-ops-server 暂未合并到 master,待开发完成后添加 ] return moduleMap[service] ?: service }