Pipeline 是什么

Jenkins Pipeline 实际上是基于 Groovy 实现的 CI/CD 领域特定语言(DSL),主要分为两类,一类叫做 Declarative Pipeline,一类叫做 Scripted Pipeline

Declarative Pipeline 体验上更接近于我们熟知的 travis CI 的 travis.yml,通过声明自己要做的事情来规范流程,形如:

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

而 Scripted Pipeline 则是旧版本中 Jenkins 支持的 Pipeline 模式,主要是写一些 groovy 的代码来制定流程:

node {
stage('Build') {
//
}
stage('Test') {
//
}
stage('Deploy') {
//
}
}

一般情况下声明式的流水线已经可以满足我们的需要,只有在复杂的情况下才会需要脚本式流水线的参与。

过去大家经常在 Jenkins 的界面上直接写脚本来实现自动化,但是现在更鼓励大家通过在项目中增加 Jenkinsfile 的方式把流水线固定下来,实现 Pipeline As Code,Jenkins 的 Pipeline 插件将会自动发现并执行它。

语法

Declarative Pipeline 最外层有个 pipeline 表明它是一个声明式流水线,下面会有 4 个主要的部分: agentpoststagessteps,我会逐一介绍一下。

Agent

agent 主要用于描述整个 Pipeline 或者指定的 Stage 由什么规则来选择节点执行。Pipeline 级别的 agent 可以视为 Stage 级别的默认值,如果 stage 中没有指定,将会使用与 Pipeline 一致的规则。在最新的 Jenkins 版本中,可以支持指定任意节点(any),不指定(none),标签(label),节点(node),dockerdockerfile 和 kubernetes 等,具体的配置细节可以查看文档,下面是一个使用 docker 的样例:

agent {
docker {
image 'myregistry.com/node'
label 'my-defined-label'
registryUrl 'https://myregistry.com/'
registryCredentialsId 'myPredefinedCredentialsInJenkins'
args '-v /tmp:/tmp'
}
}

Tips:

  • 如果 Pipeline 选择了 none,那么 stage 必须要指定一个有效的 agent,否则无法执行
  • Jenkins 总是会使用 master 来执行 scan multibranch 之类的操作,即使 master 配置了 0 executors
  • agent 指定的是规则而不是具体的节点,如果 stage 各自配置了自己的 agent,需要注意是不是在同一个节点执行的

Stages && Stage

Stages 是 Pipeline 中最主要的组成部分,Jenkins 将会按照 Stages 中描述的顺序从上往下的执行。Stages 中可以包括任意多个 Stage,而 Stage 与 Stages 又能互相嵌套,除此以外还有 parallel 指令可以让内部的 Stage 并行运行。实际上可以把 Stage 当作最小单元,Stages 指定的是顺序运行,而 parallel 指定的是并行运行。

接下来的这个 case 很好的说明了这一点:

pipeline {
agent none
stages {
stage('Sequential') {
stages {
stage('In Sequential 1') {
steps {
echo "In Sequential 1"
}
}
stage('In Sequential 2') {
steps {
echo "In Sequential 2"
}
}
stage('Parallel In Sequential') {
parallel {
stage('In Parallel 1') {
steps {
echo "In Parallel 1"
}
}
stage('In Parallel 2') {
steps {
echo "In Parallel 2"
}
}
}
}
}
}
}
}

除了指定 Stage 之间的顺序关系之外,我们还可以通过 when 来指定某个 Stage 指定与否:比如要配置只有在 Master 分支上才执行 push,其他分支上都只运行 build

stages {
stage('Build') {
when {
not { branch 'master' }
}
steps {
sh './scripts/run.py build'
}
}
stage('Run') {
when {
branch 'master'
}
steps {
sh './scripts/run.py push'
}
}
}

还能在 Stage 的级别设置 environment,这些就不展开了,文档里有更详细的描述。

Steps

