# Jenkins教程 - 11 Pipeline部署SpringBoot到docker容器中
现在使用 Pipeline 来部署 SpringBoot 项目,将项目部署到 Docker 容器中。
这里为了保持本章内容的独立性,之前已经配置的步骤,也重新复制了过来,如果你从前面看过来的,就当重新温习了一遍。
# 11.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 ,用来执行停止、删除、启动容器等操作,后面介绍。
# 2 将SpringBoot项目托管码云
Jenkins 服务后面需要从 git 仓库拉取代码进行构建,这里使用 gitee 码云来托管代码,所以这里将 SpringBoot 项目托管到码云。
这里细节就不介绍了,git 不太书写的,可以学习本站的 git教程 (opens new window) 。
# 11.2 配置插件和工具
# 1 安装Maven插件
我们现在构建项目需要使用 Maven,所以还需要安装一个 Maven 插件。
在可用的插件中,搜索 maven,在搜索结果中选中 Maven Integration
进行安装。
拉到最下面,查看安装进度
# 2 配置Maven工具
我们的自动化构建任务是使用 Maven 构建的,需要告诉 Jenkins Maven的安装位置。
配置 Maven 的路径:
使用 mvn -v
可以查看 maven 安装的路径。
# 3 安装SSH插件
这个插件的作用就是将 Jenkins 构建的 SpringBoot 项目的 jar 包发布的业务服务器上。
还是刚才安装插件的步骤:
# 4 配置业务服务器
后面需要将构建的 SpringBoot 的 jar 包发布到业务服务器,所以在这里配置一下要发布到的业务服务器的信息。
拉到最下面找到 Publish over SSH
,安装完 SSH 插件才有这个选项。
Server是可以有多个的,新增一个 SSH Server。填写SpringBoot项目要部署到的业务服务器的信息。
配置上面几个选项就可以了,配置完成,在最下面有个测试的按钮,可以测试一下配置有没有问题,没有问题,保存配置。
# 11.3 创建构建任务
# 1 新建任务
在 Jenkins 管理页面,新建Item,也就是新建构建任务。
填写任务名称,选择流水线任务:
# 2 编写脚本
编写流水线脚本,目前我们主要实现 4 个阶段:
代码如下:
pipeline {
agent any
stages {
stage('拉取代码') {
steps {
echo '拉取代码完成!'
}
}
stage('执行构建') {
steps {
echo '执行构建成功!'
}
}
stage('发送文件') {
steps {
echo '发送文件成功!'
}
}
stage('构建并启动容器') {
steps {
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
我们在编写的时候,可以一步一步去实验,看看有没有问题,例如编写完上面的脚本,可以运行测试一下执行有没有问题。
上面各个阶段确认了,下面来编写各个阶段的执行的脚本。
# 3 编写拉取代码脚本
不会写流水线脚本,没关系,我们可以使用工具。
点击下面的流水线语法,
在新的页面提供了生成脚本的功能,这里是拉取代码,所以示例步骤选择 git: Git
:
填写生成流水线脚本按钮,会在下面的文本框中生成对应的脚本。
添加凭证的操作:
将生成的脚本填写到之前的步骤中:
pipeline {
agent any
stages {
stage('拉取代码') {
steps {
git branch: 'main', credentialsId: 'gitee', url: 'https://gitee.com/doubibiji/hello-springboot.git'
echo '拉取代码完成!'
}
}
stage('执行构建') {
steps {
echo '执行构建成功!'
}
}
stage('发送文件') {
steps {
echo '发送文件成功!'
}
}
stage('构建并启动容器') {
steps {
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
此时拉取代码的阶段就编写好了,可以执行任务测试一下,看看日志有没有执行成功。
# 4 编写执行构建脚本
下面开始编写执行构建阶段的脚本,构建是 maven 构建的,直接执行 maven 命令即可,但是 maven 需要配置一下:
pipeline {
agent any
tools {
maven "maven3" // 这里的maven3的名字是和前面配置maven工具的时候指定的名称是一致的。
}
stages {
stage('拉取代码') {
steps {
git branch: 'main', credentialsId: 'gitee', url: 'https://gitee.com/doubibiji/hello-springboot.git'
echo '拉取代码完成!'
}
}
stage('执行构建') {
steps {
sh """
mvn --version
mvn clean package
"""
echo '执行构建成功!'
}
}
stage('发送文件') {
steps {
echo '发送文件成功!'
}
}
stage('构建并启动容器') {
steps {
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
解释一下:
stage('执行构建') {
steps {
sh """
mvn --version
mvn clean package
"""
echo '执行构建成功!'
}
}
2
3
4
5
6
7
8
9
在这个步骤中就是执行了 maven 命令进行打包,maven 命令默认就是在 Jenkins 工作目录下的构建任务所在的文件夹中执行的(不清楚的可以去看构建的第一个SpringBoot项目),此时SpringBoot项目 pom.xml
文件就在 workspace/pipeline-springboot
目录下,所以直接执行构建命令。如果 pom.xml
文件不是在这个目录,则进入到所在目录即可。
"""
表示的是执行多行命令,mvn clean package
表示清理然后打包。
配置好以后,可以再执行一下,看看 Pipeline 脚本到这里是否有问题。
# 5 编写发送文件脚本
和编写拉取代码脚本类似,也是使用脚本生成工具。
因为是使用 Publish Over SSH
插件实现传输的,所以这里选择 sshPublisher:Send build artifacts over SSH
:
再添加一个传输配置,将 Dockerfile 和 deploy.sh 也传输到业务服务器。
这里和之前部署到Docker一样,我们将 jar 包传输到业务服务器,还编写一个构建 docker 镜像、备份、执行容器的脚本文件,也就是 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
deploy.sh
主要是构建镜像,并停止和删除之前的镜像,运行新的镜像。
deploy.sh
是在 SpringBoot 根目录下的 docker 文件中的,所以也会被 Jenkins 拉取到工作目录下,所以将 deploy.sh
传输到业务服务器,然后在构建并启动容器阶段,执行这个脚本。
生成脚本以后,将脚本内容添加到
pipeline {
agent any
tools {
maven "maven3" // 这里的maven3的名字是和前面配置maven工具的时候指定的名称是一致的。
}
stages {
stage('拉取代码') {
steps {
git branch: 'main', credentialsId: 'gitee', url: 'https://gitee.com/doubibiji/hello-springboot.git'
echo '拉取代码完成!'
}
}
stage('执行构建') {
steps {
sh """
mvn --version
mvn clean package
"""
echo '执行构建成功!'
}
}
stage('发送文件') {
steps {
// 传输文件
sshPublisher(publishers: [sshPublisherDesc(configName: 'doubibiji-server', 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 {
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
此时可以再执行构建,查看是否成功将文件传输到业务服务器的 ~/projects/hello-springboot
目录下。
# 6 编写构建并启动容器脚本
这里直接在远程执行脚本就可以了。
因为是在远程执行命令,所以这里还是使用 Publish Over SSH
插件的脚本生成功能生成,只是这里不传输文件,只执行脚本。
将生成的脚本添加到构建和启动容器脚本阶段:
pipeline {
agent any
tools {
maven "maven3" // 这里的maven3的名字是和前面配置maven工具的时候指定的名称是一致的。
}
stages {
stage('拉取代码') {
steps {
git branch: 'main', credentialsId: 'gitee', url: 'https://gitee.com/doubibiji/hello-springboot.git'
echo '拉取代码完成!'
}
}
stage('执行构建') {
steps {
sh """
mvn --version
mvn clean package
"""
echo '执行构建成功!'
}
}
stage('发送文件') {
steps {
// 传输文件
sshPublisher(publishers: [sshPublisherDesc(configName: 'doubibiji-server', 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 {
sshPublisher(publishers: [sshPublisherDesc(configName: 'doubibiji-server', 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
现在 4 个阶段的流水线脚本都编写好了,最后再执行构建。
# 11.4 执行构建
现在再执行一遍完整的构建,构建成功,就可以访问业务服务器的 SpringBoot 项目测试的接口
重新修改代码,并推送到 gitee,然后重新使用 Jekins 重新执行构建,发现自动构建更新完成。
至此,完成了整个 Pipeline 部署 SpringBoot 项目到 Docker 容器的自动构建。
从上面的任务也可以看到,使用流水线需要学习 groovy
语言来编写脚本,这本身是很蛋疼的,这也是流水线的缺点,流水线对编程要求较高,比之前界面中操作的声明式的代码更复杂。