一.简介

都是在推送代码后,再切换到Jenkins界面,手动点击构建。显然不够自动化,应该让每次代码变动后,就自动进行构建才对。对于pipeline触发条件,一般从时间触发和事件触发。

二.时间触发

时间触发是指定义一个时间,时间到了就触发pipeline执行。在pipeline中,使用trigger指令来定义时间触发,只能定义在pipeline块下。支持cron pollSCM upstream三种方式。其它方式可以通过插件来实现。

定时触发

定时执行就像cronjob,一到时间点就执行。它的使用场景通常是执行一些周期性的job,比如每晚构建。

pipeline {
    agent any
    triggers {
        cron('0 0 * * *')
    }
    stages {
        stage('Nightly build') {
            steps {
                echo "这是一个耗时的构建,每天凌晨执行"
            }
        }
    }
}

Jenkins tigger cron语法采用UNIX cron语法(有细微差别)。一条cron包含5个字段,使用空格或者Tab分隔,格式为:分,时,日,月,周

  • MINUTE:一小时内的分钟,取值范围为0~59
  • HOUR:一天内的小时,0~23
  • DOM:一个月的某几天,1~31
  • MONTH:月份,取值1~12
  • DOW:星期几,取值0~7 0和7代表周日

还可以使用以下特殊字符,一次性指定多个值

  • *匹配所有
  • M-N,匹配M到N之间的值
  • M-N/X or */x  指定到N范围内,以X值为步长
  • A,B,...,Z 使用逗号枚举多值

在一些大型组织中,会同时存在大量的同一时刻执行的定时任务,比如N个半夜零点 0 0 * * * 执行的任务。这样会产生负载不均衡。在Jenkins tigger cron语法中使用H字符来解决这一问题,H代表hash。对于没必要精确到零点0分执行的任务,cron可以这样写: H 0 * * *,代表零点0分支59分之前任何一个时间点执行。

需要注意的是,H应用在DOM,一个月的某一天字段时会有不准确的情况,因为10月有31天,而2月却是28天。

Jenkins trigger cron还设计了一些人性化的别名:@yearly、@annually、@monthly、@weekly、@daily、@midnight和@hourly。

例如@hourly与 H * * * *相同,代表一小时内的任何时间;@midnight实际上代表在半夜12:00到凌晨2:59之前的某个时间。其它别名很少有应用场景。

轮询代码仓库

轮询代码仓库是指定期到代码仓库询问代码是否有变化,如果有变化就执行。有读者会问:那多久轮询一次?笔者的回答是:越频繁越好。

因为构建的间隔时间越长,在一次构建内就可能会包含多次代码提交。当构建失败时,你无法马上知道那一次代码提交导致了构建失败。总之,越不频繁集成,得到的持续集成的好就越少。

triggers {

    pollSCM('H/1 * * * *')

}

这种一般用于特殊情况,比如外网的代码仓库无法调用内网的jenkins。则需要用这种方式。

三.事件触发

事件触发就是发生了某个事件就触发pipeline执行,这个事件可以是你能想到的任何事件,比如手动在界面上触发、其它job主动触发、HTTP API Webhook触发等。

由上游任务触发

当B任务的执行依赖A任务的执行结果时,A就被称为B的上游任务。

在Jenkins 2.22及以上版本中,trigger指令开始支持upstream类型的触发条件。upstream的作用就是能让B pipeline自行决定依赖哪些上游任务。

triggers {
    upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS)
}

当upstreamProjects参数接收多个任务时,使用逗号分隔。threshold参数是指上游任务的执行结构是什么值时触发。hudson.model.Result是一个枚举,包括以下值:

  • ABORTED 任务被手动中止
  • FAILURE 构建失败
  • SUCCESS 构建成功
  • UNSTABLE 存在一些错误,但不至于构建失败
  • NOT_BUILT 在多阶段构建时,前面阶段的问题导致后面阶段无法执行

注意:这种需要手动构建当前任务一次,让jenkins加载pipeline后,trigger指令才生效

gitlab通知触发