steps 是 Pipeline 中最核心的部分,每个 Stage 都需要指定 Steps。Steps 内部可以执行一系列的操作,任意操作执行出错都会返回错误。完整的 Steps 操作列表可以参考 Pipeline Steps Reference,这里只说一些使用时需要注意的点。

  • groovy 语法中有不同的字符串类型,其中 'abc' 是 Plain 字符串,不会转义 ${WROKSPACE} 这样的变量,而 "abc" 会做这样的转换。此外还有 ''' xxx ''' 支持跨行字符串,""" 同理。
  • 调用函数的 () 可以省略,使得函数调用形如 updateGitlabCommitStatus name: 'build', state: 'success',通过 , 来分割不同的参数,支持换行。
  • 可以在声明式流水线中通过 script 来插入一段 groovy 脚本

Post

post 部分将会在 pipeline 的最后执行,经常用于一些测试完毕后的清理和通知操作。文档中给出了一系列的情况,比较常用的是 alwayssuccess 和 failure

比如说下面的脚本将会在成功和失败的时候更新 gitlab 的状态,在失败的时候发送通知邮件:

post {
failure {
updateGitlabCommitStatus name: 'build', state: 'failed'
emailext body: '$DEFAULT_CONTENT', recipientProviders: [culprits()], subject: '$DEFAULT_SUBJECT'
}
success {
updateGitlabCommitStatus name: 'build', state: 'success'
}
}

每个状态其实都相当于于一个 steps,都能够执行一系列的操作,不同状态的执行顺序是事先规定好的,就是文档中列出的顺序。

Shared Libraries

同一个 Team 产出的不同项目往往会有着相似的流程,比如 golang 的大部分项目都会执行同样的命令。这就导致了人们经常需要在不同的项目间复制同样的流程,而 Shared Libraries 就解决了这个问题。通过在 Pipeline 中引入共享库,把常用的流程抽象出来变成一个的指令,简化了大量重复的操作。

在配置好 lib 之后,Jenkins 会在每个 Pipeline 启动前去检查 lib 是否更新并 pull 到本地,根据配置决定是否直接加载。

所有的 Shared Libraries 都要遵循相同的项目结构:

(root)
+- src # Groovy source files
| +- org
| +- foo
| +- Bar.groovy # for org.foo.Bar class
+- vars
| +- foo.groovy # for global 'foo' variable
| +- foo.txt # help for 'foo' variable
+- resources # resource files (external libraries only)
| +- org
| +- foo
| +- bar.json # static helper data for org.foo.Bar

目前我们的使用比较低级,所以只用到了 vars 来存储全局的变量。

vars 下的每一个 foo.groovy 文件都是一个独立的 namespace,在 Pipeline 中可以以 foo.XXX 的形式来导入。比如我们有 vars/log.groovy

def info(message) {
echo "INFO: ${message}"
} def warning(message) {
echo "WARNING: ${message}"
}

那么 Jenkinsfile 中就可以这样调用:

// Jenkinsfile
steps {
log.info 'Starting'
log.warning 'Nothing to do!'
}

大家可能已经注意到了,在 groovy 文件中,我们可以直接像在 steps 中一样调用已有的方法,比如 echo 和 sh 等。

我们也能在 groovy 文件中去引用 Java 的库并返回一个变量,比如:

#!/usr/bin/env groovy
import java.util.Random; def String name() {
def rand = new Random()
def t = rand.nextInt()
return String.valueOf(t)
}

这样就能够在 JenkinsFile 中去设置一个环境变量:

// Jenkinsfile
environment {
NAME = random.name()
}

除了定义方法之外,我们还能让这个文件本身就能被调用,只需要定义一个 call 方法:

#!/usr/bin/env groovy

def call() {
sh "hello, world"
}

还能够定义一个新的 section,接受一个 Block:

def call(Closure body) {
node('windows') {
body()
}
}

这样可以让指定的 Body 在 windows 节点上调用:

// Jenkinsfile
windows {
bat "cmd /?"
}

常用技巧

发送邮件通知

主要使用 emailext,需要在 Jenkins 的配置界面事先配置好,可用的环境变量和参数可以参考文档 Email-ext plugin

emailext body: '$DEFAULT_CONTENT',  recipientProviders: [culprits(),developers()], subject: '$DEFAULT_SUBJECT'

结果同步到 gitlab

同样需要配置好 gitlab 插件,在 Pipeline 中指定 options

// Jenkisfile
options {
gitLabConnection('gitlab')
}

然后就可以在 post 中根据不同的状态来更新 gitlab 了:

// Jenkisfile
failure {
updateGitlabCommitStatus name: 'build', state: 'failed'
}
success {
updateGitlabCommitStatus name: 'build', state: 'success'
}

文档参考:Build status configuration

构建过程中可用的环境变量列表

Jenkins 会提供一个完整的列表,只需要访问 <your-jenkins-url>/env-vars.html/ 即可,别忘了需要使用 "${WORKSPACE}"

在 checkout 前执行自定义操作

在 Multibranch Pipeline 的默认流程中会在 checkout 之前和之后执行 git clean -fdx,如果在测试中以 root 权限创建了文件,那么 jenkins 会因为这个命令执行失败而报错。所以我们需要在 checkout 之前执行自定义的任务:

#!/usr/bin/env groovy

// var/pre.groovy
def call(Closure body) {
body()
checkout scm
}

在 Jenkinsfile 中配置以跳过默认的 checkout 行为:

// Jenkisfile
options {
skipDefaultCheckout true
}

在每个 stage 中执行自定义的任务即可:

// Jenkisfile
stage('Compile') {
agent any
steps {
pre {
sh 'pre compile'
}
sh 'real compile'
}
}

总结

Jenkins 作为使用最为广泛的 CI/CD 平台,网上流传着无数的脚本和攻略,在学习和开发的时候一定要从基本出发,了解内部原理,多看官方的文档,不要拿到一段代码就开始用,这样才能不会迷失在各式各样的脚本之中。

更重要的是要结合自己的业务需求,开发和定制属于自己的流程,不要被 Jenkins 的框架限制住。比如我们是否可以定义一个自己的 YAML 配置文件,然后根据 YAML 来生成 Pipeline,不需要业务自己写 Pipeline 脚本,规范使用,提前检查不合法的脚本,核心的模块共同升级,避免了一个流程小改动需要所有项目组同步更新。这是我现在正在做的事情,有机会再跟大家分享~

Jenkins Pipeline 参数详解的更多相关文章

  1. Jenkins pipeline 语法详解

    原文地址http://www.cnblogs.com/fengjian2016/p/8227532.html pipeline 是一套运行于jenkins上的工作流框架,将原本独立运行于单个或者多个节 ...

  2. 利用 Java 操作 Jenkins API 实现对 Jenkins 的控制详解

    本文转载自利用 Java 操作 Jenkins API 实现对 Jenkins 的控制详解 导语 由于最近工作需要利用 Jenkins 远程 API 操作 Jenkins 来完成一些列操作,就抽空研究 ...

  3. Nginx主配置参数详解,Nginx配置网站

    1.Niginx主配置文件参数详解 a.上面博客说了在Linux中安装nginx.博文地址为:http://www.cnblogs.com/hanyinglong/p/5102141.html b.当 ...

  4. iptables参数详解

    iptables参数详解 搬运工:尹正杰 注:此片文章来源于linux社区. Iptalbes 是用来设置.维护和检查Linux内核的IP包过滤规则的. 可以定义不同的表,每个表都包含几个内部的链,也 ...

  5. chattr的常用参数详解

    chattr的常用参数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在实际生产环境中,有的运维工程师不得不和开发和测试打交道,在我们公司最常见的就是部署接口.每天每个人部署的 ...

  6. mha配置参数详解

    mha配置参数详解: 参数名字 是否必须 参数作用域 默认值 示例 hostname Yes Local Only - hostname=mysql_server1, hostname=192.168 ...

  7. $.ajax()方法所有参数详解;$.get(),$.post(),$.getJSON(),$.ajax()详解

    [一]$.ajax()所有参数详解 url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. type: 要求为String类型的参数,请求方式(post或get)默认为get.注 ...

  8. linux PHP 编译安装参数详解

    linux PHP 编译安装参数详解 ./configure --prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc -- ...

  9. 【转】jqGrid 各种参数 详解

      [原文]http://www.cnblogs.com/younggun/archive/2012/08/27/2657922.htmljqGrid 各种参数 详解 JQGrid JQGrid是一个 ...

随机推荐

  1. python实现词云

    一.安装使用命令[pip install wordcloud]安装词云 二.参数使用了OpenCV的数据格式进行读取,字体可以多试几种 def create_wordcloud_pic(): stop ...

  2. Zookeeper的安装与配置、使用

    Dubbo的介绍 如果表现层和服务层是不同的工程,然而表现层又要调用服务层的服务,肯定不能像之前那样,表现层和服务层在一个项目时,只需把服务层的Java类注入到表现层所需要的类中即可,但现在,表现层和 ...

  3. Oracle 原生驱动带来的精度问题的分析与解决

    问题 Oracle 官方提供了 dotnet core 驱动,但我们在使用中遇到了精度问题. 复现 以下代码运行数学运算 1/3,无论是 OracleCommand.ExecuteScalar() 还 ...

  4. OWIN详细介绍

    1.OWIN.dll介绍 用反编译工具打开Owin.dll,你会发现类库中就只有一个IAppBuilder接口,所以说OWIN是针对.NET平台的开放Web接口. public interface I ...

  5. .Net捕获网站异常信息记录操作日志

    第一步:在Global.asax文件下的Application_Error()中写入操作日志 /// <summary> /// 整个网站出现异常信息,都会执行此方法 /// </s ...

  6. ORM:对象关系映射

    一.简单操作 定义:面向对象和关系型数据库的一种映射,通过操作对象的方式操作数据 对应关系: 类对应数据表 对象对应数据行(记录) 属性对应字段 导入:from app01 import models ...

  7. day10 作业

    猜年龄升级版 ''' 1. 可以直接玩猜年龄游戏,不需要登录 2. 登录成功后玩猜年龄游戏 3. 猜年龄猜中后,可以选择两次奖品 4. 注册的用户名不能重复注册 ''' import random p ...

  8. mysql_innodb存储引擎的优化

    采用innodb作为存储引擎时的优化 innodb_buffer_pool_size 如果用 Innodb,那么这是一个重要变量.相对于 MyISAM 来说,Innodb对于 buffer size ...

  9. 李宏毅-Network Compression课程笔记

    一.方法总结 Network Pruning Knowledge Distillation Parameter Quantization Architecture Design Dynamic Com ...

  10. Linux 动态链接库路径 LD_LIBRARY_PATH

    如果遇到一些 .so 缺失问题 把路径添加到这个变量里面就可以了,注意跟PATH的区别 export LD_LIBRARY_PATH= 注意使用 export 否则变量设置成功但是子进程不可见