1 认识Pipeline

1.1 Pipeline是什么?

  • Pipeline是Jenkins的核心功能,提供一组可扩展的工具。
  • 通过Pipeline 的DSL语法可以完成从简单到复杂的交付流水线实现。
  • jenkins的Pipeline是通过Jenkinsfile(文本文件)来实现的。
  • 这个文件可以定义Jenkins的执行步骤,例如检出代码。

1.2 Jenkinsfile

Jenkinsfile使用两种语法进行编写,分别是声明式和脚本式。

  • 声明式和脚本式的流水线从根本上是不同的。
  • 声明式是jenkins流水线更友好的特性。
  • 脚本式的流水线语法,提供更丰富的语法特性。
  • 声明式流水线使编写和读取流水线代码更容易设计。

1.3 为什么使用Pipeline?

本质上,jenkins是一个自动化引擎,它支持许多自动模式。流水线向Jenkins添加了一组强大的工具,支持用例、简单的持续集成到全面的持续交付流水线。 通过对一系列的发布任务建立标准的模板,用户可以利用更多流水线的特性,比如:

  • 代码化: 流水线是在代码中实现的,通常会存放到源代码控制,使团队具有编辑、审查和更新他们项目的交付流水线的能力。
  • 耐用性:流水线可以从Jenkins的master节点重启后继续运行。
  • 可暂停的:流水线可以由人功输入或批准继续执行流水线。
  • 解决复杂发布: 支持复杂的交付流程。例如循环、并行执行。
  • 可扩展性: 支持扩展DSL和其他插件集成。

构建一个可扩展是Jenkins的核心价值,流水线可以通过ShareLibrary的方式来扩展。

2 Pipeline定义

  • 一条流水线通过Jenkinsfile描述
  • 安装声明式插件Pipeline
  • DeclarativeJenkinsfile组成

1.  指定node节点/workspace

2. 指定指定运行选项

3. 指定stages阶段

4. 指定构建后操作

Pipeline有声明式和脚本式的语法,后面会用声明式嵌入脚本方式,通过sharelibary完善我们的jenkinfile

Pipeline基础语法_环境变量

2.1 agent/options

  • 指定node节点/workspace
  • 指定运行选项(可以忽略)

第一部分agent,agent指定的运行的节点,node可以以标签的方式指定节点,比如下面我这条流水线要运行在有master标签的节点上,然后工作目录这里做了自定义 

Pipeline基础语法_环境变量_02

比如排查什么时候运行失败的,会在日志里面打印时间,使用timestamps需要安装插件Timestamper

跳过默认的checkout,声明式的脚本默认会检查有没有配置代码库,如果有的话可以自动的帮你下载,但是没必要下载,所以跳过

有些时候项目不需要并行

有时候流水线的构建会超时了,一直卡在那,这样会消耗大量的资源,而且会占用构建队列。

所以这里要设置流水线的超时时间,超时时间的流水线会自动结束

2.2 stages

Pipeline基础语法_Jenkins_03

steps是步骤,一般stages下面都有steps,这个步骤超时时间是5分钟,然后嵌入一个脚本打印信息

2.3 post

构建后的操作,这个非常的重要,这是固定的格式,可以按照这个代码块模板去写,比如成功失败了发个邮件通知

Pipeline基础语法_Groovy_04

这里current是全局的变量

写代码可以用好多变量,可以自己去定义变量,也可以使用jenkins的全局变量

上面是一个完整的流水线

3 声明式Pipeline

声明式Pipleine是最近添加到Jenkins流水线的,它在流水线子系统之上提供了一种更简单,更有主见的语法。 所有的声明式Pipeline都必须包含一个 pipeline块中,比如:

pipeline {
    //run
}
在声明式Pipeline中的基本语句和表达式遵循Groovy的语法。但是有以下例外:
· 流水线顶层必须是一个块,特别是pipelin{}。
· 不需要分号作为分割符,是按照行分割的。
· 语句块只能由阶段、指令、步骤、赋值语句组成。例如: input被视为input()。

样例

