舍得
2022/04/23阅读:187主题:橙心
Jenkins Pipeline语法

目录
1、初识 Pipeline 核心语法

1.什么是 Pipeline


-
stage:流水线中的每一个阶段;
-
agent:流水线的运行节点;
-
jenkinsfile :以代码的方式描述流水线;Jenkins 在运行 Pipeline 任务的时候会按照 Jenkinsfile 中定义的代码顺序执行;
2.创建 Pipeline 作业
🍀 作业的项目类型
1.自由风格(图形化界面)被淘汰!

2.Pipeline (代码)

注意:
jenkinsfile解决的难点、通点是:一次改变,随处可用,便于流水线的管理和维护!
自由风格:全部都要在图形化界面上进行配置的。
Pipeline:以代码方式定义流水线。
使用场景:
例如目前有250个流水线项目,如果都是自由风格类型,现在有个需求,想对这所有的项目统一配置一个参数,该如何做呢?
1、自由风格类型(1.手动傻瓜式一个个项目做哈哈 2.如果可以,可调用api进行配置)
2、流水线类型 (直接修改jenkinsfile即可实现,一次改变,随处可用效果!)
学习完pipeline之后,你可以基于公司现有的流水线进行一些改造!
🍀 要想使用这个 Pipeline 作业类型首先要安装 Pipeline 插件

🍀 创建 Pipeline 作业方法

day2-pipeline-demo

全局的一些选项:

构建触发器:

流水线:
第一种方式:Pipeline script

第二种方式:Pipeline script from SCM

3.运行第一条 Pipeline

🍀 亲自测试
一个 pipeline 流水线无非就是如下几个动作 1、创建一个 Pipeline 流水线项目 2、编写 Jenkinsfile 文件 3、触发构建 4、调试
这里选择一个 Hello World 测试案例,点击保存:

构建:

验证:



一个简单的 demo 测试结束。😘
4.调试-Pipeline-回放

🍀 亲自测试


这里修改下上一次构建过的 jenkinsfile 代码:



测试结束。
🍀 注意:如果某次的构建失败了的话,那么本次回放是不可用的,即上次的代码会丢失!(注意:推荐在本地编辑器编辑代码,然后复制到回放中就好)


5.什么是 Jenkinsfile


1、Jenkinsfile-顶级块-pipeline{}

2、Jenkinsfile-二级块-agent{}

3、Jenkinsfile-二级块-options{}

也就是如下的配置:

4、Jenkinsfile-二级块-stages{}

:warning: 注意
Jenkinsfile 支持 声明式
和命令式
2 种方式来写代码,一般推荐使用声明式。如果把命令式代码写在了 steps 里面,有的命令会报错的,因此一般要写在 scriptP{}
里面;这样一来的话,Jenkinsfile 就由声明式代码,内嵌一部分命令式代码组成,更加增加了其灵活性;
5、Jenkinsfile-二级块-post{}

