# Jenkins教程 - 12 Jebkinsfile的多分支构建
在前面我们创建流水线的时候,定义选择的是 Pipeline script
,然后直接写脚本。
还有一种是 Pipeline script from SCM
,这种方式我们可以在项目目录下创建 Jenkinsfile 文件,在文件中编写脚本文件,然后 Jenkins 从 Git 中拉取 Jenkinsfile 文件,然后执行文件中的脚本。这有点类似于 Dockerfilie。
我们可以使用 Jenkinsfile 来创建多分支的构建任务。
也就是我们的 SpringBoot 项目在 gitee 中有两个分支,每个分支的项目目录下都有一个 Jenkinsfile 文件,这样 Jenkins 在构建的时候,会分别拉取两个分支的代码,根据各个分支的 Jenkinsfile 文件中的脚本来执行构建,可以将不同分支的代码部署到不同的服务器。
下面简单演示一下使用 Jenkins 创建多分支构建任务。
# 12.1 准备SpringBoot项目
# 1 新建一个SpringBoot 项目
新建一个 SpringBoot 项目,这里我就在 SpringBoot 中新建一个 Controller。
只提供了一个接口,证明 SpringBoot 能访问运行就好了。
package com.doubibiji.hellospringboot.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String sayHello() {
return "Hello www.doubibiji.com";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
同时在项目下创建一个 docker
文件夹,并编写 Dockerfile
文件,后面用来生成 Docker
镜像。
Dockerfile
文件内容如下:
# 使用基础的 Java 11镜像
FROM openjdk:11
# 对外暴露的端口
EXPOSE 9000
# 设置环境变量来指定时区
ENV TZ=Asia/Shanghai
# 将时区文件复制到容器中的特定路径
RUN ln -sf /usr/share/zoneinfo/{TZ} /etc/localtime && echo "{TZ}" > /etc/timezone
# 将jar包添加到容器中并更名为app.jar
ADD hello-springboot-0.0.1-SNAPSHOT.jar app.jar
# 运行jar包
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
项目结构如下:
deploy.sh
用来执行停止、删除、启动容器等操作:
#!/bin/bash
# 项目名称
projectName=hello-springboot
# 年月日时分的时间戳
timestamp=$(date +%Y%m%d%H%M)
# 新镜像的名称
newImageName=$projectName-$timestamp
# 1.首先使用Dockerfile打镜像
docker build -t $newImageName .
# 2.停止并删除之前运行的容器
runningContainerId=$(docker ps | grep "$projectName" | awk '{print $1}')
# 如果有运行中的容器,停止它,并删除它
if [ -n "$runningContainerId" ]; then
docker stop "$runningContainerId"
docker rm "$runningContainerId"
fi
# 万一新的镜像有问题,为了恢复,就不删除之前的镜像了
# 在宿主机上创建logs目录,用于容器挂载,这样查看日志可以直接在宿主机查看,比较方便
mkdir -p ~/projects/$projectName/logs
# 3.运行新的镜像
docker run -d -p 9000:9000 --restart=always -v ~/projects/$projectName/logs:/logs $newImageName
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
在项目根目录下新建 Jenkinsfile,前面说了 Jenkins 会根据各个分支下的 Jenkinsfile 来构建项目,这样会有一个问题,各个分支进行代码合并的时候,Jenkinsfile 文件可能会产生冲突。为了避免这个问题,这里也可以各个分支的 Jenkins 分支脚本代码相同,在脚本代码里通过分支名称来区分执行的代码,例如下面这样:
pipeline {
agent any
stages {
stage('构建项目') {
steps {
sh """
mvn --version
mvn clean package
"""
echo '构建完成!'
}
}
stage('传送文件') {
steps {
script {
// 根据分支名称不同,传输到不同的服务器
if (env.BRANCH_NAME == 'develop') {
echo '传输到测试服务器...'
// 这里按照之前编写 Pipeline 脚本的方式生成脚本来传输,只是传输的目标服务器不同
sshPublisher(publishers: [sshPublisherDesc(configName: 'doubibiji-server-test', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'projects/hello-springboot', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/*.jar'), sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'projects/hello-springboot', remoteDirectorySDF: false, removePrefix: 'docker', sourceFiles: 'docker/Dockerfile,docker/deploy.sh')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
} else if (env.BRANCH_NAME == 'main') {
echo '传输到生产服务器...'
sshPublisher(publishers: [sshPublisherDesc(configName: 'doubibiji-server-pro', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'projects/hello-springboot', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/*.jar'), sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'projects/hello-springboot', remoteDirectorySDF: false, removePrefix: 'docker', sourceFiles: 'docker/Dockerfile,docker/deploy.sh')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
echo '传输完成!'
}
}
stage('构建并启动容器') {
steps {
script {
// 这里两个分支只是发布到的服务器不同,其他要执行的指令都是相同的
if (env.BRANCH_NAME == 'develop') {
sshPublisher(publishers: [sshPublisherDesc(configName: 'doubibiji-server-test', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd ~/projects/hello-springboot
chmod +x deploy.sh
sh deploy.sh''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
} else if (env.BRANCH_NAME == 'main') {
sshPublisher(publishers: [sshPublisherDesc(configName: 'doubibiji-server-pro', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd ~/projects/hello-springboot
chmod +x deploy.sh
sh deploy.sh''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
echo '执行启动容器完成!'
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
如果你看了之前的 Pipeline部署SpringBoot到Docker
章节,上面的代码应该是比较简单的,也是从那个章节拷贝过来的,只是修改了部署到的业务服务器。
根据分支名称修改代码要传输到的业务服务器,我这里在Jenkins中添加了两个业务服务器,'doubibiji-server-test
和 doubibiji-server-pro
,分别将 main 分支和 develop 分支的代码部署到这两台服务器。
# 2 将SpringBoot项目托管码云
Jenkins 服务后面需要从 git 仓库拉取代码进行构建,这里使用 gitee 码云来托管代码,所以这里将 SpringBoot 项目托管到码云。
项目创建两个分支,main 和 develop 分支。
这里细节就不介绍了,git 不太会的,可以学习本站的 git教程 (opens new window) 。
# 12.2 创建多分支流水线任务
新建多分支流水线:
配置分支源:
先选择 Git:
配置 Git 仓库:
然后保存即可,保存后 Jenkins 会自动扫描仓库的分支并执行构建。
也可以手动使用 立即扫描 多分支流水线
触发扫描构建。
# 12.3 查看构建任务
回到构建任务页面,可以看到两个分支的构建情况。
点击进入到每个分支的详情页面,可以单独对这个分支进行构建,也可以查看到构建的情况。
查看构建情况:
# 12.4 访问项目
现在项目已经根据 Jenkinsfile 的配置将 SpringBoot 项目部署到服务器上了。可以同时访问测试环境和生产环境的服务器,都可以访问接口。此时 develop 分支和 main 分支的代码是一样的,所以访问
此时如果修改 develop 分支的代码,并提交到远程,重新执行扫描分支,或重新对 develop 分支执行构建,会发现测试环境服务器的接口发生变化了。