pipeline {
  agent any
  stages {
    stage('Example') {
      steps {
        echo 'Hello World'
      }
    }
  }
  post {
    always {
      echo 'I will always say Hello again!'
    }
  }
}

3.1 agent(代理)

agent 指定了流水线的执行节点。
参数:
· any 在任何可用的节点上执行pipeline。
· none 当pipeline全局指定agent为none,则根据每个stage中定义的agent运行(stage必须指定)。
· label 在指定标签上的节点上运行Pipeline。
· node 允许额外的选项。

这两种是一样的
agent { node { label 'labelname' }}
aget { label 'labelname'}

Jenkins本机的默认标签
"'Jenkins' doesn’t have label 'master'"
agent { node {  label "master" } }
新版本jenkins将master node改成了built-in node,
agent { node {  label "built-in" } }

Pipeline基础语法_Jenkins_05

3.2 stages(阶段)

包含一系列一个或多个 stage 指令, 建议 stages 至少包含一个 stage 指令用于连续交付过程的每个离散部分,比如构建, 测试, 和部署。

3.3 steps(步骤)

step是每个阶段中要执行的每个步骤。

3.4 post

定义一个或多个steps ,这些阶段根据流水线或阶段的完成情况而 运行(取决于流水线中post部分的位置). post 支持以下 post-condition 块中的其中之一: always, changed, failure, success, unstable, 和 aborted。这些条件块允许在 post 部分的步骤的执行取决于流水线或阶段的完成状态。

  • always 无论流水线或者阶段的完成状态。
  • changed 只有当流水线或者阶段完成状态与之前不同时。
  • failure 只有当流水线或者阶段状态为”failure”运行。
  • success 只有当流水线或者阶段状态为”success”运行。
  • unstable 只有当流水线或者阶段状态为”unstable”运行。例如:测试失败。
  • aborted 只有当流水线或者阶段状态为”aborted “运行。例如:手动取消。

注意post可以写到stage里面,那么就是针对于某个阶段了,如果写在pipeline里面那么就是全局的,是针对整个流水线的状态,里面script不一定要写,但是运行了脚本方式的语法最好带上。


什么时候在stage里面写post?比如构建maven项目在单元测试之后,会产生一个报告,也就是单元测试成功之后可以将这个报告展示在jenkins上面,失败了就可以不让她展示了


在post always里面可以清理项目的空间,比如删除workspace的空间,在always里面的sript里面加入shell清理worksapce空间

3.5 指令

3.5.1 environment

environment 指令指定一个键值对序列,该序列将被定义为所有步骤的环境变量,或者是特定于阶段的步骤,这取决于 environment 指令在流水线内的位置。

该指令支持一个特殊的方法 credentials() ,该方法可用于在Jenkins环境中通过标识符访问预定义的凭证。对于类型为 "Secret Text"的凭证, credentials() 将确保指定的环境变量包含秘密文本内容。对于类型为 "SStandard username and password"的凭证, 指定的环境变量指定为 username:password ,并且两个额外的环境变量将被自动定义 :分别为 MYVARNAME_USR 和 MYVARNAME_PSW 。

pipeline {
  agent any
  environment { 
    CC = 'clang'
  }
  stages {
    stage('Example') {
      environment { 
        SECRET_TEXT_KEY = credentials('869f9770-0467-496a-84f9-d7b2c729fd8f')
        USER_PASS_KEY = credentials('8c8a0774-7d4c-48a9-8f52-dd1a04f71320')
      }
      steps {
        sh 'printenv'
        sh 'echo $USER_PASS_KEY_USR : $USER_PASS_KEY_PSW'
      }
    }
  }
}

Pipeline基础语法_Jenkins_06

3.5.2 options

