备注:由于我不是专职的devops工程师,所以学习jenkins本着够用的原则即可。但作为一个高级软件工程师,学会写pipeline是必须的。

pipeline翻译成流水线,在Unix/Linux系统中经常用到,Pipeline将一个命令/程序/进程的输出发送到另一个命令/程序/进程,以进行进一步处理。比如:cat test.txt | grep test1。Jenkins 中的Pipeline借用了Unix/Linux中的 Pipeline思路,实现像流水线一样来调度Jenkins任务,通过Jenkinsfile来描述整个持续集成流程。

Jenkinsfile就是描述pipeline的脚本文件。

pipeline支持两种语法:声明式Declarative和脚本式,声明式比较简单,也基本满足我们的需求,所以非专业人事建议学习声明式语法即可。

Scripted pipeline - 脚本式流水线语法,基于 Groovy语言构建的通用 DSL(Domain-specific language,领域特定语言)
Declarative pipeline - 声明式流水线语法,在v2.5之后引入,支持结构化方式,提供了更丰富的语法特性。

声明式语法包括以下核心流程:

1.pipeline : 声明其内容为一个声明式的 pipeline 脚本

2.agent: 执行节点(job 运行的 slave 或者 master 节点)

3.stages: 阶段集合,包裹所有的阶段(例如:编译,打包,部署等各个阶段)

4.stage: 阶段,被 stages 包裹,一个 stages 可以有多个 stage,但至少要有一个

5.steps: 步骤,为每个阶段的最小执行单元,被 stage 包裹

6.post: 执行构建后的操作,根据构建结果来执行对应的操作

一个最基本的声明式 pipeline框架如下:

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                echo 'Building..'
            }
        }
        stage('Test') {
            steps {
                echo 'Testing..'
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying....'
            }
        }
    }
}

声明式流水线语法必须包含在一个 pipeline块内:

pipeline { 
	/* Declarative Pipeline */
}

pipeline块中主要由Sections, Directives, Steps, 或者赋值语句组成。

Sections
Sections包括agent、stages、steps和post。

agent

agent定义 pipeline执行节点。agent定义在顶层pipeline下叫全局agent。也可以为stage指定agent。

主要参数:

  • any:可以在任意可用的 agent上执行pipeline
  • none:pipeline将不分配全局agent,每个 stage必须分配自己的agent
  • label:指定运行节点agent的 Label

agent { label 'my-defined-label' }

label支持条件语法:
agent { label 'my-label1 && my-label2' } or agent { label 'my-label1 || my-label2' }

这个label要来自jenkins的配置,例如公司里有很多台服务器,我们可以给服务器贴标签,用指定的服务器干指定的事。

点击左下角执行器状态可以对执行器进行配置:

jenkins声明式流水线 gitParameter和extendedchoice jenkins pipeline支持声明式语法_学习

有比较多的有用配置,可以配置服务器有多少个执行器,服务器的label,添加环境变量等。

jenkins声明式流水线 gitParameter和extendedchoice jenkins pipeline支持声明式语法_docker_02

  • node:自定义运行节点配置,
  • 指定 label
  • 指定 customWorkspace
  • docker:使用给定的容器执行流水线。
agent {
    docker {
        image 'maven:3.8.1-adoptopenjdk-11'
        label 'my-defined-label'
        args  '-v /tmp:/tmp'
    }
}
agent {
    docker {
        image 'myregistry.com/node'
        label 'my-defined-label'
        registryUrl 'https://myregistry.com/'
        registryCredentialsId 'myPredefinedCredentialsInJenkins'
    }
}
  • dockerfile:使用源码库中包含的Dockerfile构建的容器来执行Pipeline。
    比较少用,因为每次都要构建docker有点浪费时间。
  • kubernetes:在kubernetes集群执行Pipeline
    上述参数也可以用于stage中。

示例脚本:

pipline {
    agent {
        node {
            label "myslave"
            customWorkspace "myWorkspace"
        }
    }
}

为stage指定agent示例:

pipeline {
    agent none 
    stages {
        stage('Example Build') {
            agent { docker 'maven:3.8.1-adoptopenjdk-11' } 
            steps {
                echo 'Hello, Maven'
                sh 'mvn --version'
            }
        }
        stage('Example Test') {
            agent { docker 'openjdk:8-jre' } 
            steps {
                echo 'Hello, JDK'
                sh 'java -version'
            }
        }
    }
}

stages

包含一个或多个 stage, Pipeline的大部分工作在此执行。stages也是必须指定的指令没有参数。此外,每个 pipeline块中必须只有一个 stages。

stages里至少要有一个stage

stage

需要定义stage的名字:

pipeline {
    agent any
    stages {
        stage('init') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
steps

steps位于stage块中,也是必须设置的指令,无参数。

steps块中可以包含script块,可用于存放Scripted Pipeline 脚本:

pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'

                script {
                    def browsers = ['chrome', 'firefox']
                    for (int i = 0; i < browsers.size(); ++i) {
                        echo "Testing the ${browsers[i]} browser"
                    }
                }
            }
        }
    }
}

jenkins的插件提供了许多有用的steps,查阅https://www.jenkins.io/doc/pipeline/steps/,我们就常写的steps就是执行shell命令,
可以使用sh 'shell语句'的方式。

例如我们要执行编译:sh 'make'

post

post是在Pipeline或者 stage执行结束后的操作,不是必须出现的指令。
也就是说,post可以放在pipeline里,那么会在整个pipeline结束后运行;放在特定的stage里,就会在该stage结束后运行。

可设置以下触发条件:

  • always:无论 Pipeline或者stage运行完成的状态如何都会运行
  • changed:只有当前 Pipeline或者stage运行的状态与先前运行状态不同时才能运行
  • fixed:只有当前一次构建失败或者不稳定,而当前 Pipeline或者stage运行成功时运行
  • regression:前一次运行成功,而当前Pipeline或者stage运行状态为failure, unstable 或者 aborted时运行
  • aborted:只有当前 Pipeline或者stage处于“aborted”状态时才能运行。通常是手动终止。
  • failure:当前 Pipeline或者stage处于“failed”状态时才运行
  • success:当前 Pipeline或者stage具有“success”状态时才运行
  • unstable:当前 Pipeline或者stage具有“unstable”状态才运行
  • unsuccessful:当前 Pipeline或者stage不是“success”状态时运行
  • cleanup:不管Pipeline或stage的状态如何,在每一个post条件被执行之后运行。
    示例脚本:
pipeline {
    agent any
    stages {
        stage('init') {
            steps {
                echo 'Hello World'
            }
        }
    }
    post {
        success {
            echo 'success!'
            sleep 2        
        }

        always {
            echo 'goodbye'
        }
    }
}

典型pipeline框架参考

一个基本的CI流程:

jenkins声明式流水线 gitParameter和extendedchoice jenkins pipeline支持声明式语法_jenkins_03

下面这个pipeline能满足绝大数场景需求了:

pipeline {
    agent any 
    stages {
        stage('Build') { 
            steps {
                // 
            }
        }
        stage('Test') { 
            steps {
                // 
            }
        }
        stage('Deploy') { 
            steps {
                // 
            }
        }
    }
    post {
    	success {
    	}
    	failure{ 
    	}
	}
}

参考:https://www.jenkins.io/doc/book/pipeline/syntax/