侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 292 篇文章
  • 累计创建 132 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Jenkins入门教程-3:Jenkins实战,实现CICD

孔子说JAVA
2022-05-10 / 0 评论 / 0 点赞 / 184 阅读 / 10,494 字 / 正在检测是否收录...

Jenkins是一款开源自动化服务器,旨在自动化连续集成和交付(CICD)软件所涉及的重复技术任务。在Jenkins入门教程-2:Ubuntu下Jenkins安装指南及详细配置中我们已经搭建好了Jenkins服务,本文在此基础上实现使用 jenkins 服务器控制 dev环境 和 线上release环境来完成CICD的流程演示。

1、CICD流程

1.1 传统打包部署模式

在实际开发中,我们经常要一边开发一边测试,这里的测试是指同组程序员将代码提交后,由测试人员测试(而不是程序员对自己代码的单元测试);或者前后端分离后,经常会修改接口,然后重新部署;这些情况都会涉及到频繁的打包部署;

手动打包常规步骤:

  • 1.个人提交代码到代码仓库,如gitee/github/svn
  • 2.问一下同组小伙伴有没有要提交的代码
  • 3.拉取代码并打包(war包,或者jar包)
  • 4.上传部署包到Linux服务器
  • 5.查看当前程序是否在运行
  • 6.关闭当前程序
  • 7.启动新的jar包
  • 8.观察日志看是否启动成功
  • 9.如果有小伙伴的代码还没有提交…重复1到8的步骤!(半天时间没了)

那么,有没有一种工具能够实现将代码提交到git后就自动打包部署,答案是肯定的:那就是Jenkins。

1.2 持续集成自动部署流程

CICD的步骤为:自动编译、打包、构建镜像、容器部署等,流程图如下:

20190327131025159

具体步骤:开发人员 push 代码到 gitee/github 仓库,触发 Jenkins 的自动构建流程(是由Jenkins编排文件设置的),这时候 Jenkins 会自动 pull 代码、进行 maven编译、打包,并通过自动化执行shell脚本使 docker构建镜像并 push 到私服(或者阿里云)仓库,此操作完成后 Jenkins 服务器上再执行SSH命令登录到部署服务器,docker 从仓库(私服)拉取镜像,启动容器。整个操作流程完成。

2、服务器环境及基础配置

2.1 需准备的服务器

生产环境下,Jenkins服务器和测试服务器位于不同的服务器,由于条件所限,我们采用同一台服务器。

jenkins服务器: 172.19.82.206
测试服务器: 172.19.82.206

这里的Jenkins服务器使用我们上个教程搭建的环境。需要确认下基础配置是否完成。

2.2 Jenkins安装插件

本例中我们使用的代码仓库为gitee。所以插件也需要安装 gitee 相关插件。

系统管理 -> 插件管理 中,查看已安装插件,确认 Jenkins 是否安装了 Gitee PluginPublish Over SSH 这2个插件,如果没有在 可选插件 中搜索对应插件并安装。

  • Gitee Plugin 插件通过伪造一个 Gitee CI 服务器将Gitee集成到 Jenkins。此插件允许 Gitee 在提交代码或打开/更新拉取请求时触发 Jenkins 中的构建。它还可以将构建状态发送回 Gitee。
  • Publish Over SSH 插件通过 SSH 发送构建工件,即通过SSH发送部署文件到远程机器上。
  • SSH Plugin 插件使用 SSH 协议远程执行 shell 命令。
  • Mask Passwords 此插件允许屏蔽可能出现在控制台中的密码。该插件还提供了一个非存储密码参数。

Jenkins plugins

2.3 Jenkins添加gitee凭据

系统管理 -> 凭据管理(Manage Credentials) 中,查看 凭据 列表,如果没有添加过你的gitee凭据,可以点击下方全局凭据右侧的小箭头,会弹出 添加凭据 的菜单,点击进入添加凭据页面。

1_20220430193054

在添加凭据页面,类型选择 Username with password, 范围选择 全局, 填入你的gitee的账号和密码,然后点击 Create 创建即可。 如下图所示。

