Jenkins流水線共享庫

小强找BUG發表於2024-09-03

絕大部份專案的構建流程是:拉取原始碼---執行單元測試---構建目標包---構建映象---推送映象---叢集拉取映象部署 ,此指令碼為Jenkins流水線共享庫(Jenkins pipline shared library),將所有步驟統一定義到此指令碼中,所有專案引用共享庫即可,支援多分支構建,不同的分支釋出到不同的環境。引用共享庫之後,就只需要在專案的Jenkinsfile中,定義各自專案的引數即可,避免了每個專案都編寫大量高度重複的構建指令碼:

#!groovy
library 'pipeline-shared-library'
    def map = [:]
    map.put('repoBranch',env.BRANCH_NAME)
    map.put('repoUrl','http://gitlab.balabala.com/development/balabala.git')
    map.put('appName','demo-app')
    map.put('k8sSvcName','kubernetes-service-name')
    map.put('tag','v1.0.1')
    map.put('k8sResourceType','Deployment')
    map.put('runUnitTest','0')
    map.put('credentialsId','3818ec5a-b476-4471-8c47-db36ed4d5eb0')
    map.put('proRegistryAddr','127.0.0.1:8888/registry')
    map.put('fatRegistryAddr','registry.cn-hangzhou.aliyuncs.com/app_k8s')
    map.put('multibrachComposeName','demo-app-multi_master')
    map.put('pubRepoUrl','https://nexus.balabala.com/repository/maven-releases/')
    map.put('pubRepoUrl','https://nexus.balabala.com/repository/maven-snapshots/')
    map.put('gradleConfigFileName','build.gradle')
    if(env.BRANCH_NAME == 'master') {
        map.put('k8sNamespace','pro')
        map.put('multibrachComposeName', 'demo-multi_master')
        map.put('buildJar','demo-service-1.0.0-RELEASE.jar')
    }
    if(env.BRANCH_NAME == 'feature/demo'){
        map.put('k8sNamespace','fat')
        map.put('multibrachComposeName', 'demo-multipipeline_feature_demo')
        map.put('buildJar','demo-service-1.0.0-SNAPSHOT.jar')
    }

ci("gradle",map)

#!groovy