gitlab通知触发是指当gitlab发现源代码有变化时,触发jenkins执行构建。

由gitlab主动通知进行构建的好处是显而易见的,这样很容易就解决了我们之前提到的轮询代码仓库时“多久轮询一次”的问题,实现每一次代码变化都对应一次构建。

1.安装jenkins插件

安装Generic Webhook Trigger Plugin、git、Gitlab API Plugin、GitLab Plugin插件,注意不是gitlab hook插件(已废弃)

2.在gitlab创建一个项目,test-a,地址http://1.1.1.1/book/test-a

3.在jenkins上创建pipelien项目,可以同名称test-a。正常在不使用pipeline进行这个触发配置的时候,也可以用页面进行配置,勾选相当于开始接收外界发来的请求。

这里要注意,上面标注的URL是固定输出的信息,实际项目地址要看WEB栏,这个才是真实地址的

4.生成个人API的Token,用于安全验证

5.在gitlab项目的设置里,配置钩子

URL填入如下

http://账号名:刚才生成的Token@Jenkins的地址/job/test-a/build?job=test-a&token=随机写个项目token,这里随便打

URL直接粘贴了我的

http://zhuhaoran:119db4649f157c0a25f7d2b541d3f4d7da@10.0.12.9:8080/job/test-a/build?job=test-a&token=t8vcxwuza023ehzcftzr5a74vkpto6xr

现在网络上可能有各种配置,可能老版本适用,但我用的2.220就各种用不了,最后从官网找到这个能用的配置。

为什么这么配置:

gitlab代码有更新,就会通过上面这个url,将一些请求和相关内容通过post方式传给Jenkins。Jenkins发现你的test-a项目开启了这个触发功能,就会根据pipeline的配置进行相应处理,符合条件后就会触发执行。

如果只粘贴Jenkins web配置中显示的地址+Token,会报错403问题。这是因为如果没指定账号密码,gitlab只能通过匿名用户去访问Jenkins去传参。

但现在大多全局安全配置里,是Role-Based Strategy插件方式管理的

往上都说403要这样,我感觉是真的蠢,这样会不安全,而且插件管理和这个只能选择一个。

6.编写pipeline,要保存执行一下这个job让配置生效,具体的参数含义在末尾

pipeline {
agent any triggers {
gitlab(triggerOnPush: true,
triggerOnMergeRequest: true,
branchFilterType: "All",
secretToken: "t8vcxwuza023ehzcftzr5a74vkpto6xr")
} stages {
stage('pull') {
steps {
echo '拉取代码'
}
}
}
}

会发现这里自动勾上了,这是因为pipeline其实就是配置的这个选项,但版本化管理会更好。

7.在gitlab上点击一下触发,看是否jenkins job被触发了

8.然后在gitlab项目中,随意修改个文件,看是否也能自动触发

9.参数含义

triggerOnPush: 当Gitlab触发push事件时,是否执行构建

triggerOnMergeRequest: 当Gitlab触发mergeRequest事件时,是否执行构建

branchFilterType: 只有符合条件的分支才会触发构建,必选,否则无法实现触发。
All: 所有分支
NameBasedFilter: 基于分支名进行过滤,多个分支名使用逗号分隔
includeBranchesSpec: 基于branchFilterType值,输入期望包括的分支的规则
excludeBranchesSpec: 基于branchFilterType值,输入期望排除的分支的规则
RegexBasedFilter: 基于正则表达式对分支名进行过滤
sourceBranchRegex: 定义期望的通过正则表达式限制的分支规则 secretToken: 指定这个job_name的token验证字符

如果只允许master分支push后才触发,就如下配置,token使用了全局变量,这样多个项目都可以用一个token,比较方便(内网比较适合)

triggers {
gitlab(triggersOnPush: true,
triggersOnMergeRequest: true,
branchFilterType: "NameBasedFilter",
includeBranchesSpec: "master",
secretToken: "${env.git_token}")
}

用正则匹配,适合对分支号进行规则定义的项目

