前言
相信大家对Jenkins已经非常了解了,大多数项目都采用了这款开源工具来实现项目的CI/CD。
对于小型项目,我们完全可以采用“融合部署”的模式,即将Jenkins和构建环境部署在同一台服务器上,来实现自动构建和发布,这时Jenkins的环境搭建也比较简单。但有些时候我们需要多个项目并行编译,或者需要适配多种编译环境,这时对于单主机的性能要求就比较高了。
为应对这种情况,通常会采用“代理模式”(也有叫主从模式的):将Jenkins独立部署,负责对多个项目的构建任务进行调度,而不参与(或极少参与)项目的构建发布;然后添加多个子节点,来负责具体的编译构建任务。这种模式的好处是:
- 构建节点高可用。一个构建节点挂了,其他节点可以接替执行构建任务,保证系统正常运行;
- 可以配置差异化的构建环境。每个节点可以针对不同语言开发的项目配置不同的构建环境,互不影响;
- 构建任务可并行。当SCM同时触发了多个构建任务时,可以将这些任务分配到不同节点上执行,提升构建效率。
代理模式的环境搭建比较简单,这里不做讨论。当我们在使用代理模式时构建项目时会出现很多问题,本文主要讨论在这种情况下的一些实践经验和建议。
准备工作
1、环境准备
这一步的工作是必须的,也是“很有学问”的。
对于java项目,我们需要配置的就是jdk和Maven。按照传统的思路,我们会这么做:
- 上传适配系统和应用的jdk和maven;
- 在~/.bash_profile或/etr/profile中配置jdk和maven的环境变量;
- 在任意路径下执行java -version和mvn -v验证环境配置
最终配置的结果类似下方截图:
但是你会惊奇的发现这样做对Jenkins来说并不没有用,你可能会遇到如下错误:
相信大家到这里都会有点懵。啥情况?明明配置好了环境变量,在主机上运行也好使,怎么到Jenkins里就不好用呢?
这是因为Jenkins在运行时不会加载用户的环境变量,只会使用自己(在Jenkins里配置)的环境变量。如果没有在Jenkins中配置环境变量,默认会使用系统中(Linux为例)/usr/bin或/bin 目录下的指令。
所以,针对上面的问题,有2种解决方案,任选其一即可:
1)在Jenkins的控制台上,对构建节点添加环境变量,在“系统管理->节点管理->选中目标节点->配置从节点”中,添加环境变量,如下图:
说明:
这是节点的个性化配置。
如果所有的构建节点环境配置一致,就可以在“全局配置”中统一配置。
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项目”:
但是这个工程有一个问题,它依赖于Jenkins的全局配置。如果没有配置,现象如下:
这时可以点击后面的“the tool configuration”进入全局配置界面,配置maven路径。
很多时候各节点的jdk和maven的路径配置不同,或某些节点根本就不需要这2个工具,那么又需要在每个节点上分别修改配置。这种情况下,使用“构建一个Maven项目”就不太合适了。
我们可以使用下面的2种方式。
2、构建一个自由风格的软件项目
这种模式比较简单,只要在“环境准备”步骤中都配置好,接下来就是一些shell指令的编排。
首先,在创建项目时选择“构建一个自由风格的软件项目”:
?编辑
其次,在General中勾选“限制项目的运行节点”,填写构建节点的名称,如下:
然后,在“源码管理”中选择代码库、在“构建触发器”中设置SCM周期,这里就不展示了。
接下来到核心操作步骤了,在“构建”中增加构建步骤,选“执行 shell”,按照你工程的实际编译指令,编写shell内容,如:
执行shell时,默认是在当前工作目录下,在主机上路径为$(JENKINS_HOME)/workspace/工程目录/。如果你的pom文件不在工程的根目录下,你还需要cd到目标路径下。
这一步完成之后,就会在你 “工作目录/target”中生成jar或war包。
在部署应用时,可以部署到容器、k8s、或者独立运行。本文只讨论独立部署运行的情况。可以在“构建后操作”中使用“Publish Over SSH”这个插件,将jar包上传到运行节点(也可以是本机)的目标目录中,然后启动程序。参考如下:
需要注意几点:
- 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 目录下。
后续的程序启动就可以在“Exec Command”中完成了,比较简单。
至此,我们就完成了一个Maven项目的自动构建和独立发布。
3、流水线
我们还可以使用Pipeline来构建和运行项目。在创建项目时,选择“流水线”:
在项目中,“General”和“构建触发器”的配置方式跟前面都是一样的。
在后面的“流水线”这里,需要编写Groovy脚本来控制构建和发布的逻辑。我们可以在网上找一些通用的代码模板,也可以选择Jenkins自带的模板,为我们自动生成一些代码,观察代码结构:
看到pipeline里面,指定了agent节点、克隆代码、构建,等等。
不会Groovy怎么办?看到左下角的“流水线语法”了吗?点进去,会为我们自动生成流水线代码!例如,我想指定我的运行节点,就可以按照如下步骤点击、选择:
从英文中不难理解每个步骤的含义,最后点击按钮就会为我们生成代码。把这个代码直接贴到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个步骤是最基本的,即:
- 指定任务运行节点
- 设置环境变量
- 拉取代码
- 编译构建
- 应用发布
有了“流水线语法”,不会Groovy也可以编写Pipeline!本例中的所有代码都是通过“流水线语法”自动生成的。
当然,如果你想实现更多的高级功能,就需要深入研究Groovy了。
总结
本文介绍了在代理模式下,分别通过“构建一个自由风格的软件项目”、“构建一个Maven项目”以及“流水线”3种方式来构建Maven项目,以及每种方式的注意事项,总结如下:
- Jenkins在运行任务时,使用的自己的环境变量,而不是操作系统的环境变量。可以在Jenkins的系统设置中进行设置,也可以针对每个节点进行设置;
- Jenkins默认使用的是/usr/bin和/bin下的指令,不会读取主机用户的PATH;
- “构建一个Maven项目”,更适用于小型项目,单台服务器就能够完成调度和构建任务的情形;
- 不熟悉Groovy也可以构建流水线,使用“流水线语法”自动生成代码;
?