1. 程式人生 > 其它 >jenkins流水線,實現多臺伺服器批量釋出、回滾

jenkins流水線,實現多臺伺服器批量釋出、回滾

/* 
1、指令碼中儘量使用雙引號,單引號中使用變數會出問題
2、遠端執行shell指令碼中的內部的“$”符號需要斜槓轉義,包括變數和正則表示式的使用,流水線中的全域性變數則不需要轉義直接使用
3、遠端執行shell指令碼說明
    釋出:
        1)使用“Publish over SSH”外掛上傳jar包到伺服器
        2)修改jar檔名稱,在名稱後面加上構建時間,最終jar檔名稱類似gateway-1.0.7.22020914.jar,jar檔名新增時間這步也可以由maven實現
        3)生成軟連線
        4)nohup啟動java程式
        5)輸出20s日誌
    回滾:
        1)停止程序
        2)軟連線指向回滾版本的jar檔案
        3)啟動java程式
        4)輸出20s日誌
*/
pipeline {
    agent any
    environment {
        /* 
        BUILD_TIMESTAMP 構建時間,由 Build Timestamp外掛提供,這裡在全域性配置格式改成了yyMMddHHmm,也可以使用groovy的TimeZone.getTimeZone("Asia/Shanghai")函式實現

        */
        PROJECT_NAME = "golife"    // 專案名稱
        SERVICE_NAME= "member"     // 服務名稱
        BRANCH_NAME = "master"       // gitlab分支
        GIT_PATH = "GITURL"        // 專案URL
        GIT_AUTH_ID = "git憑證id"    // git憑證id
        GIT_BRANCH = "master"   // git分支

    }

    // maven工具,在系統管理-全域性工具配置-Maven,如果沒有新增一個即可,這裡的“maven3.6.3”為新增mavne的“name”
    tools {
        maven "maven" 
    }

    options {
        timestamps()    //設定在專案列印日誌時帶上對應時間
        disableConcurrentBuilds()   //不允許同時執行流水線,被用來防止同時訪問共享資源等
        timeout(time: 5, unit: "MINUTES")   // 設定流水線執行超過n分鐘,Jenkins將中止流水線
        buildDiscarder(logRotator(numToKeepStr: "10"))   // 表示保留n次構建歷史
    }

    //引數化構建過程,可在流水線語法http://{JENKINS URL}/job/piptt/pipeline-syntax/中選擇“properties: Set job properties”生成流水線
    parameters{
        // 釋出選項--選項引數
        choice(
            choices: ['deploy', 'rollback','start','restart','stop'], 
            description: '''釋出選項:
釋出:deploy
回滾:rollback
啟動:start
重啟:restart
停止:stop
''', 
            name: 'ACTION'
        )
        // 要執行的伺服器--多選框引數(需安裝外掛Extended Choice Parameter)
        extendedChoice(
            description: '選擇需要執行的伺服器',  
            multiSelectDelimiter: ',', 
            name: 'Release_servers', 
            quoteValue: false, 
            saveJSONParameterToFile: false, 
            type: 'PT_CHECKBOX', 
            value: '192.168.1.100,192.168.1.101,192.168.1.102,192.168.1.103',   // Publish over SSH外掛新增的伺服器名,安裝好外掛後再系統管理-系統配置-找到“Publish over SSH”新增伺服器
            visibleItemCount: 10
        )
        // 釋出版本號--字串引數
        string(
            defaultValue: '1.0.7', 
            description: '''釋出版本號,僅釋出操作需要填寫。
該版本號為maven打包後jar包名稱的版本號,如gateway-1.0.7,填寫 1.0.7''', 
            name: 'RELEASE_VERSION', 
            trim: true
        )
        // 回滾版本號--字串引數
        string(
            description: '''回滾版本號,僅回滾操作需要填寫  
可在構建歷史日誌中,搜尋“RELEASE VERION”找到,格式為:1.0.7.22010456''', 
            name: 'BACK_VERSION', 
            trim: true
        )
    }

    stages {
        stage("列印資訊") {      //列印資訊
            steps {
                echo "列印資訊"
                echo "jenkins任務名: ${JOB_NAME}"
                echo "專案名: ${PROJECT_NAME}"
                echo "服務名:${SERVICE_NAME}"
                echo "執行動作: ${ACTION}"
                echo "gitlab分支名: ${BRANCH_NAME}"
                echo "build_id: ${BUILD_ID}"
                echo "工作空間: ${WORKSPACE}"
                echo "釋出伺服器: ${Release_servers}"
           }
        }

        stage("拉取程式碼") {
            //  僅當${ACTION}=="deploy"時,再執行此stage,詳情檢視官網when指令https://www.jenkins.io/zh/doc/book/pipeline/syntax/#when
            when {
                environment name:"ACTION", value: "deploy"
            }
            // 流水線語法中選擇“checkout: Check out from version control”生成
            steps {
                script {
                    checkout([
                        $class: "GitSCM",
                        branches: [[name: "${GIT_BRANCH}"]],
                        doGenerateSubmoduleConfigurations: false,
                        extensions: [],
                        submoduleCfg: [],
                        userRemoteConfigs: [[credentialsId: "${GIT_AUTH_ID}", url: "${GIT_PATH}"]]
                    ])
                }
            }
        }

        stage("maven構建") {
            when {
                environment name:"ACTION", value: "deploy"
            }

            steps {
                sh "mvn clean install -f ./pom.xml"
            }
        }

        stage("釋出") {
            /*
            when {
                environment name:"ACTION", value: "rollback"
                not {
                    environment name:"Release_servers", value:""
                }
            }
            這裡的when指令可以多用一個not來判斷構建的時候是否有選擇釋出的伺服器,為了直觀的看到我這裡在scritp裡面判斷了下,如果沒有選擇伺服器則輸出“沒有可用於執行的伺服器”
            */
            when {
                environment name:"ACTION", value: "deploy"
            }
            steps {
                script {
                    if (Release_servers.length() == 0) {
                        println("沒有可用於執行的伺服器")
                    } else {
                        for ( ip in Release_servers.tokenize(",")) {
                            sshPublisher (
                                publishers: [
                                    sshPublisherDesc (
                                    configName: "${ip}", 
                                    transfers: [
                                        sshTransfer (
                                        cleanRemote: false, 
                                        excludes: "", 
                                        execCommand: 
                                        """ 
                                            echo  "###########################################################################################################################################################################################################################"
                                            mkdir  /var/log/${PROJECT_NAME}/${SERVICE_NAME} -p
                                            mkdir  /opt/${PROJECT_NAME}/link-jar/ -p
                                            SERVICE_PID=`pgrep -f "java.*${SERVICE_NAME}{0,20}\$"`  # 服務執行pid
                
                                            mv /opt/${PROJECT_NAME}/jar/${SERVICE_NAME}/${SERVICE_NAME}-${RELEASE_VERSION}.jar /opt/${PROJECT_NAME}/jar/${SERVICE_NAME}/${SERVICE_NAME}-${RELEASE_VERSION}.${BUILD_TIMESTAMP}.jar 
                                            if [ \$? != "0" ]
                                            then
                                                echo "${ip}上找不到版本號為${RELEASE_VERSION}的${SERVICE_NAME},請檢查後重新構建"
                                                exit 145
                                            else
                                                echo   "${ip}:開始部署${SERVICE_NAME}"
                                                ln -snf  /opt/${PROJECT_NAME}/jar/${SERVICE_NAME}/${SERVICE_NAME}-${RELEASE_VERSION}.${BUILD_TIMESTAMP}.jar   /opt/${PROJECT_NAME}/link-jar/${PROJECT_NAME}-${SERVICE_NAME} 
                                                kill -9 "\${SERVICE_PID}" 
                                                nohup java -jar  /opt/${PROJECT_NAME}/link-jar/${PROJECT_NAME}-${SERVICE_NAME} > /var/log/${PROJECT_NAME}/${SERVICE_NAME}/${SERVICE_NAME}-${BUILD_TIMESTAMP}.log 2>&1 &
                                                echo -e "\n啟動日誌將持續輸出20s時間,如果沒有輸出日誌,則表示釋出失敗\n"
                                                timeout 20 tail -f  /var/log/${PROJECT_NAME}/${SERVICE_NAME}/${SERVICE_NAME}-${BUILD_TIMESTAMP}.log
                                                sleep 1
                                                echo "< RELEASE VERION: ${RELEASE_VERSION}.${BUILD_TIMESTAMP} >"
                                            fi
                                        """,
                                        execTimeout: 120000, 
                                        flatten: false, 
                                        makeEmptyDirs: false, 
                                        noDefaultExcludes: false, 
                                        patternSeparator: "[, ]+", 
                                        remoteDirectory: "/${PROJECT_NAME}/jar/${SERVICE_NAME}", 
                                        remoteDirectorySDF: false, 
                                        removePrefix: "${SERVICE_NAME}/target", 
                                        sourceFiles: "**/${SERVICE_NAME}*.jar"
                                        )
                                    ], 
                                        usePromotionTimestamp: false, 
                                        useWorkspaceInPromotion: false, 
                                        verbose: true
                                    )
                                ]
                            )
                        }
                    }
                }
            }
        }
        stage('回滾') {
            when {
                environment name:"ACTION", value: "rollback"
            }
            steps {
                script {
                     if (Release_servers.length() == 0) {
                        println("沒有可用於執行的伺服器")
                    } else {
                        for ( ip in Release_servers.tokenize(",")) {
                            sshPublisher(
                                publishers: [
                                    sshPublisherDesc(
                                        configName: "${ip}", 
                                        transfers: [
                                            sshTransfer(cleanRemote: false, 
                                            excludes: '', 
                                            execCommand: """
                                                echo  "###########################################################################################################################################################################################################################"
                                                mkdir  /var/log/${PROJECT_NAME}/${SERVICE_NAME} -p
                                                mkdir  /opt/${PROJECT_NAME}/link-jar/ -p
                                                SERVICE_PID=`pgrep -f "java.*${SERVICE_NAME}{0,20}\$"`  # 服務執行pid
                                                if [ -f  "/opt/${PROJECT_NAME}/jar/${SERVICE_NAME}/${SERVICE_NAME}-${BACK_VERSION}.jar" ]
                                                then
                                                    echo   "${ip}:開始部署${SERVICE_NAME}"
                                                    ln -snf  /opt/${PROJECT_NAME}/jar/${SERVICE_NAME}/${SERVICE_NAME}-${BACK_VERSION}.jar   /opt/${PROJECT_NAME}/link-jar/${PROJECT_NAME}-${SERVICE_NAME} 
                                                    kill -9 "\${SERVICE_PID}" 
                                                    nohup java -jar  /opt/${PROJECT_NAME}/link-jar/${PROJECT_NAME}-${SERVICE_NAME} > /var/log/${PROJECT_NAME}/${SERVICE_NAME}/${SERVICE_NAME}-${BUILD_TIMESTAMP}.${ACTION}.log 2>&1 &
                                                    echo -e "\n啟動日誌將持續輸出20s時間,如果沒有輸出日誌,則表示回滾失敗\n"
                                                    timeout 20 tail -f  /var/log/${PROJECT_NAME}/${SERVICE_NAME}/${SERVICE_NAME}-${BUILD_TIMESTAMP}.${ACTION}.log
                                                    sleep 1
                                                else
                                                    echo "${ip}上找不到版本號為${BACK_VERSION}的${SERVICE_NAME},請檢查後重新構建"
                                                    exit 145
                                                fi
                                            """, 
                                            execTimeout: 120000, 
                                            flatten: false, 
                                            makeEmptyDirs: false, 
                                            noDefaultExcludes: false, 
                                            patternSeparator: '[, ]+', 
                                            remoteDirectory: '', 
                                            remoteDirectorySDF: 
                                            false, removePrefix: '', 
                                            sourceFiles: ''
                                            )
                                        ], 
                                        usePromotionTimestamp: false, 
                                        useWorkspaceInPromotion: false, 
                                        verbose: true
                                    )
                                ]
                            )
                        }
                    }
                }
            }
        }
        stage('啟動') {
            when {
                environment name:"ACTION", value: "start"
            }
            steps {
                script {
                    if (Release_servers.length() == 0) {
                        println("沒有可用於執行的伺服器")
                    } else {
                        for ( ip in Release_servers.tokenize(",")) {
                            sshPublisher(
                                publishers: [
                                    sshPublisherDesc(
                                        configName: "${ip}", 
                                        transfers: [
                                            sshTransfer(cleanRemote: false, 
                                            excludes: '', 
                                            execCommand: """
                                                echo  "###########################################################################################################################################################################################################################"
                                                SERVICE_PID=`pgrep -f "java.*${SERVICE_NAME}{0,20}\$"`  # 服務執行pid
                                                if [ \$? != "0" ]
                                                then
                                                    echo   "${ip}:正在啟動${SERVICE_NAME}"
                                                    nohup java -jar  /opt/${PROJECT_NAME}/link-jar/${PROJECT_NAME}-${SERVICE_NAME} > /var/log/${PROJECT_NAME}/${SERVICE_NAME}/${SERVICE_NAME}-${BUILD_TIMESTAMP}.${ACTION}.log 2>&1 &
                                                    echo -e "\n啟動日誌將持續輸出20s時間,如果沒有輸出日誌,則表示回滾失敗\n"
                                                    timeout 20 tail -f  /var/log/${PROJECT_NAME}/${SERVICE_NAME}/${SERVICE_NAME}-${BUILD_TIMESTAMP}.${ACTION}.log
                                                    sleep 1
                                                else
                                                    echo "${ip}上${SERVICE_NAME}已啟動,無需執行"
                                                    exit 145
                                                fi
                                            """, 
                                            execTimeout: 120000, 
                                            flatten: false, 
                                            makeEmptyDirs: false, 
                                            noDefaultExcludes: false, 
                                            patternSeparator: '[, ]+', 
                                            remoteDirectory: '', 
                                            remoteDirectorySDF: 
                                            false, removePrefix: '', 
                                            sourceFiles: ''
                                            )
                                        ], 
                                        usePromotionTimestamp: false, 
                                        useWorkspaceInPromotion: false, 
                                        verbose: true
                                    )
                                ]
                            )
                        }
                    }
                }
            }
        }
        stage('重啟') {
            when {
                environment name:"ACTION", value: "restart"
            }
            steps {
                script {
                    if (Release_servers.length() == 0) {
                        println("沒有可用於執行的伺服器")
                    } else {
                        for ( ip in Release_servers.tokenize(",")) {
                            sshPublisher(
                                publishers: [
                                    sshPublisherDesc(
                                        configName: "${ip}", 
                                        transfers: [
                                            sshTransfer(cleanRemote: false, 
                                            excludes: '', 
                                            execCommand: """
                                                echo  "###########################################################################################################################################################################################################################"
                                                SERVICE_PID=`pgrep -f "java.*${SERVICE_NAME}{0,20}\$"`  # 服務執行pid
                                                echo   "${ip}:正在重啟${SERVICE_NAME}"
                                                kill -9 "\${SERVICE_PID}" 
                                                nohup java -jar  /opt/${PROJECT_NAME}/link-jar/${PROJECT_NAME}-${SERVICE_NAME} > /var/log/${PROJECT_NAME}/${SERVICE_NAME}/${SERVICE_NAME}-${BUILD_TIMESTAMP}.${ACTION}.log 2>&1 &
                                                echo -e "\n啟動日誌將持續輸出20s時間,如果沒有輸出日誌,則表示回滾失敗\n"
                                                timeout 20 tail -f  /var/log/${PROJECT_NAME}/${SERVICE_NAME}/${SERVICE_NAME}-${BUILD_TIMESTAMP}.${ACTION}.log
                                                sleep 1

                                            """, 
                                            execTimeout: 120000, 
                                            flatten: false, 
                                            makeEmptyDirs: false, 
                                            noDefaultExcludes: false, 
                                            patternSeparator: '[, ]+', 
                                            remoteDirectory: '', 
                                            remoteDirectorySDF: 
                                            false, removePrefix: '', 
                                            sourceFiles: ''
                                            )
                                        ], 
                                        usePromotionTimestamp: false, 
                                        useWorkspaceInPromotion: false, 
                                        verbose: true
                                    )
                                ]
                            )
                        }
                    }
                }
            }
        }
        stage('停止') {
            when {
                environment name:"ACTION", value: "stop"
            }
            steps {
                script {
                    if (Release_servers.length() == 0) {
                        println("沒有可用於執行的伺服器")
                    } else {
                        for ( ip in Release_servers.tokenize(",")) {
                            sshPublisher(
                                publishers: [
                                    sshPublisherDesc(
                                        configName: "${ip}", 
                                        transfers: [
                                            sshTransfer(cleanRemote: false, 
                                            excludes: '', 
                                            execCommand: """
                                                echo  "###########################################################################################################################################################################################################################"
                                                SERVICE_PID=`pgrep -f "java.*${SERVICE_NAME}{0,20}\$"`  # 服務執行pid
                                                if [ \$? == "0" ]
                                                then
                                                    echo   "${ip}:正在停止服務${SERVICE_NAME}"
                                                    kill -9 "\${SERVICE_PID}" 
                                                    echo "服務${SERVICE_NAME}"停止成功
                                                else
                                                    echo "${ip}上${SERVICE_NAME}未啟動,無需執行"
                                                    exit 145
                                                fi
                                            """, 
                                            execTimeout: 120000, 
                                            flatten: false, 
                                            makeEmptyDirs: false, 
                                            noDefaultExcludes: false, 
                                            patternSeparator: '[, ]+', 
                                            remoteDirectory: '', 
                                            remoteDirectorySDF: 
                                            false, removePrefix: '', 
                                            sourceFiles: ''
                                            )
                                        ], 
                                        usePromotionTimestamp: false, 
                                        useWorkspaceInPromotion: false, 
                                        verbose: true
                                    )
                                ]
                            )
                        }
                    }
                }
            }
        }
    }
}