Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本

文章目录

    • 1、Pipeline和Jenkinsfile
    • 2、可以重用的构建脚本
      • 2.1、配置多版本JDK
      • 2.2、配置Maven
      • 2.3、远程服务器操作插件Publish Over SSH
      • 2.4、创建Git帐号密码认证信息
      • 2.5、创建PipeLine任务
      • 2.6、PipeLineJenkinsfile脚本代码
      • 2.7、构建效果
        • 2.71、编译
        • 2.72、部署
        • 2.73、回滚
      • 2.8、全部构建结果

1、Pipeline和Jenkinsfile

Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第1张图片

项目部署使用Pipeline的Jenkinsfile脚本代码方式会比基于界面配置好处:

  • 可以使用Git/SVN之类的版本工具把构建脚本也管理和控制;
  • 支持多人协作,也可以对脚本进行代码审核;
  • 构建脚本可以重用;

使用脚本的方式唯一缺点就是脚本构建相对界面配置会稍有一点难度,需要pipeline语法,pipeline支持groovy代码,可以基于groovy实现功能更强大的操作。

2、可以重用的构建脚本

这个构建脚本模板,定义了编译、部署、关闭、回滚操作,适用于大多数java项目,支持多服务器部署,可用于生产环境。
对于大多数项目,我们都是在安装Jenkins的这台服务器,完成编译和打包工具和制品管理,而在部署的服务器上,一般只安装java运行环境。对于大多公司可以使用Jenkins自带的archiveArtifactsa插件来对制品(部署文件、安装包等)管理,归档制品备份,回滚操作中可以直接使用归档的旧版本包,

2.1、配置多版本JDK

可以根据项目需要,配置多个版本的JAVA_HOME,比如本文是同时了OpenJDK8和OpenJDK11,构建时,可以通过在脚本中工具代码块中配置

tools {
	jdk 'JAVA_HOME8'  # 指定编译用的jdk版本
}

Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第2张图片

2.2、配置Maven

同样可以通过在脚本中工具代码块中配置:

tools {
     maven 'MAVEN_HOME'
}

Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第3张图片

2.3、远程服务器操作插件Publish Over SSH

可以在Linux shell中通过scp命令上传文件,ssh命令连接远程服务器操作脚本,参考代码如下,但是使用Publish Over SSH插件会更方便
Pipeline通过Linux shell上传文件和远程服务命令,注意需要先配置远程服务器免密登录。

stage('部署') {
    steps {
        script{
            sh "scp target/JApiTest-1.0.0_56.zip [email protected]:$upload_dir/JApiTest-1.0.0_56.zip"
            sh "ssh -tt [email protected] << remotessh
                unzip -oq $upload_dir/${app_name}.zip -d ${deploy_dir}/${app_name}
                cd ${deploy_dir}/${app_name}
                chmod 0755 ./server.sh
                ./server.sh restart
                exit
                remotessh"
        }

    }
}

不推荐上边直接在Linux Shell命令上传和远程执行命令,建议使用Publish Over SSH或SSH Pipeline Steps的方式更好。
Publish Over SSH配置远程服务器连接信息,这里配置了两台部署服务器的连接信息。可以使用帐号密码的方式远程连接,也可以免密的方式远程连接。
Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第4张图片

2.4、创建Git帐号密码认证信息

Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第5张图片

2.5、创建PipeLine任务

Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第6张图片
创建的任务中,只需要在界面上配置Jenkinsfile文件所在的git仓库和在仓库中的具体目录就行了,其它信息不需要配置。Jenkinsfile代码版本化,更适合项目管理的需要,有能力公司也可以对Jenkinsfile代码进行评审。
Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第7张图片

2.6、PipeLineJenkinsfile脚本代码

完成2.1-2.5配置,就可以在具体的流水线代码上使用这些配置了,为了获取pom.xml文件中的版本,也使用groovy代码写了个version(file)获取版本号的方法供脚本调用。完整的流水线代码如下:

/**
* 获取maven项目版本号
*/
def version(file){
    def version = ''
    if(fileExists(file)){
        def data = readFile(file: file)
        def lines = data.readLines()
        def isProject = false;
        def isParent = false;
        for (line in lines) {
            if(line.indexOf(") > -1){
                isProject = true
            }
            if(isProject == true && line.indexOf("") > -1){
                def start = line.indexOf("");
                def end = line.indexOf("");
                version = line.substring(start + 9,end);
                break;
            }
        }
    }
    return version
}

def build(){
    checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [],userRemoteConfigs:[[
                                                                                                        credentialsId: 'gitee', url: 'https://gitee.com/penngo/XXJApiTest.git']]])
    app_version =version(source_dir + '/pom.xml')
    env.app_name_version ="${app_name}-${app_version}"
    sh("""
        java -version
        mvn clean package
    """.replace("    ", ""))
    sh([
            "cd ${source_dir}/target",
            "cp -f ../server.sh server.sh",
            "zip -q -r ${app_name_version}_${BUILD_ID}.zip ${app_name_version}.war server.sh"
    ].join("\n"))
}

