1987WEB视界-分享互联网热门产品和行业

您现在的位置是:首页 > WEB开发 > 正文

WEB开发

JenkinsCI:多分支构建

1987web2023-10-06WEB开发137
jenkins允许用户开发插件,扩展功能,因此你可以在社区找到丰富的插件,但是插件质量参差不齐,想让多个插件协作,需要非常复杂的配置。

jenkins允许用户开发插件,扩展功能,因此你可以在社区找到丰富的插件,但是插件质量参差不齐,想让多个插件协作,需要非常复杂的配置。

现代的CI/CDgitlab CItravis CI均摒弃了这样的插件思路

比如,一个普遍遇到的问题就是,如何支持构建不同的分支?这几乎大部分CI支持、用户以为理所当然的功能,在jenkins里是件比较麻烦的事情

前提

除非是非常简单的项目,大多数项目会使用jenkins pipeline来计划构建、部署任务

有两个方式定义Pipeline

  1. 直接写在 web ui项目配置
  2. 提交到SCM,在项目配置中指定其位置

复杂一点的Pipeline会采用第二种方式,因为可以帮助我们追踪Pipeline的变更。 但是这会引发我们今天要讨论的问题:

问题:Pipeline过早初始化

采用Pipeline from SCM的项目,随便打开任意构建 console output,会看到类似这样的日志:

我们可以看到,Pipeline是在拉取代码之前就被确定、初始化的。

Pipeline是存放在SCN(代码仓库)里, 因此我们需要在配置里面指定拉取的分支:

如果我们想要构建不同的分支,不同分支上的Pipeline有些不一样,怎么办?

解决方法 1:环境变量

我们可以用参数化构建中的环境变量代替手写的分支名:

BRANCH参数化构建中的一个参数

CI/CD ?

问题似乎解决了,但是我们不可能每次构建都要打开jenkins手动点击触发,这样就不叫CI/CD了。我们要支持trigger,比如gitlab hook,由git push触发构建任务

你需要安装gitlab-plugin

这样,分支可能来自trigger注入的环境变量,可能来自参数化构建的参数。

很容易想到,我们可以使用同样的名字来隐藏两者的区别,比如gitlab hook注入的变量gitlabBranch,那我们也以同样的名字作为参数化构建中的一个参数名

因此,不管gitlabBranch是来自哪里,我们的Pipeline文件都是最新的。

如果需要更复杂的逻辑,而不是简单的合并,也许你需要EnvInject插件

解决方案 2:动态加载 Pipeline

问题的本质在于Pipeline是在拉取代码之前被确定的,那么,我们可不可以反过来,在拉取代码之后再去「初始化Pipeline」,像其他CI那样?

利用loadAPI,我们可以做到这一点。

load可以动态加载一个Groovy文件(假设名为Main.groovy),我们可以把主要的任务逻辑放在Main.groovy.

而我们的Pipeline文件只是一个启动入口,本身不定义任务,只做一件事情——git checkout,之后就加载Main.groovy。 如下:

deploy/
├── Jenkinsfile
└── Main.groovy
// Jenkinsfile// 1. checkoutdefrepo=checkout([$class:GitSCM,branches:[[name:"${gitlabBranch}"]],doGenerateSubmoduleConfigurations:false,extensions:[],gitTool:Default,submoduleCfg:[],userRemoteConfigs:scm.userRemoteConfigs])// 2. load main pipelineload"deploy/Main.groovy"
由于Main.groovy永远是当前分支的,所以整个Pipeline也是当前分支的,除非Jenkinsfile发生变更

为什么不使用Multibranch Pipeline

Multibranch Pipeline为项目的每一个分支单独创建一个对应的job,看起来不错,但是这种方式不支持tag pushmerge request等。 在实际工作中,也很少看到项目使用这样的方式。

总结

大家可以看到仅仅是多分支,jenkins就需要你花时间去 google,阅读各种不同风格的 plugin 文档,学习 groovy API,不断尝试。

虽然这篇是关于Jenkins Pipeline,但是我不推荐使用jenkins,除非像我一样万不得已(团队内部原因)

如果公司代码托管使用的是gitlab,明显可以选择gitlab ci