options 指令允许从流水线内部配置特定于流水线的选项。 流水线提供了许多这样的选项, 比如buildDiscarder,但也可以由插件提供, 比如 timestamps。

  • buildDiscarder: 为最近的流水线运行的特定数量保存组件和控制台输出。
  • disableConcurrentBuilds: 不允许同时执行流水线。 可被用来防止同时访问共享资源等。
  • overrideIndexTriggers: 允许覆盖分支索引触发器的默认处理。
  • skipDefaultCheckout: 在agent 指令中,跳过从源代码控制中检出代码的默认情况。
  • skipStagesAfterUnstable: 一旦构建状态变得UNSTABLE,跳过该阶段。
  • checkoutToSubdirectory: 在工作空间的子目录中自动地执行源代码控制检出。
  • timeout: 设置流水线运行的超时时间, 在此之后,Jenkins将中止流水线。
  • retry: 在失败时, 重新尝试整个流水线的指定次数。
  • timestamps 预测所有由流水线生成的控制台输出,与该流水线发出的时间一致。
//指定一个小时的全局执行超时, 在此之后,Jenkins将中止流水线运行。
pipeline {
  agent any
  options {
    timeout(time: 1, unit: 'HOURS') 
  }
  stages {
    stage('Example') {
      steps {
        echo 'Hello World'
      }
    }
  }
}

3.6 参数

为流水线运行时设置项目相关的参数
string 字符串类型的参数, 例如:
parameters {
  string defaultValue: 'qingchen', description: '#this is a string parameter', name: 'name'
}
booleanParam 布尔参数, 例如:
parameters {
  booleanParam defaultValue: true, description: 'this is a boolean parameter', name: 'isOK'
}
选项参数
parameters {
  choice choices: ['dev', 'test', 'main'], description: 'this is a choice parameter', name: 'buildEnv'
}

示例
pipeline {
  agent any
  parameters {
    string defaultValue: 'qingchen', description: '#this is a string parameter', name: 'name'
  }
  stages {
    stage('Example') {
	  steps {
	    echo "this build name is ${name}"
	  }
	}
  }
}

第一遍执行失败,第二遍自动将参数添加到参数化构建中,执行成功

Pipeline基础语法_环境变量_07

3.7 触发器

构建触发器
cron 计划任务定期执行构建。
triggers {
  cron 'H */4 * * 1-5'
}
pollSCM 与cron定义类似,但是由jenkins定期检测源码变化。
triggers {
  pollSCM 'H */4 * * 1-5'
}
upstream 只有构建稳定时触发。
triggers {
  upstream 'job1,job2'
}

示例
pipeline {
  agent any
  triggers {
    cron 'H */4 * * 1-5'
  }
  stages {
    stage('Example') {
	    steps {
	      echo 'Hello World'
	    }
	  }
  }
}

3.8 tool

获取通过自动安装或手动放置工具的环境变量。支持maven/jdk/gradle。
工具的名称必须在系统设置->全局工具配置中定义。
tools {
  maven 'maven3.6.2'
}

示例:
pipeline {
  agent any
  tools {
    maven 'maven3.6.2'
  }
  stages {
    stage('Example') {
	    steps {
	      sh 'mvn --version'
	    }
	  }
  }
}

3.9 input

input用户在执行各个阶段的时候,由人工确认是否继续进行。

  • message 呈现给用户的提示信息。
  • id 可选,默认为stage名称。
  • ok 默认表单上的ok文本。
  • submitter 可选的,以逗号分隔的用户列表或允许提交的外部组名。默认允许任何用户。
  • submitterParameter 环境变量的可选名称。如果存在,用submitter 名称设置。
  • parameters 提示提交者提供的一个可选的参数列表。
示例:
pipeline {
  agent any
  stages {
    stage('Example') {
	    input {
          message 'Should we continue?'
          ok 'Yes, we should.'
          submitter 'alice,bob'
          parameters {
            string defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?', name: 'PERSON'
          }
      }
	    steps {
	      echo "Hello, ${PERSON}, nice to meet you."
	    }
	  }
  }
}

Pipeline基础语法_Groovy_08

3.10 when

when 指令允许流水线根据给定的条件决定是否应该执行阶段。 when 指令必须包含至少一个条件。 如果when 指令包含多个条件, 所有的子条件必须返回True,阶段才能执行。 这与子条件在 allOf 条件下嵌套的情况相同。