triggers {
gitlab(triggersOnPush: true,
triggersOnMergeRequest: true,
branchFilterType: "RegexBasedFilter",
sourceBranchRegex: "dev.*",
secretToken: "${env.git_token}")
}

四.通用触发接口

GWT

前文中,我们讲到安装GitLab插件后,GitLab系统就可以发送Webhook触发Jenkins项目的执行。那是不是说其他系统想触发Jenkins项目执行,也需要找一个插件或者开发一个插件来实现呢?

有了Generic Webhook Trigger插件就不需要了,安装Generic Webhook Trigger插件(下文使用GWT简称)后, Jenkins会暴露一个API: <JENKINS URL>/generic-webhook-triggerlinvoke,即由GWT插件来处理此API的请求。

GWT插件接收到JSON或XML的HTTP POST请求后,根据我们配置的规则决定触发哪个Jenkins项目。下面我们先感受一下,然后再详细介绍GWT各参数的含义,现在我们创建一个普通的pipeline项目。

代码如下:

pipeline {
agent any
triggers {
GenericTrigger(
genericVariables:[
[key: 'ref', value: '$.ref']
],
token:'secret',
causeString: 'Triggered on $ref',
printContri butedVariables: true,
printPostContent: true
)
}
stages {
stage('Some step') {
steps {
sh "echo $ref"
sh "printenv"
}
}
}
}

执行一次job后才会生效,然后发起一次HTTP POST请求

curl -X POST -H "Content-Type: application/json" -d '{ "ref": "refs/heads/master" }' -vs http://192.168.23.11:8667/jenkins/generic-webhook-trigger/invoke?token=secret

接着,我们就看到pipeline被触发执行了。日志如下:

Triggered on refs/heads/master
省略git操作细节部分
Seen branch in repository origin/dev
Seen branch in repository origin/ master
Seen 2 remote branches Obtained Jenkinsfile from 6b2c6a36ac5fade7448596a5fc67ee33be4bab95
Running in Durability level: MAX_ SURVIVABILITY
Generi cWebhookEnvironmentContributor
Received :
{ "ref": "refs/heads/master" }
Contributing variables:
ref = refs/heads/master

GenericTrigger触发条件由GWT插件提供。此触发条件可以说是GWT的所有内容。将GenericTrigger触发条件分为5部分,这样更易于理解各参数的作用。

  • 从HTTP POST请求中提取参数值
  • token,GWT插件用于标识Jenkins项目的唯一性
  • 根据请求参数值判断是否触发Jenkins项目的执行
  • 日志打印控制
  • Webhook响应控制

提取参数

一个HTTP POST请求可以从三个维度提取参数,即POST body、URL参数和header。

GWT插件提供了三个参数分别对这三个维度的数据进行提取。

  1. genericVariables :提取POST body中的参数。
genericVariables:[
[key: 'ref', value: '$.ref'] ,
[key: 'before'
value: ' $.before',
expressionType:' JSONPath
regexpFilter:
defaultValue:
]
]
  • value: JSONPath表 达式,或者XPath 表达式,取决于expressionType参数值,用于从POST body中提取值。
  • key :从POST body中提取出的值的新变铭,可用于pipeline其他步骤。
  • expressionType :可选, value的表达式类型, 默认为JSONPath。当请求为XML内容时,必须指定XPath值。
  • defaultValue:可选,当提取不到值,且defaultValue不为空时,则使用defaultValue作为返回值。
  • regexpFilter :可选,过滤表达式,对提取出来的值进行过滤。其实就是string.replaceAll ( regexpFilter ,"");。string是从HTTP请求中提取出来的值。

2.genericRequestVariables :从URL参数中提取值。

  • key :提取出的值的新变量名,可用于pipeline其他步骤。
  • regexpFilter :对提取出的值进行过滤。

3.genericHeaderVariables :从HTTP header中提取值。

genericHeaderVariables的用法与genericRequestVariables-样,区别是它是从HTTP header中提取值的。

触发某个具体项目

上面可以看到GenericTrigger方法有一个token参数