def deploy(servers, build_id_temp){
    def build_id = build_id_temp == '' ? readFile(file: "build_id.txt") : build_id_temp;
    sh("""
        cp -f ${WORKSPACE}/../../jobs/${app_name}/builds/${build_id}/archive/target/*_${build_id}.zip ${app_name}.zip
    """.replace("\t",""));

    for(ip in servers.tokenize(",")){
        echo "=====ssh_ip:" + ip
        sshPublisher(
                publishers: [
                        sshPublisherDesc(
                                configName: "${ip}",
                                transfers: [
                                        sshTransfer(cleanRemote: false,
                                                excludes: '',
                                                execCommand: """
                                                        unzip -oq $upload_dir/${app_name}.zip -d ${deploy_dir}/${app_name}
                                                        cd ${deploy_dir}/${app_name}
                                                        chmod 0755 ./server.sh
                                                        ./server.sh restart
                                                """.replace('    ',''),
                                                execTimeout: 120000,
                                                flatten: false,
                                                makeEmptyDirs: false,
                                                noDefaultExcludes: false,
                                                patternSeparator: '[, ]+',
                                                remoteDirectory: "${upload_dir}",
                                                remoteDirectorySDF: false,
                                                removePrefix: "",
                                                sourceFiles: "${app_name}.zip")
                                ],
                                usePromotionTimestamp: false,
                                useWorkspaceInPromotion: false,
                                verbose: true)
                ])
    }
}

def rollback(servers, build_number){
    deploy(servers, build_number)
}

pipeline {
    agent any
    tools {
        maven 'MAVEN_HOME'
        jdk 'JAVA_HOME8'
    }
    options {
        buildDiscarder(logRotator(numToKeepStr: "10"))
    }
    environment{
        source_dir="${WORKSPACE}/JApiTest"
        jenkinsfile_dir="${WORKSPACE}"
        jenkinsfile_job_dir="${WORKSPACE}/../../JApiTest"
        app_version=version(source_dir + '/pom.xml')
        app_name="JApiTest"
        app_name_version="${app_name}-${app_version}"
        deploy_dir="/data/app"
        upload_dir="/data/upload"

    }
    parameters {
        choice(name: 'app', choices:['JApiTest'],description: '应用(请选择需要操作的应用:JApiTest)')
        choice(name: 'select', choices:[
                '请选择',
                '编译',
                '部署',
                '回滚',
        ],description: '操作(请选择操作:编译、部署、回滚)')

        extendedChoice(description: '服务器', value: '192.168.28.129,192.168.28.132',
            descriptionPropertyValue: '192.168.28.129(测试),192.168.28.132(正式)',
            multiSelectDelimiter: ',', name: 'servers', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', visibleItemCount: 5)
        string(
                description: """回滚版本号""",
                name: 'roll_number',
                trim: true
        )
    }

    stages {
        stage('编译') {
            when {
                expression { params.select.trim() == "编译" }
            }
            steps {
                dir("${source_dir}"){
                    script {
                        build()
                    }
                }
                writeFile(file: "build_id.txt", text: "${BUILD_ID}")
            }
        }

        stage('部署') {
            when {
                expression { "${params.select}".trim() == "部署" }
            }
            steps {
                script {
                    deploy(params.servers, '')
                }
            }
        }

        stage('回滚') {
            when {
                expression { "${params.select}".trim() == '回滚' }
            }
            steps {
                script {
                    rollback(params.servers, params.roll_number)
                }
            }
        }
    }
    post {
        success{
            script {
                if(params.select.trim() == "编译"){
                    dir("${source_dir}"){
                        archiveArtifacts artifacts: "target/${app_name_version}_${BUILD_ID}.zip", fingerprint: false
                    }
                }
            }

        }
    }
}

配合运行的Linux脚本server.sh

#!/bin/bash -il
export JAVA_HOME=/usr/lib/jvm/bellsoft-java8-full.x86_64
export PATH=$JAVA_HOME/bin:$PATH
java -version

APP_NAME="JApiTest"
JAR_NAME="JApiTest-1.0.0.jar"
JAVA_OPTS="-Xmx2G -XX:+UseG1GC"

start() {
	pid=`ps -ef | grep "$JAR_NAME" | grep -v grep | awk '{print $2}'`
	if [ -z $pid ]; then
	  export JENKINS_NODE_COOKIE=dontKillMe
    nohup java $JAVA_OPTS -jar $JAR_NAME 2>&1 &
    sleep 3
    pid=`ps -ef | grep "$JAR_NAME" | grep -v grep | awk '{print $2}'`
    if [ -z $pid ]; then
      echo ".....service ${JAR_NAME} is run error....."
    else
      echo ""
      echo ".....Service ${JAR_NAME} is starting!pid=${pid}....."
      echo "........................Start successfully!........................."
    fi
	else
		echo ""
		echo "Service ${JAR_NAME} is already running,it's pid = ${pid}"
		echo ""
	fi
}

stop() {
	pid=`ps -ef | grep "$JAR_NAME" | grep -v grep | awk '{print $2}'`
	if [ -z $pid ]; then
    echo "Service ${JAR_NAME} is not running!"
	else
		kill -9 $pid
		echo "Service stop successfully!pid:${pid} been killed"
	fi
}

restart() {
	echo ""
	echo ".............................Restarting.............................."
	stop
	start
	echo "....................Restart successfully!..........................."
}

if [ ! -n "$1" ] ;then
 echo "Usage: $0 {start|stop|restart}"
elif [ $1 = "start" ];then
 start
elif [ $1 = "stop" ];then
 stop
elif [ $1 = "restart" ];then
 restart
fi

2.7、构建效果

使用Pipeline脚本方式部署,必须先执行一次后,才能出现2.7.1参数可选界面,如果未执行过,默认是下边在界面:
Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第8张图片

2.71、编译

Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第9张图片

2.72、部署

Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第10张图片

2.73、回滚

构建前需要填入有归档文件的构建任务号。
Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第11张图片

2.8、全部构建结果

构建任务中有下载图标的都表示这个构建任务有归档文件。
Jenkins流水线部署模板,编译、部署、关闭、回滚流水线脚本_第12张图片

你可能感兴趣的:(持续交付,jenkins,linux,服务器)