学了几天jenkins的流水线,拼凑出了一个批量发布的脚本,由于是才入门还存在很多不足,先记录下后续再优化。
下一步打算实现容器的批量部署

/* 
1、脚本中尽量使用双引号,单引号中使用变量会出问题
2、远程执行shell脚本中的内部的“$”符号需要斜杠转义,包括变量和正则表达式的使用,流水线中的全局变量则不需要转义直接使用
3、远程执行shell脚本说明
    发布:
        1)使用“Publish over SSH”插件上传jar包到服务器
        2)修改jar文件名称,在名称后面加上构建时间,最终jar文件名称类似gateway-1.0.7.22020914.jar,jar文件名添加时间这步也可以由mav`在这里插入代码片`en实现
        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")   // 设置流水线运行超过5分钟,Jenkins将中止流水线
        buildDiscarder(logRotator(numToKeepStr: "10"))   // 表示保留10次构建历史
    }

    //参数化构建过程,可在流水线语法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
                                    )
                                ]
                            )
                        }
                    }
                }
            }
        }
    }
}