前言

相信大家对Jenkins已经非常了解了,大多数项目都采用了这款开源工具来实现项目的CI/CD。

对于小型项目,我们完全可以采用“融合部署”的模式,即将Jenkins和构建环境部署在同一台服务器上,来实现自动构建和发布,这时Jenkins的环境搭建也比较简单。但有些时候我们需要多个项目并行编译,或者需要适配多种编译环境,这时对于单主机的性能要求就比较高了。

为应对这种情况,通常会采用“代理模式”(也有叫主从模式的):将Jenkins独立部署,负责对多个项目的构建任务进行调度,而不参与(或极少参与)项目的构建发布;然后添加多个子节点,来负责具体的编译构建任务。这种模式的好处是:

代理模式的环境搭建比较简单,这里不做讨论。当我们在使用代理模式时构建项目时会出现很多问题,本文主要讨论在这种情况下的一些实践经验和建议。


准备工作

1、环境准备

这一步的工作是必须的,也是“很有学问”的。

对于java项目,我们需要配置的就是jdk和maven。按照传统的思路,我们会这么做:

  1. 上传适配系统和应用的jdk和maven;
  2. 在~/.bash_profile或/etr/profile中配置jdk和maven的环境变量;
  3. 在任意路径下执行java -version和mvn -v验证环境配置

最终配置的结果类似下方截图:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(1)

配置环境变量

但是你会惊奇的发现这样做对Jenkins来说并不没有用,你可能会遇到如下错误:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(2)

Jenkins报错

相信大家到这里都会有点懵。啥情况?明明配置好了环境变量,在主机上运行也好使,怎么到Jenkins里就不好用呢?

这是因为Jenkins在运行时不会加载用户的环境变量,只会使用自己(在Jenkins里配置)的环境变量。如果没有在Jenkins中配置环境变量,默认会使用系统中(Linux为例)/usr/bin或/bin 目录下的指令。

所以,针对上面的问题,有2种解决方案,任选其一即可:

1)在Jenkins的控制台上,对构建节点添加环境变量,在“系统管理->节点管理->选中目标节点->配置从节点”中,添加环境变量,如下图:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(3)

节点属性配置

说明:

这是节点的个性化配置。

如果所有的构建节点环境配置一致,就可以在“全局配置”中统一配置。

2)也可以在构建节点上建立软连接,链接到我们的可执行程序上,如:

ln -s /home/maven/apache-maven-3.6.2/bin /usr/bin/mvn ln -s /home/maven/apache-maven-3.6.2/bin /bin/mvn

这样,Jenkins就能找到mvn这个指令了。

java指令也是这样配置。

2、插件准备

在Jenkins中商店中按需安装相关插件,如svn、git、pipeline,等等。

如果你的构建节点和运行节点不在一个机器上,需要安装“Publish Over SSH”这个插件。插件的安装不在本文讨论。

在Jenkins和构建环境中做好上述配置之后,就可以进行下一步了。

Maven项目构建

1、构建一个Maven项目

对于Maven工程,我们会本能的选择“构建一个Maven项目”:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(4)

选择项目形式

但是这个工程有一个问题,它依赖于Jenkins的全局配置。如果没有配置,现象如下:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(5)

Jenkins报错

这时可以点击后面的“the tool configuration”进入全局配置界面,配置maven路径。

很多时候各节点的jdk和maven的路径配置不同,或某些节点根本就不需要这2个工具,那么又需要在每个节点上分别修改配置。这种情况下,使用“构建一个Maven项目”就不太合适了。

我们可以使用下面的2种方式。

2、构建一个自由风格的软件项目

这种模式比较简单,只要在“环境准备”步骤中都配置好,接下来就是一些shell指令的编排。

首先,在创建项目时选择“构建一个自由风格的软件项目”:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(6)

​编辑

其次,在General中勾选“限制项目的运行节点”,填写构建节点的名称,如下:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(7)

然后,在“源码管理”中选择代码库、在“构建触发器”中设置SCM周期,这里就不展示了。

接下来到核心操作步骤了,在“构建”中增加构建步骤,选“执行 shell”,按照你工程的实际编译指令,编写shell内容,如:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(8)

执行shell时,默认是在当前工作目录下,在主机上路径为$(JENKINS_HOME)/workspace/工程目录/。如果你的pom文件不在工程的根目录下,你还需要cd到目标路径下。

这一步完成之后,就会在你 “工作目录/target”中生成jar或war包。

在部署应用时,可以部署到容器、k8s、或者独立运行。本文只讨论独立部署运行的情况。可以在“构建后操作”中使用“Publish Over SSH”这个插件,将jar包上传到运行节点(也可以是本机)的目标目录中,然后启动程序。参考如下:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(9)

Publish Over SSH 插件