1_20220430201718

添加完的凭据如图所示

1_20220430204323

3、Jenkins服务器上创建项目和构建配置

新建任务

点击左侧新建任务,输入你的任务名称,如 demo,选择构建自由风格的项目。

1_20220426194501

接着会跳转至Jenkins项目配置区。

大体步骤:General(基础配置)–》源码管理–》构建触发器–》构建环境–》构建–》构建后操作

3.1 配置 general

该配置项下的所有配置都可以不用配置,本例中我们不做任何配置,下面对各配置项做简要说明。

1_20220430221120

描述:就是注释,给我们这个job一个更便于其他查看的详解
GitHub 项目:里面配置响应的url和需要显示的名称就可以了
Gitee 链接:用于 Gitee Pull Request Webhook 触发的构建结果评论到的 Pull Request中,以及自动合并 Pull Request 等。
This build requires lockable resources:此构建需要可锁定的资源
Throttle builds:节流构建,通过设置时间段内允许并发的次数来实现构建的控制
丢弃旧的构建:设置构建历史的保存策略。

  • log Rotation 日志循环
  • 保持构建的天数 意思就是根据你所填写的天数来保存构建记录
  • 保持构建的最大个数 意思就是有几条构建记录就保存几条
  • 发布包保留天数 例如我们发布的war包等的保存天数
  • 发布包最大保留#个构建 例如我们发布了几个war包,就保存几个

参数化构建过程:参数允许您提示用户输入一个或多个将传递到构建中的输入。例如,您可能有一个项目通过允许用户上传包含要测试的二进制文件的 zip 文件来按需运行测试。这可以通过在此处添加文件参数来完成。
关闭构建:选中此选项后,将不会执行此项目的新构建。当您想暂时阻止构建项目时,这会很有帮助。
在必要的时候并发构建:选中此选项时,可以并行执行该项目的多个构建。默认情况下,一次只执行一个项目的构建——任何其他开始构建该项目的请求都将保留在构建队列中,直到第一个构建完成。这是一个安全的默认设置,因为项目通常需要独占访问某些资源,例如数据库或硬件。
静默期:如果设置此选项,一个计划中的构建在开始之前需要等待选项中设置的秒数。
重试次数:拉取源码重试的次数
该项目的上游项目正在构建时阻止该项目构建:用于上游项目有关联的构建策略
该项目的下游项目正在构建时阻止该项目构建:用于下游项目有关联的构建策略
使用自定义的工作空间:使该项目独立于系统的工作空间,默认jenkins的工作空间是在 .jenkins/workspace/task 中,可自定义工作空间。
显示名称:如果设置,则在整个 Jenkins Web GUI 中显示项目的可选显示名称。由于它仅用于显示目的,因此显示名称在项目中不需要是唯一的。如果未设置显示名称,Jenkins Web GUI 将默认显示项目名称。
保留构建的依赖日志:如果启用此选项,则从该项目 的构建中引用的所有构建(通过指纹)都将受到保护免受日志轮换。

3.2 配置 源码管理

选择源码管理项,Git选项,输入你Git仓库的地址,然后在Credentials处选择你之前添加过的gitee凭据,你也可以直接在这里添加你Git仓库的用户名和密码;并且选择监听master分支(默认就是)。

1_20220501095940

3.3 配置 构建触发器

我们需要的效果是一旦git仓库发生变化就要自动构建镜像,并且部署新的镜像容器,所以在构建触发器项下选择轮询SCM,使用corn表达式控制Jenkins监听git仓库的频率为每分钟一次。

  • 当您输入 “* * * * *” 时,意思为每分钟轮询一次, “H * * * *” 意思为每小时轮询一次

1_20220501100705

其他工程构建后触发:在其他项目构建完成后再进行构建。这里又分4种情况:

  1. 只有构建稳定时触发
  2. 即使构建不稳定时也会触发
  3. 即使构建失败时也会触发
  4. 始终触发,即使构建被中止

定时构建:隔一段时间build一次,不管版本库代码是否发生变化,通常不会采用此种方式。例如: 0 2 * * * (每天2:00 必须build一次源码)