示例
-
案例代码如下
pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
script{
println("获取代码")
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
-
将案例代码拷贝到流水线里,然后保存,立即构建即可:

可以运行成功,但是有个问题:


-
我们再来使用 Blue Ocean
观察下现象:


测试结束。😘
2、Pipeline 开发工具

1.片段生成器

🍀 亲自测试
-
这里随便打开一个项目,点击 流水线语法
,点击片段生成器
:



-
这里来测试下,我们先来使用下 echo: Print Message
测试下

将生成的代码拷贝到源代码文件里:
pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
echo 'i love you ,xyy'
script{
println("获取代码")
echo 'i love you ,xyy'
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
此时,有个问题:我将这个echo 'i love you ,xyy'
语句分别写在 steps 和 script 里,那么等会构建下,是否会报错呢?

在上次构建地方,点击回放,将新代码拷贝进去,点击运行
,观察效果:

可以看到,会正常构建的:

-
此时,我们再选择 sh: Shell Script
,生成流水线脚本

此时,有个问题:我将这个sh 'ehco "i love you, hurt"''
语句分别写在 steps 和 script 里,那么等会构建下,是否会报错呢?
pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
echo 'i love you ,xyy'
sh 'echo "i love you,hurt"'
script{
println("获取代码")
echo 'i love you ,xyy'
sh 'echo "i love you,hurt"'
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}

在上次构建地方,点击回放,将新代码拷贝进去,点击运行
,观察效果:


可以看到,shell 命令放在 stage 里也是不会报错的。
🍀 总结
虽然有的 shell 命令放在 stage 里也不会报错的,但是为了代码的规范性及可读性,强烈建议将 shell 命令都放在 script 里!(有可能 if else 放在 stage 里可能会报错)

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
script{
println("获取代码")
echo 'i love you ,xyy'
sh 'echo "i love you,hurt"'
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
2.声明式语法生成器

🍀 示例
可以看到有很多 Sample Directive:

例如这里可以选择 agent: Agent


3.全局变量参考

🍀 示例
env 是全局变量的:


-
全局变量使用测试
我们来使用下BUILD_ID
这个全局变量下:

:warning: 注意:这里一定要使用双引号,否则会把其当做字符串打印出的!(linux 中单引号与双引号的区别)
pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
script{
println("获取代码")
echo 'i love you ,xyy'
echo "${BUILD_ID}"
echo "${env.BUILD_ID}"
echo "$BUILD_ID"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}

可以看到会构建成功:

🍀 创建全局变量并测试
我们首先将全局变量的定义放在stage
里面:

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
env.myName = "xyy"
script{
println("获取代码")
echo 'i love you ,xyy'
echo "${BUILD_ID}"
echo "${env.BUILD_ID}"
echo "$BUILD_ID"
echo "${myName}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
结果构建失败了:

此时,我们修改下代码,再把其放在 script 里面,看能否构建成功:

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
script{
env.myName = "xyy"
echo "${myName}"
println("获取代码")
echo 'i love you ,xyy'
echo "${BUILD_ID}"
echo "${env.BUILD_ID}"
echo "$BUILD_ID"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}

可以看到,本次构建成功,原来就是把命令式代码写在 stage 位置了,导致构建失败!因此也验证了上面的结论脚本式的语法我们都写在script里面
。
-
此时,有个问题:
刚才在检出代码阶段定义的全局变量,是否可以在构建阶段里面使用?这边来测试下

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
script{
env.myName = "xyy"
echo "${myName}"
env.branchName = "dev"
println("获取代码")
echo 'i love you ,xyy'
echo "${BUILD_ID}"
echo "${env.BUILD_ID}"
echo "$BUILD_ID"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}

结论:可以看到,在某一个 stage 里定义的全局变量,在其他 stage 里也是可以使用的!
🍀 示例:如何使用命令式语法来定义局部变量

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
//管道运行选项
options {
skipStagesAfterUnstable()
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
script{
envType = "test"
echo "envType: ${envType}"
env.myName = "xyy"
echo "${myName}"
env.branchName = "dev"
println("获取代码")
echo 'i love you ,xyy'
echo "${BUILD_ID}"
echo "${env.BUILD_ID}"
echo "$BUILD_ID"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
echo "envType: ${envType}"
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
进行构建:

结论:发现在 script 里定义的局部变量,在其他 stage 里也是可以使用的。。。😥 并且,也是可以在 stage 里引用局部变量的,也是不会报错的。
3、深入 Pipeline 核心语法

1.agent{}流水线运行节点


🍀 注意
none 情况:适合于流水线的阶段分布在不同的 agent 上运行;
还是指定节点这种方式用的多一些;
2.stages{}流水线阶段

3.post{}

🍀 注意
-
always:例如每次执行后清理缓存动作; -
success:执行成功后,也可触发下一动作,例如触发 CD;(远程构建) -
failure/aborted:可能要给开发人员发个邮件。
4.enironment{}环境变量

推荐:声明式语法里使用 enironment 这个语句块来写。
🍀 示例:全局变量测试
编写代码:

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
environment{
branchName = "dev"
version = "1.1.1"
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
steps{
script{
echo "${branchName}"
echo "${version}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
echo "${version}"
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
立即构建:构建成功。

🍀 示例:局部变量测试
编写如下代码:

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
environment{
branchName = "dev"
version = "1.1.1"
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
environment{
branchName = "test"
}
steps{
script{
echo "${branchName}"
echo "${version}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
echo "${version}"
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
运行:

注意:这里涉及到一个作用域问题,局部变量优先级高于全局变量。
5.options{}流水线运行时选项

🍀 注意:以上不用硬记的,需要用到时可以到声明式语法生成器
那里寻找就好


6.parameters{}参数化构建

🍀 示例:定义字符串参数和选项参数
在声明式语法生成器
里选择参数构建-字符串构建:

代码如下:

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
environment{
branchName = "dev"
version = "1.1.1"
}
parameters {
string defaultValue: '1.1.2', description: '版本号', name: 'VERSION', trim: true
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
environment{
branchName = "test"
}
steps{
script{
echo "${branchName}"
echo "${version}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
echo "${version}"
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
进行构建:


在配置这里也是可以看到参数化构建
的选项的:

-
我们再来定义下选项参数:


pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
environment{
branchName = "dev"
version = "1.1.1"
}
parameters {
string defaultValue: '1.1.2', description: '版本号', name: 'VERSION', trim: true
choice choices: ['prod', 'test', 'dev'], name: 'envType'
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
environment{
branchName = "test"
}
steps{
script{
echo "${branchName}"
echo "${version}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
echo "${version}"
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
构建:


-
参数定义好了,该如何引用呢?

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
environment{
branchName = "dev"
version = "1.1.1"
}
parameters {
string defaultValue: '1.1.2', description: '版本号', name: 'VERSION', trim: true
choice choices: ['prod', 'test', 'dev'], name: 'envType'
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
// environment{
// branchName = "test"
// }
steps{
script{
echo "${branchName}"
echo "${version}"
echo "${VERSION}"
echo "${env.VERSION}"
echo "${params.VERSION}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
echo "${version}"
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
构建:

-
我们再来测试下如下现象:

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
environment{
branchName = "dev"
// version = "1.1.1"
}
parameters {
string defaultValue: '1.1.2', description: '版本号', name: 'VERSION', trim: true
choice choices: ['prod', 'test', 'dev'], name: 'envType'
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
// environment{
// branchName = "test"
// }
steps{
script{
echo "${branchName}"
// echo "${version}"
echo "${VERSION}"
echo "${env.VERSION}"
echo "${params.VERSION}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
// echo "${version}"
}
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
构建:

结论:
如果同时有
environment
和parameters
时,env.VERSION
和VERSION
默认会使用 enironment 的值的,因此要想使用 parameters,推荐使用params.VERSION
来引用。这里需要注意下,大小写变量问题。
7.triggers{}触发器

🍀 注意


定时构建:例如代码扫描。
SCM 轮询构建:之前自由风格类型用的多,现在 pipeline 用的不多了,后面会讲一个更高级的工具。(xx webhook)
8.input{}触发器

🍀 示例
生成代码:


编写代码:

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
// triggers {
// cron 'H 11 * * *'
// }
environment{
branchName = "dev"
// version = "1.1.1"
}
parameters {
string defaultValue: '1.1.2', description: '版本号', name: 'VERSION', trim: true
choice choices: ['prod', 'test', 'dev'], name: 'envType'
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
// environment{
// branchName = "test"
// }
steps{
script{
echo "${branchName}"
// echo "${version}"
echo "${VERSION}"
echo "${env.VERSION}"
echo "${params.VERSION}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
// echo "${version}"
}
}
}
stage("deploy"){
input {
message '选择开发环境'
ok '提交'
parameters {
choice choices: ['dev', 'prod', 'test'], name: 'envName'
}
}
steps{
echo "deploy ${envName}"
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
构建:


以 BlueOcean 方式打开构建过程:


🍀 注意

9.when{}阶段运行控制

🍀 示例
编写代码:

pipeline{
//指定运行此流水线的节点
agent { node { label "build"}}
// triggers {
// cron 'H 11 * * *'
// }
environment{
branchName = "dev"
// version = "1.1.1"
}
parameters {
string defaultValue: '1.1.2', description: '版本号', name: 'VERSION', trim: true
choice choices: ['prod', 'test', 'dev'], name: 'envType'
}
//流水线的阶段
stages{
//阶段1 获取代码
stage("CheckOut"){
// environment{
// branchName = "test"
// }
steps{
script{
echo "${branchName}"
// echo "${version}"
echo "${VERSION}"
echo "${env.VERSION}"
echo "${params.VERSION}"
}
}
}
stage("Build"){
steps{
script{
println("运行构建")
echo "${branchName}"
// echo "${version}"
}
}
}
stage("deploy"){
when{
environment name: "branchName", value: "dev"
}
input {
message '选择开发环境'
ok '提交'
parameters {
choice choices: ['dev', 'prod', 'test'], name: 'envName'
}
}
steps{
echo "deploy ${envName}"
}
}
}
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
这里的自己现象:自己现象为什么和老师的不一样呢。。。😥


老师现象:

10.parallel{}阶段并行

🍀 示例
我们先来给 master 节点打个master
标签:

编写代码:

pipeline {
agent any
stages {
stage('Parallel Stage') {
failFast true
parallel {
stage('windows') {
agent {
label "master"
}
steps {
echo "windows"
}
}
stage('linux') {
agent {
label "build"
}
steps {
echo "linux"
}
}
}
}
}
}
构建:


关于我
我的博客主旨:我希望每一个人拿着我的博客都可以做出实验现象,先把实验做出来,然后再结合理论知识更深层次去理解技术点,这样学习起来才有乐趣和动力。并且,我的博客内容步骤是很完整的,也分享源码和实验用到的软件,希望能和大家一起共同进步!
各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人免费帮您解决问题:
-
个人微信二维码:x2675263825 (舍得), qq:2675263825。
image-20211002091450217 -
个人微信公众号:云原生架构师实战
image-20211002141739664 -
个人博客地址:www.onlyonexl.cn
image-20211002092057988 -
个人 csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421
image-20211002092344616 -
个人已开源干货 😘
不服来怼:宇宙中最好用的云笔记 & 其他开源干货:https://www.yuque.com/go/doc/73723298?#
image-20220423100718009
最后
好了,关于 Jenkins Pipeline 语法就到这里了,感谢大家阅读,最后贴上我女神的 photo,祝大家生活快乐,每天都过的有意义哦,我们下期见!

作者介绍