jenkins 允许用户开发插件,扩展功能,因此你可以在社区找到丰富的插件,但是插件质量参差不齐,想让多个插件协作,需要非常复杂的配置。
现代的CI/CD
如 gitlab CI、travis CI
均摒弃了这样的插件思路
比如,一个普遍遇到的问题就是,如何支持构建不同的分支?这几乎大部分 CI
支持、用户以为理所当然的功能,在 jenkins 里是件比较麻烦的事情
前提
除非是非常简单的项目,大多数项目会使用 jenkins pipeline
来计划构建、部署任务
有两个方式定义 Pipeline
- 直接写在 web ui 项目配置里
- 提交到 SCM,在项目配置中指定其位置
复杂一点的 Pipeline 会采用第二种方式,因为可以帮助我们追踪 Pipeline 的变更。 但是这会引发我们今天要讨论的问题:
问题:Pipeline 过早初始化
采用 Pipeline from SCM
的项目,随便打开任意构建 console output,会看到类似这样的日志:
![baa9454229b39b6e388244e1885cae5c.png](https://img-blog.csdnimg.cn/img_convert/baa9454229b39b6e388244e1885cae5c.png)
我们可以看到,Pipeline 是在拉取代码之前就被确定、初始化的。
而 Pipeline 是存放在 SCN
(代码仓库)里, 因此我们需要在配置里面指定拉取的分支:
![89771a367530c853fd6d8e9613c9004f.png](https://img-blog.csdnimg.cn/img_convert/89771a367530c853fd6d8e9613c9004f.png)
如果我们想要构建不同的分支,不同分支上的 Pipeline 有些不一样,怎么办?
解决方法 #1:环境变量
我们可以用参数化构建中的环境变量
代替手写的分支名:
![2008ae5123bde0eadf1cda341bca7cad.png](https://img-blog.csdnimg.cn/img_convert/2008ae5123bde0eadf1cda341bca7cad.png)
BRANCH
是参数化构建中的一个参数
CI/CD ?
问题似乎解决了,但是我们不可能每次构建都要打开 jenkins 手动点击触发,这样就不叫 CI/CD
了。我们要支持 trigger
,比如 gitlab hook
,由 git push
触发构建任务
你需要安装 gitlab-plugin
这样,分支可能来自 trigger
注入的环境变量,可能来自参数化构建的参数。
很容易想到,我们可以使用同样的名字来隐藏两者的区别,比如 gitlab hook
注入的变量 gitlabBranch
,那我们也以同样的名字作为参数化构建中的一个参数名
![a662d3b60dfc9b26c720862f5581d683.png](https://img-blog.csdnimg.cn/img_convert/a662d3b60dfc9b26c720862f5581d683.png)
因此,不管 gitlabBranch
是来自哪里,我们的 Pipeline 文件都是最新的。
如果需要更复杂的逻辑,而不是简单的”合并“,也许你需要 EnvInject 插件
解决方案 #2:动态加载 Pipeline
问题的本质在于 Pipeline 是在拉取代码之前被确定的,那么,我们可不可以反过来,在拉取代码之后再去「初始化 Pipeline」,像其他 CI
那样?
利用 load API,我们可以做到这一点。
load
可以动态加载一个 Groovy
文件(假设名为 Main.groovy
),我们可以把主要的任务逻辑放在 Main.groovy
.
而我们的 Pipeline 文件只是一个启动入口,本身不定义任务,只做一件事情——git checkout
,之后就加载 Main.groovy
。 如下:
deploy/
├── Jenkinsfile
└── Main.groovy
// Jenkinsfile
// 1. checkout
def repo = checkout([$class : 'GitSCM',
branches : [[name: "${gitlabBranch}"]],
doGenerateSubmoduleConfigurations: false,
extensions : [],
gitTool : 'Default',
submoduleCfg : [],
userRemoteConfigs : scm.userRemoteConfigs
])
// 2. load main pipeline
load "deploy/Main.groovy"
由于Main.groovy
永远是当前分支的,所以整个Pipeline
也是当前分支的,除非Jenkinsfile
发生变更
为什么不使用 Multibranch Pipeline
Multibranch Pipeline 为项目的每一个分支单独创建一个对应的 job
,看起来不错,但是这种方式不支持 tag push
、merge request
等。 在实际工作中,也很少看到项目使用这样的方式。
总结
大家可以看到仅仅是多分支,jenkins 就需要你花时间去 google,阅读各种不同风格的 plugin 文档,学习 groovy API,不断尝试。
虽然这篇是关于 Jenkins Pipeline,但是我不推荐使用 jenkins,除非像我一样万不得已(团队内部原因)
如果公司代码托管使用的是 gitlab
,明显可以选择 gitlab ci。