轮询 SCM(Poll SCM):隔一段时间比较一次源代码如果发生变更,那么就build。否则,不进行build,通常采用这种方式; Jenkins会定时检查源码变更(根据SCM软件的版本号),如果有更新就checkout最新code下来,然后执行构建动作。配置如下: */5 * * * * (每5分钟检查一次源码变化,如果有更新才build)

在 Schedule中填入* * * * *,代表一分钟监听一次

  • 第一个参数代表的是分钟 minute,取值 0~59;
  • 第二个参数代表的是小时 hour,取值 0~23;
  • 第三个参数代表的是天 day,取值 1~31;
  • 第四个参数代表的是月 month,取值 1~12;
  • 最后一个参数代表的是星期 week,取值 0~7,0 和 7 都是表示星期天。

所以 0 * * * * 表示的就是每个小时的第 0 分钟执行一次构建。

五个*依次标识 分钟小时每月几号哪个月周几

例:

  • H/15 * * * * 每15分钟
  • H(0-29)/10 * * * * 每小时的0到29分钟每10分钟
  • H 2-19/2 * * 1-5 每周1到周五(工作日)2点到19点每2小时执行
  • H H 1,15 1-11 * 1到11月1号和15号各执行一次

3.4 配置 构建环境

选中 Mask passwords and regexes (and enable global passwords),在 Regular Expressions 下方点击 新增 按钮,然后在 Regex 下方的输入框中写入正则表达式 (?<=--password).*(?=\s)

  • (?<=) 表示断言以某某开始,即以 --password 开始
  • (?=)表示断言以某某结束,\s即以空格结束
  • 两个组合的效果就是,匹配出中间的部分,.*--password和空格中间的任意字符,也就是密码。

配置界面截图:
1_20220502000124

构建后控制台输出信息截图,如果不配置这个,密码将会以明文形式显示。

1_20220502000924

3.5 配置 构建

3.5.1 Jenkins服务器构建镜像并上传至镜像仓库

1)maven打包

方式一:调用顶层Maven目标方式构建

进入 构建 配置项, 选择 增加构建步骤 右侧的下拉箭头,选择 调用顶层Maven目标

1_20220501130705

在展开的对话框中,选择 Maven版本 并填写目标指令 clean install(也可以填写为clean package)。

1_20220501131051

该步骤配置完成后,保存配置,我们可以先执行 立即构建 ,测试下配置是否正确。构建过程中,可以点击左侧构建历史列表中的当前构建记录进入构建详情页面,点击左侧控制台输出可以看到构建的执行情况。

1_20220501131342

在页面最下方我们可以看到个构建失败的原因,The goal you specified requires a project to execute but there is no POM in this directory (/opt/jenkins/workspace/demo). Please verify you invoked Maven from the correct directory. -> [Help 1], 这是因为在构建目录下没有pom文件,我这里使用的demo项目只是一个文件夹,test工程目录是demo的子目录(test目录下才有pom文件),所以构建失败了。

方式二:执行shell方式构建

这里我们换个方式,通过 执行shell 的方式来构建。删除掉当前配置(调用顶层 Maven 目标 右侧的 X 按钮),选择 增加构建步骤 右侧的下拉箭头,选择 执行shell 。在展开的shell窗口中,填写构建脚本如下。

# 因为需要构建的test项目是demo的子目录,所以先要cd到test目录
cd /opt/jenkins/workspace/demo/test
mvn clean install

1_20220501132555

保存配置后我们再次执行 立即构建 ,测试下配置是否正确。

1_20220501132556

可以看到构建成功,通过 Build History下方的记录链接进入到构建详情页面,点击详情页面左侧的 控制台输出 可以进入查看构建的详细过程。

2)执行shell方式构建镜像

选择 增加构建步骤 右侧的下拉箭头,选择 执行shell 。在展开的shell窗口中,填写构建脚本如下。(如果上一步骤已经创建了shell脚本,可以直接加到之前的shell脚本后面)

  • 因为要执行docker命令,所以我们的Jenkins服务器需要安装docker环境。
