jenkins流水线

之前采用Jenkins的自由风格构建的项目,每个步骤流程都要通过不同的方式设置,并且构建过程中整体流程是不可见的,无法确认每个流程花费的时间,并且问题不方便定位问题。

Jenkins的Pipeline可以让项目的发布整体流程可视化,明确执行的阶段,可以快速的定位问题。并且整个项目的生命周期可以通过一个Jenkinsfile文件管理,而且Jenkinsfile文件是可以放在项目中维护。

所以Pipeline相对自由风格或者其他的项目风格更容易操作。

一、构建Jenkins流水线任务

1.1、构建任务

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker


Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_02


Jenkins流水线部署ruoyi项目 jenkins复制流水线_jenkins_03

1.2、Groovy脚本

Groovy脚本基础语法

// 所有脚本命令包含在pipeline{}中
pipeline {  
	// 指定任务在哪个节点执行(Jenkins支持分布式),any 代表任意节点
    agent any
    
    // 配置全局环境,指定变量名=变量值信息
    environment{
    	key = 'value'
    }

    // 存放所有任务的合集
    stages {
    	// 单个任务
        stage('任务1') {
        	// 实现任务的具体流程
            steps {
                echo 'do something'
            }
        }
		// 单个任务
        stage('任务2') {
        	// 实现任务的具体流程
            steps {
                echo 'do something'
            }
        }
        // ……
    }
}

jenkins流水线测试模板

pipeline {
    
    // 指定任务在哪个集群节点中执行
    agent any 

    // 声明全局变量,方便后期使用
    environment {
        key = 'value'
    }

    stages {
        stage('拉取git仓库代码') {
            steps {
                echo '拉取git仓库代码 -SUCCESS'
            }
        }
        stage('通过maven构建项目') {
            steps {
                echo '通过maven构建项目 -SUCCESS'
            }
        }
        stage('通过SonarQube做代码质量检测') {
            steps {
                echo '通过SonarQube做代码质量检测 -SUCCESS'
            }
        }
        stage('通过docker制作自定义镜像') {
            steps {
                echo '通过docker制作自定义镜像 -SUCCESS'
            }
        }
        stage('将自定义镜像推送到harbor上') {
            steps {
                echo '将自定义镜像推送到harbor上 -SUCCESS'
            }
        }
        stage('通过publish over ssh通知目标服务器') {
            steps {
                echo '通过publish over ssh通知目标服务器 -SUCCESS'
            }
        }
    }
}

在jenkins流水线上执行

Jenkins流水线部署ruoyi项目 jenkins复制流水线_jenkins_04

查看构建后的状态

Jenkins流水线部署ruoyi项目 jenkins复制流水线_运维_05

1.3、jenkins-pipeline语法自动生成工具

通过流水线语法生成Checkout代码的脚本
流水线语法–>片段生成器

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_06

1.3.1、拉取git仓库代码

checkout: check out from version control

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_07

将脚本中的 */master更改为${release},release为代码版本/标签

