Jenkinsfile编写简单说明(pipeline scrip)

简介

Jenkins流水线是一套插件,它支持实现和集成持续交付流水线到 Jenkins。流水线提供了一组可扩展的工具,用于通过流水线 DSL将简单到复杂的交付流水线建模为 "代码"。本文只是简单的介绍了下Jenkinsfile文件的编写,还有许多不足和可以优化改进的地方。

通过 Blue Ocean 创建

在上一篇Jenkins的简单使用文章中,已经介绍了使用blue ocean图形化创建pipeline。但是这种方式,创建出来的pipeline往往不符合我们的要求,直接写脚本的形式,可能更容易理解一点。所以本文主要介绍pipeline脚本的编写,再编写Jenkinsfile之前,最好先看看官方的教程,了解Jenkins的pipeline语法。

编写Jenkinsfile(pipeline脚本)

maven项目构建

先附上完整的pipeline脚本,然后再对其中的命令做对应的解释。而官方有的基础命令,则本文不再多做解释了,建议直接访问官网流水线语法参考 学习其中的命令

maven的pipeline

pipeline {
    //设置环境变量
    environment {
        CI = 'true'
        HAR_NAME = "test"
        HAR_PASS = "Test12345"
        SONARURL = "http://sonar.com"
        SONARURL_token = "bb99xxxxxxx0bad5cf4"
        CON_PROT = "8002"
        TEST_ENV = "XXXX-test"
        DEV_ENV = "XXXX-dev"
    }
    agent any
		//设置构建的参数
		parameters {
		//设置环境部署参数
        choice choices: ['test', 'dev', 'not'], description: '选择需要部署的环境,不需要部署则选择not', name: 'DEPLOY_TO'
		//读取git的tag数据,该功能需要安装插件
        listGitBranches branchFilter: 'origin/(.*)', credentialsId: 'gitlab', defaultValue: 'master', name: 'tag', quickFilterEnabled: false, remoteURL: 'http://gitlab.com.cn/xxx/xxx.git', selectedValue: 'NONE', sortMode: 'DESCENDING_SMART', tagFilter: '*', type: 'PT_TAG'
		//设置钉钉的webhook
        string defaultValue: 'https://oapi.dingtalk.com/robot/send?access_token=e706xxxf835279xxxx9453xxxxxx1561', description: '钉钉webhook通知地址', name: 'webhook', trim: false
		//设置字符参数callphone,默认值是18677371111
        string defaultValue: '18677371111', description: '通知人', name: 'callphone', trim: false
    }
	//设置构建需要用到的工具,该工具需要先在Jenkins中配置好
    tools {
        maven "maven3.5.4"
    }
    stages {
        stage('构建') {
            steps {
                echo '开始构建'
				//拉去git代码,需要先配置好相应凭据
                git credentialsId: 'gitlab', url: 'http://gitlab.com.cn/xxx/xxx.git'
				//切换分支
                sh 'git checkout ${tag}'
				//构建
                sh 'mvn -DskipTests clean package'
                echo '构建成功'
            }
        }
        stage('代码扫描') {
            steps {
                echo '开始代码扫描'
                sh 'mvn sonar:sonar -Dsonar.host.url=${SONARURL} -Dsonar.login=${SONARURL_token}'
                echo '代码扫描结束'
            }
        }
        stage('镜像构建') {
            steps {
                echo '构建镜像并上传到harbor'
                script {
                    //登陆使用的凭据需要提前在Jenkins中添加好                
                    def customImage = docker.build("harbor.com.cn/${HAR_NAME}/${JOB_NAME}:${env.GIT_BRANCH}-${env.BUILD_NUMBER}")
                    withDockerRegistry(credentialsId: 'har-test', url: 'http://harbor.com.cn')  {
                    customImage.push("${env.GIT_BRANCH}-${env.BUILD_NUMBER}") 
                    customImage.push("latest")
                    }
                }
				//这里为了节约空间,所以在上传到harbor之后,就删除本地的镜像
                echo '删除本地镜像'
                sh "docker image rm harbor.com.cn/${HAR_NAME}/${JOB_NAME}:${env.GIT_BRANCH}-${env.BUILD_NUMBER}"
            }
        }
        stage('测试环境部署') {
		    //定义部署的节点机
            agent { label "${TEST_ENV}" }
			//定义该步骤不拉取代码
            options { skipDefaultCheckout() }
			//当构建参数为test的时候,才执行该步骤
            when {
                beforeAgent true
                environment ignoreCase: true, name: 'DEPLOY_TO', value: 'test'
            }
            steps {
                echo '开始环境部署'
				//登陆harbor
                sh "docker login -u ${HAR_NAME} -p ${HAR_PASS} harbor.com.cn"
				//拉去镜像
                sh "docker pull harbor.com.cn/${HAR_NAME}/${JOB_NAME}:latest"
				//删除和停止原本的容器
                sh '''if [ $(docker ps -aq --filter name=^/${JOB_NAME}$) ]; then docker stop ${JOB_NAME} && docker rm ${JOB_NAME};fi'''
                //自动部署最新版本
                sh '''docker run -d --name ${JOB_NAME} -p ${CON_PROT}:${CON_PROT} harbor.com.cn/${HAR_NAME}/${JOB_NAME}:latest --spring.profiles.active=test '''
                echo '部署结束'
            }
        }
        stage('接口测试') {
            when {
                branch 'master'
            }
            steps {
                echo '开始接口测试'
                sh '''
                curl 'yapi.com'
                '''
                echo '接口测试结束'
            }
        }
    }
    post {
        failure {
		//钉钉通知,使用的是一个简单的shell脚本,传入相关参数即可
            sh "ding.sh ${webhook} ${callphone} ${JOB_NAME} ${BUILD_ID} ${BUILD_TAG} ${esdb_tag} 失败"
        }
        success {
		//钉钉通知
            sh "ding.sh ${webhook} ${callphone} ${JOB_NAME} ${BUILD_ID} ${BUILD_TAG} ${esdb_tag} 失败"
        }
    }
}   