需要注意几点:

  • SSH Server:目标节点的登录信息可以在“节点管理”中提前配置好,也可以在SSH Server下面的“高级”中设置;
  • Source files:要上传到目标节点的文件,本例中是可执行jar文件;
  • Remove prefix:去掉目录前缀,这是根据Source files设置的。按照例子中的填写方式,放到目标路径后,rest-1.0.jar这个文件还是在target目录下。这一步的作用就是把target目录去掉;
  • Remote directory:要将源文件放到目标节点上的目标目录。注意:这里是相对路径!你需要提前在“系统配置”中,配置好ssh主机的路径,如下图,系统配置中Remote Directory配置的是 /home/appuser。那么在本例中,rest-1.0.jar 会被放到目标主机的 /home/appuser/test 目录下。

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(10)

系统配置-SSH Server

后续的程序启动就可以在“Exec Command”中完成了,比较简单。

至此,我们就完成了一个Maven项目的自动构建和独立发布。

3、流水线

我们还可以使用Pipeline来构建和运行项目。在创建项目时,选择“流水线”:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(11)

选择项目形式

在项目中,“General”和“构建触发器”的配置方式跟前面都是一样的。

在后面的“流水线”这里,需要编写Groovy脚本来控制构建和发布的逻辑。我们可以在网上找一些通用的代码模板,也可以选择Jenkins自带的模板,为我们自动生成一些代码,观察代码结构:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(12)

流水线脚本

看到pipeline里面,指定了agent节点、克隆代码、构建,等等。

不会Groovy怎么办?看到左下角的“流水线语法”了吗?点进去,会为我们自动生成流水线代码!例如,我想指定我的运行节点,就可以按照如下步骤点击、选择:

jenkinsmaven打包的路径(Jenkins代理模式配置Maven工程)(13)

从英文中不难理解每个步骤的含义,最后点击按钮就会为我们生成代码。把这个代码直接贴到Pipeline的适当位置上即可,如下:

pipeline { //1.指定标签为 test 的节点 执行该构建任务 agent { label 'test' } //2.声明环境变量 environment { MAVEN_HOME = "/home/appuser/lr/maven/apache-maven-3.6.2" JAVA_HOME = "/home/appuser/lr/jdk1.8.0_11" JRE_HOME = "${JAVA_HOME}/jre" CLASSPATH = ".:${JAVA_HOME}/lib:${JRE_HOME}/lib:$CLASSPATH" JAVA_PATH = "${JAVA_HOME}/bin:${JRE_HOME}/bin" PATH = "/usr/local/go/bin:$JAVA_HOME/bin:$PATH:$JAVA_HOME/jre/bin:$PATH:${MAVEN_HOME}/bin" } stages { stage('Pull Code') { steps { // 3.编写拉取代码的指令 // sh "svn xxxxx" // sh "git pull xxxx" echo "start" } } stage('Build') { steps { // 4.在这里添加编译构建指令 sh "mvn -Dmaven.test.failure.ignore=true clean package" } } stage('Run') { // 5.应用发布 // 这部分代码也是在流水线语法中自动生成的,在“片段生成器”中选择sshPublisher steps { sshPublisher(publishers: [sshPublisherDesc(configName: '10.4.122.155', sshCredentials: [encryptedPassphrase: '{AQAAABAAAAAQUhudNn9S1kPGyV4eRRGNs649cFzWNnaNJKTG0C0/OGc=}', key: '', keyPath: '', username: 'appuser'], transfers: [sshTransfer(excludes: '', execCommand: 'nohup java -jar /home/appuser/test/rest-1.0.jar &', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ] ', remoteDirectory: 'test', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/rest-1.0.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)]) } } } }

在编写Pipeline时,以上5个步骤是最基本的,即:

  1. 指定任务运行节点
  2. 设置环境变量
  3. 拉取代码
  4. 编译构建
  5. 应用发布

有了“流水线语法”,不会Groovy也可以编写Pipeline!本例中的所有代码都是通过“流水线语法”自动生成的

当然,如果你想实现更多的高级功能,就需要深入研究Groovy了。


总结

本文介绍了在代理模式下,分别通过“构建一个自由风格的软件项目”、“构建一个Maven项目”以及“流水线”3种方式来构建Maven项目,以及每种方式的注意事项,总结如下:

  1. Jenkins在运行任务时,使用的自己的环境变量,而不是操作系统的环境变量。可以在Jenkins的系统设置中进行设置,也可以针对每个节点进行设置;
  2. Jenkins默认使用的是/usr/bin和/bin下的指令,不会读取主机用户的PATH;
  3. “构建一个Maven项目”,更适用于小型项目,单台服务器就能够完成调度和构建任务的情形;
  4. 不熟悉Groovy也可以构建流水线,使用“流水线语法”自动生成代码;

,