内置条件
branch: 当正在构建的分支与模式给定的分支匹配时,执行这个阶段,这只适用于多分支流水线例如:
when {
  branch 'mater'
}
environment: 当指定的环境变量是给定的值时,执行这个步骤,例如:
when {
  environment name: 'DEPLOY_TO', value: 'production'
}
not 当嵌套条件是错误时,执行这个阶段,必须包含一个条件,例如:
when {
  not {
    branch 'master'
  }
}
allOf 当所有的嵌套条件都正确时,执行这个阶段,必须包含至少一个条件,例如:
when {
  allOf {
    branch 'master'
    environment name: 'DEPLOY_TO', value: 'production'
  }
}
anyOf 当至少有一个嵌套条件为真时,执行这个阶段,必须包含至少一个条件,例如:
when {
  allOf {
    branch 'master'
    environment name: 'DEPLOY_TO', value: 'production'
  }
}

示例:
pipeline {
  agent any
  stages {
    stage('Example Build') {
      steps {
        echo 'Hello World'
      }
    }
    stage('Example Deploy') {
      when {
        allOf {
          branch 'production'
          environment name: 'DEPLOY_TO', value: 'production'
        }
      }
      steps {
        echo 'Deploying'
      }
    }
  }
}

3.11 parallel并行

声明式流水线的阶段可以在他们内部声明多隔嵌套阶段, 它们将并行执行。 注意,一个阶段必须只有一个 steps 或 parallel的阶段。 嵌套阶段本身不能包含 进一步的 parallel 阶段, 但是其他的阶段的行为与任何其他 stageparallel的阶段不能包含 agent 或 tools阶段, 因为他们没有相关 steps。

另外, 通过添加 failFast true 到包含parallel的 stage中, 当其中一个进程失败时,你可以强制所有的 parallel 阶段都被终止。

示例:
pipeline {
  agent any
  stages {
    stage('Non-Parallel Stage') {
      steps {
        echo 'This stage will be executed first.'
      }
    }
    stage('Parallel Stage') {
      when {
        branch 'master'
      }
      failFast true
      parallel {
        stage('Branch A') {
          agent {
            label "for-branch-a"
          }
          steps {
            echo "On Branch A"
          }
        }
        stage('Branch B') {
          agent {
            label "for-branch-b"
          }
          steps {
            echo "On Branch B"
          }
        }
      }
    }
  }
}

3.12 step步骤

script

script 步骤需要 [scripted-pipeline]块并在声明式流水线中执行。对于大多数用例来说,应该声明式流水线中的“脚本”步骤是不必要的,但是它可以提供一个有用的”逃生出口”。非平凡的规模和/或复杂性的script块应该被转移到 共享库 。

示例:
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"
      	  }
      	}
      }
    }
  }
}

Pipeline基础语法_环境变量_09

脚本化Pipeline

脚本化流水线, 与声明式一样的是, 是建立在底层流水线的子系统上的。与声明式不同的是, 脚本化流水线实际上是由 Groovy构建的通用 DSL 。 Groovy 语言提供的大部分功能都可以用于脚本化流水线的用户。这意味着它是一个非常有表现力和灵活的工具,可以通过它编写持续交付流水线。

4.1 流程控制

脚本化流水线从Jenkinsfile的顶部开始向下串行执行, 就像 Groovy 或其他语言中的大多数传统脚本一样。
因此,提供流控制取决于 Groovy 表达式, 比如 if/else 条件, 例如:
node {
  stage('Example') {
    if (env.BRANCH_NAME == 'master') {
      echo 'I only execute on the master branch'
    } else {
      echo 'I execute else where'
    }
  }
}
另一种方法是使用Groovy的异常处理支持来管理脚本化流水线流控制。
当步骤失败 ,无论什么原因,它们都会抛出一个异常。
处理错误的行为必须使用Groovy中的 try/catch/finally 块 , 例如:
node {
  stage('Example') {
    try {
      sh 'exit 1'
    }
    catch (exc) {
      echo 'Something failed, I should sound the klaxons!'
      throw
    }
  }
}