echo "显示当前目录"
pwd
echo "显示当前目录下的文件目录"
ls -l
# Dockerfile文件所在的目录为/opt/jenkins/workspace/demo/test/deploy
docker build -t kongzid/java:test1.0.0 -f ./deploy/Dockerfile .

其中前4行代码都是打印了一些提示信息,方便我们查看执行情况,完全可以去掉。

1_20220501153015

保存配置后我们再次执行 立即构建 ,测试下配置是否正确。

1_20220501151803

可以看到,docker镜像已经构建成功。登录Jenkins服务器使用命令 docker images 可以查看到生成的docker镜像 java/test

1_20220501152357

Dockerfile文件存放在与src同级的deploy目录下。

1_20220501152629

附上Dockerfile文件的内容:

# 该镜像需要依赖的基础镜像
FROM java:8

# 维护者信息
MAINTAINER kongzi<153957433@qq.com>

# 将targer目录下的jar包复制到docker容器/home/jar目录下面
COPY ./target/*.jar /home/jar/test.jar

# 声明服务运行在8080端口
EXPOSE 8080

# 执行命令
CMD ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/home/jar/test.jar"]

3)将构建好的镜像推送到Docker Hub的Registry

选择 增加构建步骤 右侧的下拉箭头,选择 执行shell 。在展开的shell窗口中,填写构建脚本如下。(也可以加在上一步构建镜像shell脚本的后面)

# docker hub 登录
docker login --username=用户名 --password=密码
# 上传镜像到DockerHub仓库
docker push kongzid/java:test1.0.0
# 删除本地镜像
docker image rm kongzid/java:test1.0.0
# 删除本地因构建失败而生成的名称为none的镜像,这句脚本可能会失败,慎用
# docker images|grep none|awk '{print $3}' | xargs docker rmi

1_20220501210601

保存配置后我们再次执行 立即构建 ,测试下配置是否正确。查看构建结果,可以看到控制台最终输出Finished: SUCCESS, 构建状态也显示为绿色对勾。再登录DockerHub仓库也可以看到新上传的镜像。

1_20220501210900

3.5.2 从docker hub仓库下载镜像到目标服务器部署

Jenkins通过 SSH plugin 远程在目标服务器上(本示例中为测试服务器)执行 shell 命令,进行镜像的下载和容器的运行。

1)配置SSH凭证

Jenkins中打开系统管理->Manage Credentials,点击Stores scoped to Jenkins 下方的全局域后面的三角箭头,在弹出的下拉框中点击 添加凭据

1_20220502002800

在新建凭据页面,选择 Username with password类型,填入所要连接服务器的用户名和密码,输入该凭据的唯一标识id(可不填写,会自动生成,填写的这个值方便选择时候识别),填写描述信息(可为空)。

1_20220502003234

2)配置SSH

Jenkins中打开系统管理——>系统配置,下拉找到SSH remote hosts区域。点击 SSH sites 下方的新增按钮,配置选项如图所示:

image

配置说明:

  • Hostname:为linux服务器的ip地址;因为我们的jenkins服务器和测试服务器是一台机器,所以填写127.0.0.1。
  • Port:连接端口,默认22即可;
  • Credentials:凭证,即为前面步骤(配置SSH凭证)所加的凭据;
  • serverAliveInterval:所需的 serverAliveInterval 以毫秒为单位(0 = 关闭)。
  • timeout:等待连接的超时时间(以毫秒为单位)(0 = 默认超时),此处写5000。

配置完成后点击 Check connection 按钮,左侧显示 Successfull connection 即为连接成功;最后点页面下方的 保存 按钮完成配置。

3)测试服务器下载镜像并部署

在项目的构建部分,选择 增加构建步骤 右侧的下拉箭头,选择 Excute shell script on remote host using ssh 。在展开的对话框中,SSH site下会自动填入已经创建好的SSH配置信息 root@127.0.0.1:22 , 在 Command 命令行里填写我们要执行的shell命令。下面我们可以先填入一个测试命令 echo "test" > /root/hello.txt,该命令的作用是在远程主机上root目录下创建1个 hello.txt 文件,内容为test

  • 该插件的作用是在远程主机上执行 shell 命令。

image-1651424218220

保存配置后,我们点击页面左侧的 立即构建 按钮,当构建成功后,登录到远程主机上查看,/root/hello.txt 的文件内容和我们的预期是否一致。

image-1651424175897

测试成功,Jenkins中配置的shell命令在远程主机上正确的执行了。现在我们可以配置docker镜像的下载及安装部署了。

现在我们改下上述配置中的Command 命令行,把之前写的测试命令 echo "test" > /root/hello.txt 删掉,填入以下的命令(拉取镜像并启动容器):

# 拉取镜像
docker pull kongzid/java:test1.0.0
# 根据容器名称停止容器
docker stop test
# 根据容器名称删除容器
docker rm test
# 运行镜像,假设java项目端口为8081
docker run -p 8083:8080 -d --name test kongzid/java:test1.0.0

保存配置后我们再次执行 立即构建 ,查看构建结果,可以看到控制台最终输出Finished: SUCCESS, 构建状态也显示为绿色对勾。

![image-1651466729971](/upload/2022/05/image-1651466729971.png

我们可以登录到测试服务器,通过 docker ps 命令查看运行中的容器,显示容器已成功运行。

image-1651466941936

还可以通过浏览器访问应用,http://172.19.82.206:8083/hello, 返回了正常的页面。

image-1651467023349

4)更改代码后重新构建

这一步骤的作用是验证我们的CICD构建流程,和之前的操作完全一致,这里只简单叙述一下步骤:

本地更改代码 -> 提交到gitee仓库 -> giteee上合并代码到master分支 -> 登录Jenkins -> 找到对应的项目demo执行立即构建 -> 查看构建结果是否正确。

image-1651470350875

从图中可以看到,修改结果已经被部署到测试服务器。

4、Jenkins配置 构建后操作

本例中, 构建后操作 主要包括以下几点:

  • 发送打包文件到目标服务器
  • 重新启动服务

推荐的方式是将镜像上传到私服或公共仓库,目标服务器(本例中指测试服务器)再通过docker仓库下载镜像进行部署。上述步骤已经实现了将镜像推送到Docker Hub的Registry。还有一种方式就是接下来要介绍的:通过ssh publish发送打包文件(本例是jar包)到目标服务器。

  • 建议使用前面方式,即通过镜像上传到私服或公共仓库,再通过测试服务器直接下载使用。

ssh publish发送打包文件到目标服务器并启动服务

此方式是将jar包通过ssh发送到测试部署服务器,然后通过java命令启动或tomcat部署,不需要前面的构建镜像步骤。

4.1 生成Jenkins的私钥

要先在jenkins所在的机器上生成秘钥。生成方式为:

ssh-keygen -t rsa         #产生公钥与私钥对

在shell窗口中输入命令后回车,当提示Enter passphrase (empty for no passphrase)时输入密码 111111,然后会提示Enter same passphrase again:(意思再次输入确认密码), 再次输入确认密码 111111。回车直到生成了秘钥文件。此时在 用户名文件夹/.ssh/文件夹下生成两个文件:

  • is_rsa 为密钥文件
  • id_rsa.pub 为公钥文件

1_20220501161313

查看所生成私钥的格式:

root@xnzysq20210118001:~/.ssh# more /root/.ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCqnCPf7t
UqxH4YccGGWXb4AAAAEAAAAAEAAAGXAAAAB3NzaC1yc2EAAAADAQABAAABgQDMfGtHN0UI
......

可以看到密钥的首行是:

-----BEGIN OPENSSH PRIVATE KEY——

生成密钥的openssh的版本过高,而jenkins现有的版本在检验密钥时还不支持这种格式(可以通过 cat /opt/jenkins/config.xml 命令查看Jenkins版本,可以在登录Jenkins首页的右下角看到版本号)。所以我们需要指定生成秘钥的格式:

ssh-keygen -m PEM -t rsa -b 4096
  • -m 参数指定密钥的格式,PEM是rsa之前使用的旧格式
  • -b 指定密钥长度。对于RSA密钥,最小要求768位,默认是2048位。

按上述语句生成秘钥后,查看所生成私钥的格式:

root@xnzysq20210118001:~/.ssh# more /root/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,533BE3103BDFEAD081AB3C36FAA93078

cQnurtw7ITuz9X/f7fOhO2LWdrrJy5AN0aIXh53hNOExvCDKH4xcdR2JCv8Dlhbm
EoRWEyiiXu6vYh+ASnwpVqOaoE7RvK7cT3hxbe3yVGcROKwtru19OpG1dvjclqF3
aogS0XwEL7PNAFvHXHKn2nQgBJ8nTthtT64F2X/pgFxipRNkkfm7oS1Af5h+3QTw
......

可以看到密钥的首行是:

-----BEGIN RSA PRIVATE KEY-----

这样改动后可以通过jenkins对密钥格式的验证。

4.2 将公钥文件复制到目标服务器

通过以下语句将公钥文件复制到目标服务器,因为我们的Jenkins和测试机是一台服务器,所以语句最后的ip填写为127.0.0.1:

  • ssh-copy-id命令可以把本地主机的公钥复制到远程主机的authorized_keys文件上,ssh-copy-id命令也会给远程主机的用户主目录(home)和/.ssh, 和/.ssh/authorized_keys设置合适的权限。
ssh-copy-id -i /root/.ssh/id_rsa.pub root@127.0.0.1

执行此命令后会提示是否确认和目标机器建立连接,输入 yes 后回车,接着会提示你输入目标服务器的密码,输入之后回车,若密码正确就会建立连接。

1_20220501163831

4.3 配置Publish Over SSH

Jenkins中打开系统管理——>系统配置,下拉到底部的Publish over SSH区域。配置选项如下:

  • Passphrase:填写生成秘钥时的密码,如果生成秘钥没有加密码,直接enter到底生成的,则这里不用填写。我们这里填写111111
  • Path to key:填写私钥的路径,没尝试,因为在下面填写了私钥key。
  • Key:私钥的值。要将前后的-----BEGIN RSA PRIVATE KEY----------END RSA PRIVATE KEY-----带着。
  • 点击SSH Servers的“增加”,新添目标服务器。
    • Name:你起的可以分辨服务器的名称。
    • Hostname:目标服务器的ip,一般服务器之间交互的话用内网ip就行。因为我这里jenkins服务器和所部署的服务器位于同一台服务器中,故写的是127.0.0.1
    • Username:登录目标服务器的账号,需要写通过ssh-copy-id命令建立连接所用的账号。
    • Remote Directory:将jenkins构建的文件发送到目标服务器的哪个文件夹下。

1_20220501161314

配置完成后,点击右下角的 测试配置 按钮,在左下角如果提示 成功,表示配置正确。最后点保存按钮完成配置。

1_20220501171915

4.4 发送打包文件到目标服务器并启动服务

配置 构建后操作 项,点击 增加构建后操作步骤 右侧的下拉箭头,选择 Send build artifacts over SSH, 进行通过SSH发送部署包的相关配置。

1_20220501173558

Send build artifacts over SSH 配置页面,主要包括以下配置参数:

  • SSH Server Name: 会默认选中前面配置的SSH服务器test-server
  • Transfers:这里输入的是你希望传到服务器的文件夹和文件,路径是相对jenkins的workspace的项目名称的,这里我们写 target/*.jar
  • Remove prefix:如果Source files为target/*.jar,但是不想把target目录创建到服务器端,这个时候就可以在Remove prefix里填入target
  • Remote directory: 这里指定文件将被拷贝到服务器的路径,注意,被拷贝文件在服务器上的完整路径=登录服务器账号的默认路径+Remote directory,这里填写 /usr/local/demo
  • Exec command: 启动命令,执行脚本
    cd /usr/local/demo
    java -jar test.jar --server.port=8083
0

评论区