dockerfile文件

上面的Jenkinsfile中,是构建为docker镜像的形式,所以需要一个dockerfile文件,通常像下面这个就可以了。设置了时区为中国时区。基础镜像也是使用alpine的,体积比较小。

FROM java:8-jdk-alpine
VOLUME /tmp
ADD /target/*.jar /app.jar
RUN apk --no-cache add tzdata  && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone 
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar", "app.jar"]

ding.sh文件

构建完成之后,我们需要知道构建结果,就可以使用钉钉群的webhook功能,当然也有邮件、微信,qq等其他方式通知,这个就需要去自己探索了。这里给出上面Jenkinsfile中的ding.sh文件,里面需要修改下Jenkins地址为自己的。

#!/bin/sh

usage () {
  echo "Usage: ding.sh [webhook] [cell-phone number] [JOB_NAME] [BUILD_ID] [BUILD_TAG] [deploy_env] [STATUS]";
  echo "       [webhook]: 钉钉聊天机器人webhook。";
  echo "       [cell-phone number]: 要@的成员手机号。";
  echo "       [JOB_NAME]: Jenkins的构建项目名";
  echo "       [BUILD_ID]: Jenkins的构建ID";
  echo "       [BUILD_TAG]: 构建的分支";
  echo "       [deploy_env]: 部署的环境";
  echo "       [STATUS]: 状态";
  exit 1;
}

WEB_HOOK=$1	

AT=$2

JOB_NAME=$3

BUILD_ID=$4

BUILD_TAG=$5

deploy_env=$6

STATUS=$7

TIME=$(date "+%Y-%m-%d %H:%M:%S")


shift 2

make(){
curl ${WEB_HOOK} -H "Content-type: application/json" -X POST -d "
{
     "msgtype": 'markdown',
     "markdown": {
     "title":'持续集成机器人',
     "text":'
# CI/CD机器人:构建${STATUS}\n\n 执行任务:代码扫描+构建+${deploy_env}环境部署\n\n 构建时间:${TIME} \n\n 项目名称:${JOB_NAME}\n\n 构建编号:${BUILD_ID} \n\n 构建版本:${BUILD_TAG}\n\n [点击查看](http://Jenkins.com/blue/organizations/jenkins/${JOB_NAME}/detail/${JOB_NAME}/${BUILD_ID})

@${AT}
'

     },
      "at": {
          "atMobiles": [
              "$AT"
          ],
          "isAtAll": false
      }

}"

}

make $@