本文目的:
Jenkins部署Springboot单体项目
Jenkins具备发布和回滚版本两种模式部署
1.规划
本次规划节点如下:
| IP | 部署组件 | 作用 |
|---|---|---|
| 192.168.99.78 | Jenkins,Docker,Harbor | 构建服务器 |
| 192.168.99.224 | Docker | 部署服务器 |
正式环境可以Jenkins,Harbor,Docker分别在三个服务器中。
Let`s go
2.准备一个简单的Boot项目
我这里随意构建一个测试项目,端口是8083
@RestController
@SpringBootApplication
public class WebTestApplication {
public static void main(String[] args) {
SpringApplication.run(WebTestApplication.class, args);
}
@GetMapping("/hello")
public String hello() {
return "hello";
}
}
GET访问hello接口返回hello字符串
curl http://localhost:8083/hello
hello
3.Dockerfile构建
这里我们用到了docker构建插件dockerfile-maven-plugin,这个插件作用在于辅助我们快速构建boot的docker镜像。
官网:https://github.com/spotify/dockerfile-maven
具体使用如下:
3.1添加dockerfile-maven-plugin
pom.xml中添加
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.13</version>
<configuration>
<repository>${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
说明:
repository: 这里指定是项目的artifactId buildArgs: 这是指定dockerfile中接收的构建参数列表 JAR_FILE:dockerfile里的参数名,这里我们指定是target/xx.jar,也就是mvn build之后的jar包
3.2在项目根目录下新增Dockerfile
如下:
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
说明:
指定引用jdk8做基础镜像
接收docker build的参数 JAR_FILE,也就是上面我们在pom.xml中JAR_FILE指定的target/xxx.jar
COPY xxx.jar 到镜像的根目录下 命名为 app.jar
docker exec -it containerID /bin/sh
ls具体是否拷贝成功,可以在镜像build之后,run起来,进入容器内部查看
执行启动程序 java -jar app.jar 命令
注意: 同时这里构建的镜像启动后内部的端口就是8083,也就是boot程序application.yml中server.port的端口
3.3 提交到远程Git仓库
我提交到了最大的同性网站上:https://github.com/PittYao/bootJenkins.git
4.部署Harbor
官网:https://goharbor.io/
简介:
Harbor is an open source registry that secures artifacts with policies and role-based access control, ensures images are scanned and free from vulnerabilities, and signs images as trusted. Harbor, a CNCF Graduated project, delivers compliance, performance, and interoperability to help you consistently and securely manage artifacts across cloud native compute platforms like Kubernetes and Docker.
Harbor(港口,港湾)是一个用于存储和分发Docker镜像的企业级Registry服务器。除了Harbor这个私有镜像仓库之外,还有Docker官方提供的Registry。相对Registry,Harbor具有很 多优势:
提供分层传输机制,优化网络传输 Docker镜像是是分层的,而如果每次传输都使用全量文件(所以 用FTP的方式并不适合),显然不经济。必须提供识别分层传输的机制,以层的UUID为标识,确定 传输的对象。 提供WEB界面,优化用户体验 只用镜像的名字来进行上传下载显然很不方便,需要有一个用户界 面可以支持登陆、搜索功能,包括区分公有、私有镜像。 支持水平扩展集群 当有用户对镜像的上传下载操作集中在某服务器,需要对相应的访问压力作分 解。 良好的安全机制 企业中的开发团队有很多不同的职位,对于不同的职位人员,分配不同的权限, 具有更好的安全性。
一言以蔽之:Docker的私有仓库,类似Maven中的Nexus3。u know that
4.1Harbor安装
Harbor需要安装在192.168.99.78上面
先安装Docker并启动Docker(已完成)
先安装docker-compose
sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/dockercompose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose给docker-compose添加执行权限
sudo chmod +x /usr/local/bin/docker-compose查看docker-compose是否安装成功
docker-compose -version下载Harbor的压缩包,我这是2.3.0 https://github.com/goharbor/harbor/releases
上传压缩包到linux,并解压
tar -xzf harbor-offline-installer-v2.3.0.tgz
mkdir /opt/harbor
mv harbor/* /opt/harbor
cd /opt/harbor修改Harbor的配置
vi harbor.yml修改hostname和port
hostname: 192.168.99.78
port: 85安装Harbor
./prepare
./install.sh启动Harbor
docker-compose up -d 启动
docker-compose stop 停止
docker-compose restart 重新启动访问Harbor http://192.168.99.78:85 默认账户密码:admin/Harbor12345

image-20210630165109170
4.2 具体使用
在Harbor创建用户和项目
创建项目 Harbor的项目分为公开和私有的:公开项目:所有用户都可以访问,通常存放公共的镜像,默认有一个library公开项目。私有项目:只有授权用户才可以访问,通常存放项目本身的镜像。我们创建一个新的项目:webtest
给webtest项目分配用户 进入webtest项目->成员

image-20210630174036769 角色 权限说明 访客 对于指定项目拥有只读权限 开发人员 对于指定项目拥有读写权限 维护人员 对于指定项目拥有读写权限,创建 Webhooks 项目管理员 除了读写权限,同时拥有用户管理/镜像扫描等管理权限
4.3把镜像上传到Harbor
给镜像打上标签
docker tag webtest:latest 192.168.99.78:85/webtest/webtest:latest推送镜像
docker push 192.168.99.78:85/webtest/webtest:latestThe push refers to repository [192.168.66.102:85/tensquare/eureka] Get https://192.168.66.102:85/v2/: http: server gave HTTP response to HTTPS client
这时会出现以上报错,是因为Docker没有把Harbor加入信任列表中
把Harbor地址加入到Docker信任列表
vi /etc/docker/daemon.json{
"registry-mirrors": ["https://zydiol88.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.99.78:85"]
}需要重启Docker
再次执行推送命令,会提示权限不足
denied: requested access to the resource is denied需要先登录Harbor,再推送镜像
登录Harbor
docker login -u 用户名 -p 密码 192.168.99.78:85WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded登录成功
4.4从Harbor下载镜像
需求:在192.168.99.224服务器完成从Harbor下载镜像
安装Docker,并启动Docker(已经完成)
修改Docker配置
vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://zydiol88.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.99.78:85"]
}
重启docker
先登录,再从Harbor下载镜像
docker login -u 用户名 -p 密码 192.168.99.78:85
docker pull 192.168.99.78:85/webtest/webtest:latest
5.Jenkinsfile构建
5.1在项目根目录下新建Jenkinsfile
//git的凭证
def git_auth = "3c624c30-b117-47c8-9e3e-c9551498e3a5"
//git地址
def git_url = "https://github.com/PittYao/bootJenkins.git"
//项目名称
def project_name = "webtest"
//构建版本的名称
// def tag = "latest"
//程序的端口
def port = 8083
//Harbor私服地址
def harbor_url = "192.168.99.78:85"
//Harbor的项目名称
def harbor_project_name = "webtest"
//Harbor的凭证
def harbor_auth = "734a87d9-5119-4c4f-bcb3-27c9a25b2ab1"
node {
script {
if ( "${deploy}" == "发布" ) {
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']],
doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [],
userRemoteConfigs: [[credentialsId: "${git_auth}", url:"${git_url}"]]])
}
stage('编译,构建镜像') {
//定义镜像名称
def imageName = "${project_name}:${tag}"
//编译,构建本地镜像
sh "mvn clean package -Dmaven.test.skip dockerfile:build -Ddockerfile.tag=${tag}"
//给镜像打标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_project_name}/${imageName}"//登录Harbor,并上传镜像
withCredentials([usernamePassword(credentialsId: "${harbor_auth}",
passwordVariable: 'password', usernameVariable: 'username')]) {
//登录
sh "docker login -u ${username} -p ${password} ${harbor_url}"
//上传镜像
sh "docker push ${harbor_url}/${harbor_project_name}/${imageName}"
}
//删除本地镜像
sh "docker rmi -f ${imageName}"
sh "docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}"
}
stage('部署服务器执行脚本'){
//=====以下为远程调用进行项目部署========
sshPublisher(publishers:
[
sshPublisherDesc(configName: '192.168.99.224',
transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand:
"/opt/jenkins_shell/back_deploy.sh $harbor_url $harbor_project_name $project_name $tag $port",
execTimeout: 120000, flatten: false, makeEmptyDirs: false,
noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '',
remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')],
usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)
]
)
}
}
}
script {
if ( "${deploy}" == "回滚" ) {
stage('服务器执行回滚脚本'){
//=====以下为远程调用进行项目部署========
sshPublisher(publishers:
[
sshPublisherDesc(configName: '192.168.99.224',
transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand:
"/opt/jenkins_shell/back_deploy.sh $harbor_url $harbor_project_name $project_name $tag $port",
execTimeout: 120000, flatten: false, makeEmptyDirs: false,
noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '',
remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')],
usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)
]
)
}
}
}
}
参数说明:
上述一开始定义了一堆变量:
git_auth:Jenkins中项目git仓库的凭证id git_url:git地址 project_name: 镜像的名称 port : 程序的端口 harbor_url: Harbor私服地址 harbor_project_name : 推送到Harbor的项目名称 harbor_auth : Jenkins登录Harbor的凭证 ${branch}:git的拉取代码分支 ${tag}: docker的tag版本号,这里我们用时间做唯一标识 ${deploy}: 这次部署是,发布新版本,还是回滚到之前的版本 凭证的添加:

image-20210630175020694 新增凭据,输入地址,账号,密码即可。
复制id到Jenkinsfile,替换为自己的git_auth,harbor_auth
具体说明,看注释即可
5.2上传部署脚本到服务器
在最后都通过ssh执行了远端服务器来执行部署脚本,这个部署脚本的功能也就是从Harbor拉取指定镜像的tag并启动,脚本内容具体如下:
#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
echo "$imageName"
#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
#停掉容器
docker stop $containerId
#删除容器
docker rm $containerId
echo "成功删除容器"
fi
#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
#删除镜像
docker rmi -f $imageId
echo "成功删除镜像"
fi
# 登录Harbor私服,修改为自己的账号密码
docker login -u user -p password $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName
echo "容器启动成功"将back_deploy.sh上传到192.168.99.224的/opt/jenkins_shell/下
scp root@192.168.99.224:/opt/jenkins_shell/back_deploy.sh前提是开启ssh免密登录,具体操作参考前面一章即可。
并对脚本添加可执行权限
chmod +x /opt/jenkins_shell/back_deploy.sh
6.新建Jenkins项目
6.1安装时间插件
因为在构建中使用到了时间参数,所以安装该插件
插件管理中安装:Date Parameter Plugin
6.2新建流水线项目
6.2.1添加构建参数
注意: 这下面的名称都和Jenkinsfile中的变量名要保持一致
添加分支参数

image-20210630181214118 添加部署类型参数

image-20210630181249266 添加发布版本tag参数

image-20210630181300476
6.2.2添加git配置

最后构建界面如图:

7.测试
7.1测试发布新版本
点击构建
Jenkins:
Harbor下有新的tag镜像:

192.168.99.224下拉取到构建的新镜像:
root@fanyao:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.99.78:85/webtest/webtest 2021-06-30_140002 5c138ade04e5 4 hours ago 122MB
docker运行状态:
root@fanyao:~# docker ps
CONTAINER ID IMAGE COMMAND PORTS NAMES
a2478184f4e7 192.168.99.78:85/webtest/webtest:2021-06-30_140002 "java -jar /app.jar" 0.0.0.0:8083->8083/tcp, :::8083->8083/tcp pedantic_hertz
访问接口
curl http://192.168.99.224:8083/hello
hello
测试发布成功
7.2测试回滚
需要登录Harbor查看要回滚的tag版本号:

在Jenkins的参数中选择回滚,并输入tag号:

再次点构建即可。
总结
通过Dockerfile和Jenkinsfile和Harbor以及基础的脚本组合,即可对一个单体的Boot项目进行发版和回滚。只需根据自己配置的情况来构建单体项目,当然微服务项目也以此类推。