GenericTrigger(
token: 'secret',
)
}

token参数的作用是标识一个pipeline在Jenkins中的唯一性(当然,没有人阻止你让所有的pipeline使用同-个token)。

为什么需要这个参数呢?这要从GWT插件的原理说起。当Jenkins接收到generic-webhooktriggerlinvoke接口的请求时,会将请求代理给GWT插件处理。GWT插件内部会从Jenkins实例对象中取出所有的参数化Jenkins项目,包括pipeline然后进行遍历。

如果在参数化项目中GenericTrigger配置的token的值与Webhook请求时的token的值一致,则触发此参数化项目。如果多个参数化项目的token值一样,则它们都会被触发。

pipeline的token可以被设置为Jenkins的项目名

比如:

triggers {
GenericTrigger(
//省略
token: env.JOB_NAME,
//省略
)
}

过滤请求值

上节所说的不完全正确。GWT并不只是根据token值来判断是否触发,还可以根据我们提取出的值进行判断。

示例如下:

GenericTrigger(
genericVariables:[
[key: ' refValue',value: '$.ref']
],
token: env.JOB_NAME,
regexpFilterText:'$refValue',
regexpFilterExpression: 'refs/heads/(master|dev)'
)
  • regexpilterText: 需要进行匹配的key。例子中,我们使用从POST body中提取出的refValue变量值。
  • regexpFilterExpression :正则表达式。

如果regexpFilterText参数的值符合regexpilterExpression参数的正则表达式,则触发执行。

控制打印内容

打印日志有助于调试。GWT插件提供了三个参数。

  • printPostContent :布尔值, 将Webhook请求信息打印到日志上。
  • printContributedVariables:布尔值,将提取后的变量名及变量
  • 值打印出来。
  • causeString :字符串类型,触发原因可以直接引用提取后的变量,如causeString : 'Triggered on $msg'。

控制响应

GWT插件最近才加入的一个参数:

silenResponse: 布尔类型,在正常情况下当Webhook请求发布成功后,GWT插件会返回HTTP 200状态码和触发结果给调用方。但是当设置为true时,就只返回HTTP 200状态码,不返回触发结果。

最新文章

  1. 关于Nginx的一些优化(突破十万并发)
  2. ios - block循环引用Demo示例
  3. Python网络连接
  4. Lodop6 以上打印控件使用,详参考自带说明文档,打印样式及文字大小要特殊设置一下
  5. sqlmap如何修改线程
  6. C++的几种强制类型转换
  7. 横向浅谈移动技术------( 原生,混合,web --- 谁能问鼎移动开发的明天)
  8. javascirpt语法
  9. Android新增API之AudioEffect中文API与应用实例
  10. Eclipse中提高Android SDK Manager下载速度方法
  11. Picasso解决 TextView加载html图片异步显示
  12. CVE-2014-4113 Win8.1 64位利用(2014.11)
  13. git基本概念
  14. Springboot配置多数据源(Mysql和Orcale)--(Idea Maven JDBCTemplate支持下的)
  15. Android系统的镜像文件的打包过程
  16. 整体二分求动态区间第k大
  17. Java多线程runnable
  18. Django中url的反向查询
  19. [BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组)
  20. 运行mlflow命令报错 The &#39;nose&#39; distribution was not found and is required by nose-exclude

热门文章

  1. Python使用cx_Oracle模块操作Oracle数据库--通过sql语句和存储操作
  2. Mybatis动态传入tableName--非预编译(STATEMENT)
  3. [loj3043]线段树
  4. Linux学习 - 树莓派4b的U-Boot的初识
  5. 低代码开发Paas平台时代来了
  6. LOJ 2555 &amp; 洛谷 P4602 [CTSC2018]混合果汁(二分+主席树)
  7. LOJ #2185 / 洛谷 P3329 - [SDOI2015]约数个数和(莫比乌斯函数)
  8. PHP对称加密-AES加密、DES加密
  9. 【4】蛋白质组学鉴定软件之MSGFPlus
  10. 端口TCP——简介