pipeline {
    agent any
    stages {

        stage('拉取Git代码') {
            steps {
                checkout scmGit(branches: [[name: '${release}']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.12.104:9980/root/mytest.git']])
            }
        }
    }
}

新建参数变量,参考下图
${release}为版本号/gitlab中打的标签,需要自定义变量,参考下图

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_08

<---------------------废弃-------------------->

/var/jenkins_home/maven/bin/mvn clean package -DskipTests
新建3个参数,一个git,两个docker容器相关

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_09

jenkins引用gitlab中的Jenkinsfile文件
Jenkins — 项目名称 — 流水线 --定义-- SCM --> GIT,配置好之后会自动识别加载识别Jenkinsfile文件的。

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_10


<---------------------以上内容废弃-------------------->

1.3.2、通过maven构建代码

使用shell命令,参数:sh: Shell Script

pipeline文件内容如下
/var/jenkins_home/maven/bin/mvn clean package -DskipTests

stage('通过maven构建代码') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }
1.3.3、代码质量检测

代码质量检测,参数:sh: Shell Script
${JOB_NAME} 变量指项目名称

stage('通过SonarQube做代码质量检测') {
            steps {
                sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.source=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=0ab1a777144b459db09cdd0cfc06a300887c54cb'
            }
        }
1.3.4、自定义镜像

自定义镜像,参数:sh: Shell Script
注意:$release不能加{},引号会导致变量失效
mv target/*.jar docker/docker build -t ${JOB_NAME}:$release docker/

stage('通过docker制作自定义镜像') {
            steps {
                sh '''mv target/*.jar docker/
                docker build -t ${JOB_NAME}:$release docker/'''
            }
        }

开始构建,选择标签,下图中的标签上同步gitlab中的tag

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_11

1.3.5、镜像上传到harbor

上传到harbor,参数:sh: Shell Script
需要自定义环境变量
docker login -u ${harborUser} -p ${harborPwd} ${harborUrl}docker tag ${JOB_NAME}:${release} ${harborUrl}/${harborRepo}/${JOB_NAME}:${release}docker push ${harborUrl}/${harborRepo}/${JOB_NAME}:${release}docker image prune -f

pipeline {
    
    // 指定任务在哪个集群节点中执行
    agent any 

    // 声明全局变量,方便后期使用
    environment {
        harborUser = 'admin'
        harborPwd = '123456'
        harborRepo = 'repo2'
        harborUrl = '192.168.12.104:180'
    }
    stages {
        stage('将自定义镜像推送到harbor上') {
            steps {
                sh '''docker login -u ${harborUser} -p ${harborPwd} ${harborUrl}
docker tag ${JOB_NAME}:latest ${harborUrl}/${harborRepo}/${JOB_NAME}:latest
docker push ${harborUrl}/${harborRepo}/${JOB_NAME}:latest
docker image prune -f'''
            }
        }
	}
}
1.3.6、通知目标服务器执行

通知目标服务器,Publish Over SSH脚本
deploy.sh脚本已放到目标服务器的全局变量中,脚本内容如下

# 脚本内容
#/bin/bash
harbor_url=$1
harbor_repo=$2
project=$3
version=$4
host_port=$5
container_port=$6

imageName=$harbor_url/$harbor_repo/$project:$version

containerId=`docker ps -a | grep ${project} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
    docker stop $containerId
    docker rm $containerId
    echo "Delete Container Success"
fi

imageId=`docker images | grep ${project} | awk '{print $3}'`

if [ "$imageId" != "" ] ; then
    docker rmi -f $imageId
    echo "Delete Image Success"
fi

docker login -u admin -p 123456 $harbor_url

docker pull $imageName

docker run -d -p $host_port:$container_port --name $project $imageName

echo "Start Container Success"
echo $project

执行命令为:
deploy.sh $harborUrl $harborRepo $JOB_NAME $release $host_port $container_port
$harborUrl $harborRepo 为pipeline中配置的全局变量
$JOB_NAME,为项目名称变量
$release,gitlab中定义的版本变量
$host_port $container_port,需要新加2个参数

jenkins流水线参数:sshPublisher: Send build artifacts over SSH

Jenkins流水线部署ruoyi项目 jenkins复制流水线_gitlab_12

jenkins中新加参数:$host_port $container_port

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_13

pipeline内容如下, 其中自定义语法生成的是单引号,要改成双引号。

pipeline {
    agent any
    
    environment {
        harborUser = 'admin'
        harborPwd = '123456'
        harborRepo = 'repo2'
        harborUrl = '192.168.12.104:180'
    }
    stages {
		stage('通过publish over ssh通知目标服务器') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'mydemo-92', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborUrl $harborRepo $JOB_NAME $release $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }
}

构建

Jenkins流水线部署ruoyi项目 jenkins复制流水线_gitlab_14

1.4、使用JenkinsFile方式执行流水线

在gitlab中新建Jenkinsfile文件,

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_15

Jenkinsfile文件内容如下

pipeline {
    
    // 指定任务在哪个集群节点中执行
    agent any 

    // 声明全局变量,方便后期使用
    environment {
        harborUser = 'admin'
        harborPwd = '123456'
        harborRepo = 'repo2'
        harborUrl = '192.168.12.104:180'
    }

    stages {
        stage('拉取git仓库代码') {
            steps {
                checkout scmGit(branches: [[name: '${release}']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.12.104:9980/root/mytest.git']])
            }
        }
        stage('通过maven构建项目') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }
        stage('通过SonarQube做代码质量检测') {
            steps {
                sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.source=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=0ab1a777144b459db09cdd0cfc06a300887c54cb'
            }
        }
        stage('通过docker制作自定义镜像') {
            steps {
                sh '''mv ./target/*.jar ./docker/
docker build -t ${JOB_NAME}:${release} ./docker/'''
            }
        }
        stage('将自定义镜像推送到harbor上') {
            steps {
                sh '''docker login -u ${harborUser} -p ${harborPwd} ${harborUrl}
docker tag ${JOB_NAME}:${release} ${harborUrl}/${harborRepo}/${JOB_NAME}:${release}
docker push ${harborUrl}/${harborRepo}/${JOB_NAME}:${release}
docker image prune -f'''
            }
        }

		// 此处 execCommand后的命令要跟双引号,但引号会让变量失效,${harborUrl}等要改成 $harborUrl
        stage('通过publish over ssh通知目标服务器') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'mydemo-92', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborUrl $harborRepo $JOB_NAME $release $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }
}

引用gitlab中的Jenkinsfile

Jenkins流水线部署ruoyi项目 jenkins复制流水线_Jenkins流水线部署ruoyi项目_16

1.5、告警到钉钉群

安装dingtalk插件

Jenkins流水线部署ruoyi项目 jenkins复制流水线_运维_17

配置钉钉插件

Jenkins流水线部署ruoyi项目 jenkins复制流水线_gitlab_18


Jenkins流水线部署ruoyi项目 jenkins复制流水线_Jenkins流水线部署ruoyi项目_19

jenkins中项目中添加钉钉机器人告警

Jenkins流水线部署ruoyi项目 jenkins复制流水线_docker_20

pipeline语法配置,新加post请求

pipeline {
    
    // 指定任务在哪个集群节点中执行
    agent any 

    // 声明全局变量,方便后期使用
    environment {
        harborUser = 'admin'
        harborPwd = '123456'
        harborRepo = 'repo'
        harborUrl = '192.168.12.104:180'
    }

    stages {
        stage('拉取git仓库代码') {
            steps {
                checkout scmGit(branches: [[name: '${release}']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.12.104:9980/root/mytest.git']])
            }
        }
        stage('通过maven构建项目') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }
        stage('通过SonarQube做代码质量检测') {
            steps {
                sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.source=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=0ab1a777144b459db09cdd0cfc06a300887c54cb'
            }
        }
        
        stage('通过docker制作自定义镜像') {
            steps {
                sh '''mv ./target/*.jar ./docker/ \
                docker build -t ${JOB_NAME}:${release} ./docker/'''
            }
        }
        
        stage('将自定义镜像推送到harbor上') {
            steps {
                sh '''docker login -u ${harborUser} -p ${harborPwd} ${harborUrl}
docker tag ${JOB_NAME}:${release} ${harborUrl}/${harborRepo}/${JOB_NAME}:${release}
docker push ${harborUrl}/${harborRepo}/${JOB_NAME}:${release}
docker image prune -f'''
            }
        }
        stage('通过publish over ssh通知目标服务器') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'mydemo-92', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborUrl $harborRepo $JOB_NAME $release $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }
    
// 如下post内容为新加,
    post {
        success {
            dingtalk (
                robot: 'jenkins_dingtalk',	// 系统配置里边的 dingtalk ID
                type:'MARKDOWN',
                title: "success: ${JOB_NAME}",
                text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:${release}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
        failure {
            dingtalk (
                robot: 'jenkins_dingtalk',
                type:'MARKDOWN',
                title: "fail: ${JOB_NAME}",
                text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:${release}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
    }    
}

二、Jenkins整合kubernetes

2.1、将k8s的yaml文件配置到gitlab中

在gitlab中新建pipeline.yaml,内容如下

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: test
  name: pipeline
  labels:
    app: pipeline
spec:
  replicas: 2
  selector:
    matchLabels:
      app: pipeline
  template:
    metadata:
      labels:
        app: pipeline
    spec:
      containers:
      - name: pipeline
        image: 192.168.12.104:180/repo/pipeline:v3.0.0
        imagePullPolicy: Always
        ports:
        - containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  namespace: test
  name: pipeline
  labels:
    app: pipeline
spec:
  selector:
    app: pipeline
  ports:
  - port: 8081
    targetPort: 8080
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: test
  name: pipeline
spec:
  ingressClassName: ingress
  rules:
  - host: mashibing.pipeline.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: pipeline
            port:
              number: 8081

Jenkins流水线部署ruoyi项目 jenkins复制流水线_jenkins_21

2.2、设置目标服务器

jenkins --> 系统管理 --> 系统配置 --> ssh-server

Jenkins流水线部署ruoyi项目 jenkins复制流水线_Jenkins流水线部署ruoyi项目_22

2.3、在gitlab中修改Jenkinsfile,重新设置流水线任务脚本,并测试结果

修改后的jenkinsfile文件内容如下
1、新增 将yaml文件传送到k8smaster上,脚本语法见下图 sshPublisher: Send build artifacts over SSH
2、新增在k8smaster节点上执行yaml文件,sh: shell scripts

Jenkins流水线部署ruoyi项目 jenkins复制流水线_运维_23

pipeline {
    
    // 指定任务在哪个集群节点中执行
    agent any 

    // 声明全局变量,方便后期使用
    environment {
        harborUser = 'admin'
        harborPwd = '123456'
        harborRepo = 'repo'
        harborUrl = '192.168.12.104:180'
    }

    stages {
        stage('拉取git仓库代码') {
            steps {
                checkout scmGit(branches: [[name: '${release}']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.12.104:9980/root/mytest.git']])
            }
        }
        stage('通过maven构建项目') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }
        stage('通过SonarQube做代码质量检测') {
            steps {
                sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.source=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=0ab1a777144b459db09cdd0cfc06a300887c54cb'
            }
        }
        stage('通过docker制作自定义镜像') {
            steps {
                sh '''mv ./target/*.jar ./docker/
docker build -t ${JOB_NAME}:${release} ./docker/'''
            }
        }
        stage('将自定义镜像推送到harbor上') {
            steps {
                sh '''docker login -u ${harborUser} -p ${harborPwd} ${harborUrl}
docker tag ${JOB_NAME}:${release} ${harborUrl}/${harborRepo}/${JOB_NAME}:${release}
docker push ${harborUrl}/${harborRepo}/${JOB_NAME}:${release}
docker image prune -f'''
            }
        }
        stage('将yaml文件上传到目标服务器上') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'k8smaster', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'pipeline.yaml')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
        stage('在k8smaster节点上执行yaml文件') {
            steps {
                sh 'ssh root@192.168.12.120 kubectl apply -f /demo/k8s/pipeline.yaml'
            }
        }
    }
    post {
        success {
            dingtalk (
                robot: 'jenkins_dingtalk',
                type:'MARKDOWN',
                title: "success: ${JOB_NAME}",
                text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:${release}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
        failure {
            dingtalk (
                robot: 'jenkins_dingtalk',
                type:'MARKDOWN',
                title: "fail: ${JOB_NAME}",
                text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:${release}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
    }    
}

2.3、由于命令是中jenkins容器中执行的,所以要配置jenkins可以无密码连接k8smaster

在jenkins内部生成公私钥,然后执行 ssh-copy-id

2.4、查看执行效果。

构建 --> 选择版本

三、CI自动部署

3.1、gitlab中添加webhook地址,实现研发上传代码后自动构建执行部署

首先,启用jenkins的构建触发器,并拷贝webhook地址
webhook地址:http://192.168.12.110:8082/project/pipeline

Jenkins流水线部署ruoyi项目 jenkins复制流水线_运维_24

其次,设置gitlab出站请求

Jenkins流水线部署ruoyi项目 jenkins复制流水线_gitlab_25

在gitlab中添加jenkins的webhook地址,

Jenkins流水线部署ruoyi项目 jenkins复制流水线_jenkins_26

测试,初次状态玛为 403,原因是,jenkins拒绝连接,
修改jenkins中的gitlab连接配置,系统管理 --> 系统设置 --> gitlab

Jenkins流水线部署ruoyi项目 jenkins复制流水线_gitlab_27

gitlab再测试连接,状态码 200

Jenkins流水线部署ruoyi项目 jenkins复制流水线_运维_28


Jenkins流水线部署ruoyi项目 jenkins复制流水线_jenkins_29

3.2、修改jenkins配置文件,修改内容如下

1、修改所有 ${release} 为 latest,修改版本通过标签获取版本号,为制定版本号latest

2、其中,拉取git仓库代码这块,将${release} 修改为 */main
3、删除 通过publish over ssh通知目标服务器。

pipeline {
    
    // 指定任务在哪个集群节点中执行
    agent any 

    // 声明全局变量,方便后期使用
    environment {
        harborUser = 'admin'
        harborPwd = '123456'
        harborRepo = 'repo'
        harborUrl = '192.168.12.104:180'
    }

    stages {
        stage('拉取git仓库代码!') {
            steps {
                checkout scmGit(branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.12.104:9980/root/mytest.git']])
            }
        }
        stage('通过maven构建项目') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }
        stage('通过SonarQube做代码质量检测') {
            steps {
                sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.source=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=0ab1a777144b459db09cdd0cfc06a300887c54cb'
            }
        }
        stage('通过docker制作自定义镜像') {
            steps {
                sh '''mv ./target/*.jar ./docker/
docker build -t ${JOB_NAME}:latest ./docker/'''
            }
        }
        stage('将自定义镜像推送到harbor上') {
            steps {
                sh '''docker login -u ${harborUser} -p ${harborPwd} ${harborUrl}
docker tag ${JOB_NAME}:latest ${harborUrl}/${harborRepo}/${JOB_NAME}:latest
docker push ${harborUrl}/${harborRepo}/${JOB_NAME}:latest
docker image prune -f'''
            }
        }
        stage('将yaml文件传送到k8smaster上') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'k8smaster', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'pipeline.yaml')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
        stage('在k8smaster节点上执行yaml文件') {
            steps {
                sh '''ssh root@192.168.12.120 kubectl apply -f /demo/k8s/pipeline.yaml
ssh root@192.168.12.120 kubectl -n test rollout restart deployment pipeline'''
            }
        }
    }
    post {
        success {
            dingtalk (
                robot: 'jenkins_dingtalk',
                type:'MARKDOWN',
                title: "success: ${JOB_NAME}",
                text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:latest\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
        
        failure {
            dingtalk (
                robot: 'jenkins_dingtalk',
                type:'MARKDOWN',
                title: "fail: ${JOB_NAME}",
                text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:latest\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
    }    
}

3.3、修改代码文件,测试