def call(String type, Map map) {
    if (type == "gradle") {
        pipeline {
            agent any
            //triggers {
            //    parameterizedCron(env.BRANCH_NAME != 'master' ? '''H/1 * * * * % ABC=XYZ''' : '')
            //}
            parameters {
                choice(
                        name: 'env',
                        choices: ['fat', 'uat', 'pro'],
                        description: 'fat:測試環境部署\nuat:演示環境部署\npro:生產環境部署'
                )
                string(name: 'repoBranch', defaultValue: "${map.repoBranch}", description: 'git分支名稱')
                string(name: 'repoUrl', defaultValue: "${map.repoUrl}", description: '專案倉庫的地址')
                string(name: 'appName', defaultValue: "${map.appName}", description: '應用的名稱,打包Docker映象時以此命名')
                string(name: 'k8sSvcName', defaultValue: "${map.k8sSvcName}", description: 'Kubernetes服務的名稱,不要超過24個字元(實際使用時根據Kubernetes服務名稱的規定)')
                string(name: 'tag', defaultValue: "${map.tag}", description: '版本標籤,映象標籤')
                string(name: 'k8sResourceType', defaultValue: "${map.k8sResourceType}", description: 'Kubernetes資源型別,如Deployment、StatefulSet等等')
                string(name: 'runUnitTest', defaultValue: "${map.runUnitTest}", description: '是否執行單元測試')
                string(name: 'k8sNamespace', defaultValue: "${map.k8sNamespace}", description: 'Kubernetes名稱空間')
                string(name: 'credentialsId', defaultValue: "${map.credentialsId}", description: 'Jenkins認證憑據ID,用於獲取原始碼')
                string(name: 'fatRegistryAddr', defaultValue: "${map.fatRegistryAddr}", description: 'FAT環境註冊地址')
                string(name: 'multibrachComposeName', defaultValue: "${map.multibrachComposeName}", description: '' +
                        '多分支構建時,分支組合名稱,例如專案的名字是dolphin,有一個hotfix分支,在多分支構建時,傳入Jenkins自動生成的名稱dolphin_hotfix')
                string(name: 'pubRepoUrl', defaultValue: "${map.pubRepoUrl}", description: 'Jar包釋出的倉庫地址')
                string(name: 'buildJar', defaultValue: "${map.buildJar}", description: '構建目標Jar包名稱')
            }
            tools {
                gradle "Gradle"
            }
            environment {
                GRADLE_HOME = "${tool 'Gradle'}"
                PATH = "${env.GRADLE_HOME}/bin:${env.PATH}"
                repoUrl = "${map.repoUrl}"
                registryAddr = getRegistryAddr("${params.env}" == null ? "fat" : "${params.env}", map)
                k8sResourceType = getKubernetesResourceType("${params.k8sResourceType}")
            }

            stages {
                stage('checkout-source') {
                    steps {
                        git branch: "${params.repoBranch}",
                                credentialsId: "${params.credentialsId}",
                                url: "${params.repoUrl}"
                    }
                }

                stage('unit-test') {
                    when {
                        expression {
                            "${params.runUnitTest}" == '1'
                        }
                    }
                    steps {
                        sh "./gradlew test"
                    }
                }

                stage('build-api') {
                    steps {
                        script {
                            try {
                                sh "./gradlew :${params.multibrachComposeName == null ? params.appName : params.multibrachComposeName}:${params.appName}-api:build publishMavenPublicationToMavenRepository -x test"
                            } catch (err) {
                                echo "Publish jar failed, but will be continue," + err.getMessage()
                            }
                        }
                    }
                }

                stage('build') {
                    steps {
                        sh "./gradlew :${params.multibrachComposeName == null ? params.appName : params.multibrachComposeName}:${params.appName}-service:build -x test"
                    }
                }

                stage('prune-image'){
                    steps{
                        sh "docker system prune"
                    }
                }

                stage('package-image') {
                    steps {
                        sh "docker build -f ./Dockerfile --build-arg buildJar=\"${params.buildJar}\" -t=\"${params.appName}:${params.tag}\" ."
                    }
                }

                stage('tag-image') {
                    steps {
                        sh "docker tag ${params.appName}:${params.tag} ${registryAddr}/${params.appName}:${params.tag}"
                    }
                }

                stage('push-image') {
                    steps {
                        sh "docker push ${registryAddr}/${params.appName}:${params.tag}"
                    }
                }

                stage('rolling-update-fat') {
                    when {
                        expression {
                            "${params.env}" == 'fat'
                        }
                    }
                    steps {
                        sh "kubectl rollout restart ${k8sResourceType} ${k8sSvcName} -n ${params.k8sNamespace}"
                    }
                }

                stage('rolling-update-uat') {
                    when {
                        expression {
                            "${params.env}" == 'uat'
                        }
                    }
                    steps {
                        sh "kubectl rollout restart ${k8sResourceType} ${k8sSvcName} -n ${params.k8sNamespace}"
                    }
                }

                stage('rolling-update-pro') {
                    when {
                        expression {
                            "${params.env}" == 'pro'
                        }
                    }
                    steps {
                        sh "/Users/dabaidabai/.jenkins/workspace/build_shell/update-production-pod.sh ${params.tag} ${k8sSvcName} ${params.k8sNamespace} ${params.appName} ${k8sResourceType}"
                    }
                }
            }
        }
    }
}

/**
 * 獲取不同部署環境的容器推送地址
 *
 * @param env
 * @param map
 * @return
 */
def getRegistryAddr(env, Map map) {
    print("choice:" + env)
    if ("pro" == env) {
        return "${map.proRegistryAddr}"
    }
    if ("fat" == env) {
        print("fataddress:" + "${map.fatRegistryAddr}")
        return "${map.fatRegistryAddr}"
    }
    if ("uat" == env) {
        return "${map.uatRegistryAddr}"
    }
}

/**
 * 獲取Kubernetes資源型別
 * @param value
 * @return
 */
def getKubernetesResourceType(value) {
    return value == null ? "Deployment" : value
}

相關文章