🔜什么是Jenkins?🔚

Jenkins是一款基于Java开发的开源 CI&CD 软件,用于自动化各种任务,包括构建、测试和部署软件。Jenkins提供多种安装方式,提供超过1000个插件来满足任何项目的需要。

Jenkins的特征:

  • 开源的Java语言开发持续集成工具,支持持续集成,持续部署。
  • 易于安装部署配置:可通过yum安装,或下载war包以及通过docker容器等快速实现安装部署,可方便web界面配置管理。
  • 消息通知及测试报告:集成RSS/E-mail通过RSS发布构建结果或当构建完成时通过e-mail通知,生成JUnit/TestNG测试报告。
  • 分布式构建:支持制Jenkins能够让多台计算机一起构建/测试。
  • 文件识别:Jenkins能够跟踪哪次构建生成哪些jar,哪次构建使用哪个版本的jar等。
  • 丰富的插件支持:支持扩展插件,你可以开发适合自己团队使用的工具,如git,svn,maven,docker等。

本文通过GitLab+Jenkins+Tomcat,构建CI/CD流程。

主机规划

主机名 ip 所需软件 用途
121 192.168.1.121 GitLab-12.4.2 代码托管
124 192.168.1.124 Jenkins、JDK-21、Maven-3.9.9、
Git、SonarQube
Jenkins持续集成
125 192.168.1.125 JDK-1.8、Tomcat-8.5 发布测试

服务器操作系统为centos7.9

部署步骤

部署GitLab

安装GitLab

安装依赖

1
yum -y install policycoreutils-python policycoreutils postfix

下载并安装gitlab

1
2
3
4
#下载gitlab安装包
curl -O http://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-12.4.2-ce.0.el7.x86_64.rpm
#安装gitlab
rpm -i gitlab-ce-12.4.2-ce.0.el7.x86_64.rpm

修改gitlab默认访问端口

1
2
3
4
5
vi /etc/gitlab/gitlab.rb

#将默认端口80修改为82
external_url "http://192.168.1.121:82"
nginx['listen_port'] = 82

重载配置,启动gitlab

1
2
gitlab-ctl reconfigure
gitlab-ctl restart

配置防火墙策略

1
2
3
firewall-cmd --add-port=82/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all

在浏览器中输入http://192.168.1.121:82/,修改root用户密码,并用root用户登录gitlab

管理GitLab

(1)创建组

使用管理员root创建组,一个组里面可以有多个项目分支,可以将开发添加到组里面进行设置权限,不同的组就是公司不同的开发项目或者服务模块,不同的组添加不同的开发即可实现对开发设置权限的管理。

(2)创建项目

(3)创建用户

在管理中心-概览-用户中,创建一个新用户test1,并设置密码,将用户加入刚创建的项目中。

Gitlab用户在组里面有5种不同权限:

  • Guest:可以创建issue、发表评论,不能读写版本库
  • Reporter:可以克隆代码,不能提交,QA、PM可以赋予这个权限
  • Developer:可以克隆代码、开发、提交、push,普通开发可以赋予这个权限
  • Maintainer:可以创建项目、添加tag、保护分支、添加项目成员、编辑项目,核心开发可以赋予这个权限
  • Owner:可以设置项目访问权限Visibility Level、删除项目、迁移项目、管理组成员,卉发组组长可以赋予这个权限

上传项目代码

使用idea创建java项目,并上传至gitlab仓库

本文中使用的java项目代码,源自b站up主,’’涣沷a靑惷’’,原文链接为: https://www.yuque.com/huanfqc/jenkins/jenkins。

java代码地址为: https://share.feijipan.com/s/qdEO7czl

将项目导入idea中,并配置gitlab相关设置,推送代码,具体步骤参考上面提到的原文链接。

部署Jenkins

安装jenkins-2.19*版本时,无法正常安装中文插件。本文使用的jdk为jdk-21、jenkins为2.492.3,且均为rpm方式安装

(1)安装jdk

1
2
3
4
yum install -y wget && wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.rpm
rpm -ivh jdk-21_linux-x64_bin.rpm
#查看版本
java -version

(2)安装Jenkins

1
2
3
4
#下载jenkins
curl -O https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/jenkins-2.492.3-1.1.noarch.rpm
#安装
rpm -ivh jenkins-2.492.3-1.1.noarch.rpm

(3)修改jenkins的配置文件

1
2
3
4
5
vi /etc/sysconfig/jenkins
#修改默认用户为root
JENKINS_USER="root"
#修改默认端口为8888
JENKINS_PORT=8888

(4)配置防火墙策略,并启动jenkins

1
2
3
4
5
6
7
firewall-cmd --add-port=8888/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all
#启动jenkins
systemctl daemon-reload
systemctl start jenkins
systemctl enable jenkins

(5)查看jenkins的admin初始化密码

1
cat /var/lib/jenkins/secrets/initialAdminPassword

(6)在浏览器中输入http://192.168.1.124:8888/访问,输入admin初始化密码。

(7)点击选择插件来安装,选择,跳过安装插件,为之后重新配置下载插件的国内源做准备。

(8)按引导完成jenkins的安装。

配置国内插件源

(1)选择左侧边栏中的Jenkins -Manage Jenkins-Manage Plugins,选择Available,等待插件相关文件的加载。

(2)进入插件的目录,将地址修改为国内源

1
2
3
cd /var/lib/jenkins/updates && ll
sed -i 's|http://updates.jenkins-ci.org/download|https://mirrors.tuna.tsinghua.edu.cn/jenkins|g' default.json
sed -i 's|http://www.google.com|https://www.baidu.com|g' default.json

(3)访问jenkins,选择左侧边栏中的Jenkins -Manage Jenkins-Manage Plugins,选择Advanced,把Update Site改为https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json(或者https://mirrors.huaweicloud.com/jenkins/updates/update-center.json),保存,在浏览器中输入http://192.168.1.124:8888/restart,点击并重启jenkins。

设置中文

安装中文插件,选择左侧边栏中的Jenkins -Manage Jenkins-Manage Plugins,选择Advanced,搜索chinese,勾选插件,并点击下载并重启。

管理用户权限

安装Role-based Authorization Strategy插件,管理用户权限。安装完成后,(新版jenkins)选择Manage Jenkins-Security,授权策略选择Role-Based Strategy。选择Manage Jenkins-Manage and Assign Roles,进行角色的创建和分配管理。

凭证管理

(1)安装Credentials Binding插件,进行凭证管理。

凭证类型:

  • Username with password:用户名和密码
  • SSH Username with private key:使用ssH用户和密钥
  • Secret file:需要保密的文本文件,使用时Jenkins会将文件复制到一个临时目录中,再将文件路径设置到一个变量中,等构建结束后,所复制的Secret file就会被删除。
  • Secret text:需要保存的一个加密的文本串,如钉钉机器人或Github的api token
  • Certificate:通过上传证书文件的方式

常用的凭证类型有:Username with password(用户密码)和SSH Username with private key(SSH密钥)

(2)安装git插件,并在服务器上下载git。

1
yum -y install git
密码凭证

(1)创建jenkins项目和密码凭证。选择Manage Jenkins-Credentials,点击全局-Add Credentials,添加gitlab用户test1的用户名和密码,创建凭证。

(2)创建一个新任务test01,点击配置,设置源码管理为Git,填写gitlab的项目仓库地址(http开头),选择test1的凭证,保存即可。

(3)进入test01,点击Build Now,等待任务构建完成后,点击控制台输出查看详细信息。

SSH密钥凭证

(1)在jenkins服务器中创建SSH密钥。

1
2
3
4
5
6
7
ssh-keygen -t rsa
#查看公钥内容
cat ~/.ssh/id_rsa.pub
# 测试 SSH 连接
ssh -T git@192.168.1.121
# 查看是否有gitlab主机,确保有该主机,否则使用ssh凭证时会报错
cat ~/.ssh/known_hosts

(2)使用管理员账户登录Gitlab,选择设置-SSH密钥,填入SSH公钥内容,并保存。

(3)在服务器中使用命令cat ~/.ssh/id_rsa,查看私钥内容。在jenkins中创建SSH密钥凭证,输入用户名root和SSH私钥内容,保存即可。

(4)创建一个新任务test02,点击配置,设置源码管理为Git,填写gitlab的项目仓库地址(git开头),选择SSH凭证,保存即可。

(5)进入test02,点击Build Now,等待任务构建完成后,点击控制台输出查看详细信息。

安装Maven

(1)下载安装Maven

1
2
3
4
5
6
7
8
9
10
11
curl -O https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz
#创建存储目录
mkdir -p /opt/maven
tar -vxzf apache-maven-3.9.9-bin.tar.gz -C /opt/maven/
#配置环境变量,使环境生效
echo "
export MAVEN_HOME=/opt/maven/apache-maven-3.9.9
export PATH=\$PATH:\$MAVEN_HOME/bin" >> /etc/profile
source /etc/profile
#查看maven版本
mvn -v

(2)配置jenkins与maven关联

在Manage Jenkins-Tools中配置JDK安装Maven安装,配置其对应安装路径。

在Manage Jenkins-System-全局属性中,新增3个Environment variables

(3)修改Maven的本地仓库位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#创建本地仓库
mkdir -p /data/jenkins/repo
#修改Maven的配置文件
vi /opt/maven/apache-maven-3.9.9/conf/settings.xml
#将<localRepository>/path/to/local/repo</localRepository>修改为
<localRepository>/data/jenkins/repo</localRepository>

#在<id>maven-default-http-blocker</id>所在的镜像后添加阿里云镜像源
# <mirror>
# <id>maven-default-http-blocker</id>
# <mirrorOf>external:http:*</mirrorOf>
# <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
# <url>http://0.0.0.0/</url>
# <blocked>true</blocked>
# </mirror>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<mirrorOf>central</mirrorOf>
</mirror>

(4)测试Maven配置

在jenkins中选择任务test02,选择配置-Environment-Build Steps,选择Execute shell中输入命令mvn clean package,保存后,点击Build Now,等待任务构建完成后,点击控制台输出查看详细信息。

此时服务器上的test02任务目录中会新增一个target目录。

[root@124 workspace]# ls
test01 test01@tmp test02 test02@tmp
[root@124 workspace]# cd test01
[root@124 test01]# ls
pom.xml src
[root@124 test01]# cd ..
[root@124 workspace]# ls
test01 test01@tmp test02 test02@tmp
[root@124 workspace]# cd test02
[root@124 test02]# ls
pom.xml src target
[root@124 test02]# pwd
/var/lib/jenkins/workspace/test02
[root@124 test02]#

安装Tomcat

下载jdk-1.8和tomcat-9

1
2
3
4
5
6
7
8
yum install -y java-1.8.0-openjdk*
curl -O https://mirrors.huaweicloud.com/apache/tomcat/tomcat-9/v9.0.104/bin/apache-tomcat-9.0.104.tar.gz
#创建存储目录
mkdir -p /opt/tomcat/
#解压
tar -zxvf apache-tomcat-9.0.104.tar.gz -C /opt/tomcat/
#启动tomcat
/opt/tomcat/apache-tomcat-9.0.104/bin/startup.sh

配置防火墙策略

1
2
3
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all

在浏览器中访问http://192.168.1.125:8080/

配置tomcat的用户角色

1
2
3
4
5
6
7
8
9
10
11
12
13
vi  /opt/tomcat/apache-tomcat-9.0.104/conf/tomcat-users.xml

<!--在tomcat-users标签下添加以下内容 -->

<role rolename="tomcat"/>
<role rolename="role1"/>
<role rolename="manager-script"/>
<role rolename="manager-gui"/>
<role rolename="manager-status"/>
<role rolename="admin-gui"/>
<role rolename="admin-script"/>
<user username="tomcat" password="tomcat" roles="manager-gui,manager-script,tomcat,admin-gui,admin-script"/>

配置tomcat的远程访问地址范围

1
2
3
4
5
vi /opt/tomcat/apache-tomcat-9.0.104/webapps/manager/META-INF/context.xml
<!-- 将以下内容注释-->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />

重启tomcat,输入用户名和密码进行访问。

1
2
3
4
#停止运行
/opt/tomcat/apache-tomcat-9.0.104/bin/shutdown.sh
#启动
/opt/tomcat/apache-tomcat-9.0.104/bin/startup.sh

Jenkins构建项目

Jenkins中自动构建项目的类型有很多,常用的有以下三种:

  • 自由风格软件项目(FreeStyle Project)
  • Maven项目(Maven Project)
  • 流水线项目(Pipeline Project)

本文构建项目时使用的war包,源自b站up主,’’涣沷a靑惷’’,原文链接为: https://www.yuque.com/huanfqc/jenkins/jenkins。

war包项目代码地址为:https://share.feijipan.com/s/BWEO9Jad,war包构建具体过程见原文。

Jenkins构建自由风格项目

(1)安装 Deploy to container 插件

(2)新建项目freestyle_demo,配置并拉取gitlab中test_war代码,该过程除包含步骤《部署Jenkins》的过程外,还需进行构建后操作,具体如下图。

(3)配置保存后,,点击Build Now,等待任务构建完成后,访问tomcat,可以看到/websocketChat-1.0-SNAPSHOT虚拟目录已出现。

Jenkins构建Maven项目

(1)安装Maven Integration插件

(2)新建项目maven-demo,配置并拉取gitlab中test_war代码,该过程除包含步骤《Jenkins构建自由风格项目》的过程外,还需要在Build时进行修改,具体如下图。

构建时出现报错可将之前配置的阿里云镜像地址改为https

(3)配置保存后,点击Build Now,等待任务构建完成后,访问tomcat,可以看到/websocketChat-1.0-SNAPSHOT虚拟目录已出现。

Jenkins构建Pipeline流水线项目

Pipeline,简单来说,就是一套运行在Jenkins上的工作流框架,将原来独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排和可视化的工作。

如何创建Jenkins Pipeline呢?

  • Pipeline脚本是由Groovy语言实现的。

  • Pipeline支持两种语法:Declarative(声明式)和Scripted Pipeline(脚本式)语法。

  • Pipeline也有两种创建方法:可以直接在Jenkins的Web Ul界面中输入脚本;也可以通过创建一个Jenkinsfile脚本文件放入项目源码库中(一般我们都推荐在Jenkins中直接从源代码控制(SCM)中直接载入Jenkinsfile Pipeline这种方法)。

在Jenkins的Web Ul中创建Pipeline脚本发布项目

(1)安装Pipeline插件

(2)新建任务Pipeline-demo,使用声明式语法,在Jenkins的Web Ul里创建Pipeline脚本;实现从代码拉取、编译构建、到发布项目。

在Pipeline-demo的配置界面,选择构建触发器-流水线,选择一个脚本模板Hello Word。

点击流水线语法,在片段生成器中选择checkout:Check out from version control,按引导填写项目地址和凭证,生成流水线脚本,将拉取代码脚本粘贴到修改后的模板中。

在片段生成器中选择sh:Shell Script,填写编译命令,生成流水线脚本,将脚本粘贴到修改后的模板中。

在片段生成器中选择deploy:Deploy war/ear to a container,按引导填写,生成流水线脚本,将脚本粘贴到修改后的模板中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pipeline {
agent any

stages {
stage('拉取代码') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/test_war_demo.git']])
}
}
stage('编译构建') {
steps {
sh 'mvn clean package'
}
}
stage('发布项目') {
steps {
deploy adapters: [tomcat9(credentialsId: '4d9b76aa-078c-462b-81f1-33fe1d9c971c', path: '', url: 'http://192.168.1.125:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
}

(3)配置保存后,点击Build Now,等待任务构建完成后,访问tomcat,可以看到/websocketChat-1.0-SNAPSHOT虚拟目录已出现。

使用Jenkinsfile脚本发布项目

(1)在idea中的项目目录下,选择New-File,创建Jenkinsfile文件,将Pipeline脚本内容粘贴进去,随代码一起发布到项目仓库中。

(2)在任务Pipeline-demo的配置界面,选择构建触发器-流水线,定义内容选择Pipeline script from SCM-GIt,填写项目地址和凭证,脚本路径填写Jenkinsfile

(3)配置保存后,点击Build Now,等待任务构建完成后,访问tomcat,可以看到/websocketChat-1.0-SNAPSHOT虚拟目录已出现。

常用构建触发器

Jenkins内置4种构建触发器:

  • 触发远程构建

  • 其他工程构建后触发(Build after other projects are build)

  • 定时构建(Build periodically)

    定时字符串从左往右分别为:分 时 日 月 周

    定时表达式的例子:

    每30分钟构建一次:H代表形参

    H/30

    每2个小时构建一次:

    H H/2 *

    每天的8点,12点,22点,一天构建3次:(多个时间点中间用逗号隔开)

    0 8,12,22 *

  • 轮询SCM(Poll SCM)

轮询SCM,是指定时扫描本地代码仓库的代码是否有变更,如果代码有变更就触发项目构建。

(1)触发远程构建

在任务Pipeline-demo的配置界面,选择构建触发器-触发远程构建 (例如,使用脚本),自定义身份验证令牌为test,保存配置。在浏览器中访问:

jenkins地址/job/Pipeline-demo/build?token=TOKEN_NAME

http://192.168.1.124:8888/job/Pipeline-demo/build?token=test ,返回查看任务状态已经开始构建。

(2)其他工程构建后触发(Build after other projects are build)

当需要多个任务先后执行时可用。比如若希望执行freestyle_demo任务后,再执行Pipeline-demo,在任务Pipeline-demo的配置界面,选择构建触发器-Build after other projects are built,中输入freestyle_demo,选择只有构建稳定时触发,保存配置。freestyle_demo任务构建完成后,freestyle_demo开始进行构建。

(3)定时构建(Build periodically)

在任务Pipeline-demo的配置界面,选择构建触发器-Build periodically,设置*/1 * * * *(一分钟一次),保存配置,freestyle_demo任务会每分钟构建一次。

(4)轮询SCM(Poll SCM)

轮询SCM也要设置时间周期,不过与定时构建不同的是,如果在时间周期内代码仓库未发生变化,任务构建就不会进行。比如:在任务Pipeline-demo的配置界面,选择构建触发器-Poll SCM,设置*/1 * * * *(一分钟一次),保存配置。如果在之后的一分钟内代码变更,Pipeline-demo任务会进行构建,反之,直到代码变更后的那一分钟周期内进行构建。

Git hook构建触发器(常用)

当GitLab出现代码变更时,会提交构建请求到Jenkins,Jenkins收到请求后,触发构建。

(1)安装GitLab插件和GitLab Hook插件(新版本自带GitLab Hook插件)

(2)在Jenkins的任务Pipeline-demo的配置界面,选择构建触发器-Build when a change is pushed to GitLab. GitLab webhook URL: http://192.168.1.124:8888/project/Pipeline-demo,会出现以下表格中的选项,默认选择即可。

事件类型 触发条件
Push Events 代码推送到分支或标签,包括新分支创建。
Push on Branch Delete 分支被删除时。
Opened Merge Request 创建新的合并请求时触发。
New Commits in MR 向已存在的MR推送新提交时触发(更新MR)。
Accepted (Merged) MR 合并请求被合并到目标分支(如main)时触发。
Closed MR 合并请求被关闭(未合并)时触发。

(3)在Jenkins中选择Manage Jenkins-System-GitLab中,取消勾选Enable authentication for '/project' end-point,保存设置。

(4)在GitLab的管理员账户中选择管理中心-设置-网络-外发请求中勾选Allow requests to the local network from web hooks and services ,保存配置。

(5)在GitLab的项目仓库中选择设置-集成,输入webhook URL,选择默认配置,保存。在生成的Webhook右侧,选择Test-Push events,显示Hook executed successfully: HTTP 200,即为成功。

参数化构建

(1)在源码中创建分支v1,并修改Jenkinsfile脚本中的分支名称,提交代码到gitlab。

修改前: checkout scmGit(branches: [[name: ‘*/master’]]

修改后:checkout scmGit(branches: [[name: ‘*/${branch}’]]

(2)在Jenkins的任务Pipeline-demo的配置界面,选择This project is parameterized-String Parameter,具体设置如下图。

(3)保存设置,在任务Pipeline-demo界面选择Build with Parameters,输入分支的名称,点击Build,进行构建。

配置邮件服务器

(1)安装Email Extension TemplateVersion插件

(2)选择Manage Jenkins-Credentials,点击全局-Add Credentials,创建邮件服务器的密码凭证,账户为邮箱地址,密码为获取的邮箱授权码。

(3)选择System,在Jenkins Location``-系统管理员邮件地址出输入注册邮箱,在Extended E-mail Notification处,输入注册邮箱和端口,点击高级,选择密码凭证,勾选Use SSL,在Default user e-mail suffix中邮箱后缀,Default Content Type选择HTML (text/html)Default Recipients输入注册邮箱,在邮件通知部分输入SMTP服务器和用户默认邮件后缀,点击高级完善信息,勾选通过发送测试邮件测试配置测试邮件服务器。

(4)构建邮件服务器模板

在项目根目录下创建email.html模板

1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>

</head>

<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0"
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
<td>(本邮件是程序自动下发的,请勿回复!)</td>

</tr>

<tr>
<td><h2>
<font color="#0000FF">构建结果 - ${BUILD_STATUS}</font>

</h2></td>

</tr>

<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>

<hr size="2" width="100%" align="center" /></td>

</tr>

<tr>
<td>
<ul>
<li>项目名称&nbsp;&nbsp;${PROJECT_NAME}</li>

<li>构建编号&nbsp;&nbsp;第${BUILD_NUMBER}次构建</li>

<li>触发原因:&nbsp;${CAUSE}</li>

<li>构建日志:&nbsp;<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>

<li>构建&nbsp;&nbsp;Url&nbsp;&nbsp;<a href="${BUILD_URL}">${BUILD_URL}</a></li>

<li>工作目录&nbsp;&nbsp;<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>

<li>项目&nbsp;&nbsp;Url&nbsp;&nbsp;<a href="${PROJECT_URL}">${PROJECT_URL}</a></li>

</ul>

</td>

</tr>

<tr>
<td><b><font color="#0B610B">Changes Since Last
Successful Build:</font></b>

<hr size="2" width="100%" align="center" /></td>

</tr>

<tr>
<td>
<ul>
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>

</ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat="&nbsp;&nbsp;&nbsp;&nbsp;%p"}
</td>

</tr>

<tr>
<td><b>Failed Test Results</b>

<hr size="2" width="100%" align="center" /></td>

</tr>

<tr>
<td><pre
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>

<br /></td>

</tr>

<tr>
<td><b><font color="#0B610B">构建日志 (最后 100行):</font></b>

<hr size="2" width="100%" align="center" /></td>

</tr>

<tr>
<td><textarea cols="80" rows="30" readonly="readonly"
style="font-family: Courier New">${BUILD_LOG, maxLines=100}</textarea>

</td>

</tr>

</table>

</body>

</html>

(5)修改Jenkinsfile文件,添加与stages同级的post部分,添加构建后发送邮件

1
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
pipeline {
agent any

stages {
stage('拉取代码') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/test_war_demo.git']])
}
}
stage('编译构建') {
steps {
sh 'mvn clean package'
}
}
stage('发布项目') {
steps {
deploy adapters: [tomcat9(credentialsId: '4d9b76aa-078c-462b-81f1-33fe1d9c971c', path: '', url: 'http://192.168.1.125:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
post {
always {
emailext(
subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS}!',
body: '${FILE,path="email.html"}',
to: '邮箱地址1,邮箱地址2'
)
}
}
}

安装SonarQube

Jenkins集成SonarQube进行代码审查。

SonarQube7.9开始不再支持mysql,SonarQube7.8安装支持mysql >=5.6 && <8.0

(1)安装SonarQube前需要安装mysql数据库

1
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
#配置mysql5.7的yum源
vi /etc/yum.repos.d/mysql-community.repo

[mysql-connectors-community]
name=MySQL Connectors Community
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-connectors-community-el7-$basearch/
enabled=1
gpgcheck=1
gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2022

[mysql-tools-community]
name=MySQL Tools Community
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-tools-community-el7-$basearch/
enabled=1
gpgcheck=1
gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2022

[mysql-5.7-community]
name=MySQL 5.7 Community Server
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-$basearch/
enabled=1
gpgcheck=1
gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2022


#安装mysql
yum -y install mysql-server
# 查看版本
mysql -V
systemctl start mysqld
systemctl enable mysqld
# 查看MySQL的初始密码
grep "password" /var/log/mysqld.log
# MySQL的安全性配置
mysql_secure_installation
#按引导配置完后,登录并创建数据库
mysql -uroot -p
create database sonar;
#查看数据库
show databases;

(2)安装SonarQube

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#配置系统相关参数
echo "vm.max_map_count=524288
fs.file-max=131072" >> /etc/sysctl.conf
sysctl -p

#下载依赖工具
yum install -y unzip
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-7.8.zip
mkdir -p /opt/sonar
unzip -q sonarqube-7.8.zip -d /opt/sonar
#创建用户
useradd sonar
passwd sonar
#修改sonarqube文件权限
chown -R sonar:sonar /opt/sonar/sonarqube-7.8

(3)修改conf目录下的sonar.properties配置文件

1
2
3
sonar.jdbc.username=root
sonar.jdbc.password=数据库密码
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false

(4)修改conf目录下wrapper.conf的jdk-1.8的路径

1
wrapper.java.command=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/bin/java

(5)进入bin/linux-x86-64/目录,使用sonar用户启动sonarqube

1
2
3
4
su sonar
./sonar.sh start
#查看启动日志
tail ../../logs/sonar.log

使用默认账户登录,账号密码都是admin

(6)登录sonarqube后,选择 Administration - Security- Global Permissions,为admin勾选 Administer SystemAdministerExecute AnalysisCreate 权限。单击右上角头像下拉框,选择 My Account - Security,随意填写token名称,完成 Token 的创建。

配置Jenkins与sonarqube集成

(1)在Jenkins上安装SonarQube Scanner插件,安装完成后,选择Manage Jenkins -Tools-SonarQube Scanner 安装,点击新增SonarQube Scanner ,输入名称,版本选择SonarQube Scanner 4.2.0.1873,点击保存。

SonarQube 7.8 对应 Sonar-Scanner 4.2

SonarQube 8.9 LTS 对应 Sonar-Scanner 4.6

(2)在Jenkins中配置SonarQube的token凭证。选择类型为Secret text,输入token,点击创建。

(3)在Jenkins中选择System-SonarQube installations,点击Add SonarQube,输入SonarQube的地址、选择创建的token凭证,保存集成SonarQube。

非流水线任务添加SonarQube代码审查

在freestyle_demo任务中选择配置-Build Steps,点击增加构建步骤,选择Execute SonarQube Scanner,选择JDK,输入分析内容,保存配置后,点击Build Now,等待任务构建完成。在SonarQube里查看代码分析结果。

1
2
3
4
5
6
7
8
9
sonar.projectKey=websocketChat
sonar.projectName=websocketChat
sonar.projectVersion=1.0
sonar.sources=.
sonar.java.binaries=./target/classes
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
sonar.sourceEncoding=UTF-8

流水线任务添加SonarQube代码审查

(1)在项目根目录下,创建sonar-project.properties,写入以下内容。

1
2
3
4
5
6
7
8
9
sonar.projectKey=Pipeline-demo
sonar.projectName=Pipeline-demo
sonar.projectVersion=1.0
sonar.sources=.
sonar.java.binaries=./target/classes
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
sonar.sourceEncoding=UTF-8

(2)在Jenkinsfile的stages前,引入在Jenkins中安装的SonarQube Scanner作为预置环境变量,之后在拉取代码步骤后,添加审查代码的步骤。

1
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
pipeline {
agent any
environment {
//引入在Jenkins中安装的SonarQube Scanner
scannerHome = tool 'sonar-scanner-jenkins'
}
stages {
stage('拉取代码') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/test_war_demo.git']])
}
}
stage('审查代码') {
steps {
//引入在Jenkins中配置的SonarQube服务器设置
withSonarQubeEnv('SonarQube-jenkins') {
sh '${scannerHome}/bin/sonar-scanner'
}
}
}
stage('编译构建') {
steps {
sh 'mvn clean package'
}
}
stage('发布项目') {
steps {
deploy adapters: [tomcat9(credentialsId: '4d9b76aa-078c-462b-81f1-33fe1d9c971c', path: '', url: 'http://192.168.1.125:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
post {
always {
emailext(
subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS}!',
body: '${FILE,path="email.html"}',
to: '邮箱地址'
)
}
}
}

(3)代码完成变更后,在流水线任务执行完成,在SonarQube里查看代码分析结果。

应用案例

该应用案例参考来源于b站up主,’’涣沷a靑惷’’,原文链接为: https://www.yuque.com/huanfqc/jenkins/jenkins。

使用Jenkins+GitLab+Docker+SonarQube,在192.168.1.125上部署若依的springboot前后端分离项目。

环境准备

设置Jenkins服务器免密登录192.168.1.125

1
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.1.125

安装docker

1
2
3
4
5
6
7
8
9
10
11
12
13
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)
#修改镜像源和默认配置文件路径
vi /etc/docker/daemon.json
{
"data-root": "/data/dockerData",
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
]
}
#启动docker
systemctl start docker
systemctl enable docker

获取并修改源码配置

(1)拉取若依项目源码到本地,并将ruoyi-ui目录与RuoYi-Vue项目放置在同一级

1
git clone https://gitee.com/y_project/RuoYi-Vue.git

(2)修改ruoyi-ui目录中的vue.config.js文件,将localhost修改为部署主机的ip,即192.168.1.125。

1
2
3
4
#修改前
const baseUrl = 'http://localhost:8080' // 后端接口
#修改后
const baseUrl = 'http://192.168.1.125:8080' // 后端接口

(3)修改RuoYi-Vue\ruoyi-admin\src\main\resources\application.yml文件,将redis配置的ip改为192.168.1.125。

1
2
3
4
# redis 配置
redis:
# 地址
host: 192.168.1.125

(4)修改RuoYi-Vue\ruoyi-admin\src\main\resources\application-druid.yml文件,将mysql的链接地址改为192.168.1.125。

1
2
3
4
# 主库数据源
master:
url: jdbc:mysql://192.168.1.125:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8

(5)在ruoyi-ui目录下,创建sonar-project.properties,写入以下内容,添加SonarQube代码审查

1
2
3
4
5
sonar.projectKey=ruoyi-ui
sonar.projectName=ruoyi-ui
sonar.projectVersion=1.0
sonar.sources=.
sonar.sourceEncoding=UTF-8

(6)在ruoyi-ui目录下创建前端项目的Jenkinsfile文件

1
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
pipeline {
agent any
environment {
//引入在Jenkins中安装的SonarQube Scanner
scannerHome = tool 'sonar-scanner-jenkins'
}
stages {
stage('拉取代码') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/ruoyi-ui.git']])
}
}
stage('审查代码') {
steps {
//引入在Jenkins中配置的SonarQube服务器设置
withSonarQubeEnv('SonarQube-jenkins') {
sh '${scannerHome}/bin/sonar-scanner'
}
}
}
stage('打包,部署网站') {
steps {
script {
nodejs(nodeJSInstallationName: 'nodejs14') {
sh '''
npm install
# 构建生产环境
npm run build:prod
'''
}
// 将构建产物部署到 Nginx 容器挂载的目录
sh '''

# 将整个 dist 目录复制到挂载目录
scp -r dist 192.168.1.125:/data/ruoyi/nginx/html/
ssh 192.168.1.125 docker restart nginx
'''

}
}

}

}
}

7)在RuoYi-Vue目录下,创建sonar-project.properties,写入以下内容,添加SonarQube代码审查

1
2
3
4
5
6
7
8
9
sonar.projectKey=ruoyi-api
sonar.projectName=ruoyi-api
sonar.projectVersion=1.0
sonar.sources=.
sonar.java.binaries=./ruoyi-admin/target/classes
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
sonar.sourceEncoding=UTF-8

(8)在RuoYi-Vue目录下创建后端项目的Jenkinsfile文件

1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
pipeline {
agent any
environment {
//引入在Jenkins中安装的SonarQube Scanner
scannerHome = tool 'sonar-scanner-jenkins'
}
stages {
stage('拉取代码') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/ruoyi-api.git']])
}
}
stage('编译构建') {
steps {
sh 'mvn clean package'
}
}
stage('审查代码') {
steps {
//引入在Jenkins中配置的SonarQube服务器设置
withSonarQubeEnv('SonarQube-jenkins') {
sh '${scannerHome}/bin/sonar-scanner'
}
}
}
stage('发布项目') {
steps {
script {
sh '''
ssh 192.168.1.125 "mkdir -p /data/ruoyi-api"
scp ruoyi-admin/target/*.jar 192.168.1.125:/data/ruoyi-api/ruoyi.jar
'''
// 创建Dockerfile
sh '''
ssh 192.168.1.125 'cat > /data/ruoyi-api/Dockerfile <<-EOF
FROM openjdk:8
MAINTAINER xie
VOLUME /tmp
ADD ruoyi.jar ruoyi.jar
ENTRYPOINT ["java","-jar","/ruoyi.jar"]
EXPOSE 8080
EOF'
'''

// 构建镜像
sh '''
ssh 192.168.1.125 "docker build -t ruoyi:1.0 /data/ruoyi-api"
'''

// 停止并删除现有的容器
sh '''
EXISTING_CONTAINER=$(ssh 192.168.1.125 "docker ps -a -q -f name=ruoyi")
if [ -n "$EXISTING_CONTAINER" ]; then
echo "容器 'ruoyi' 已存在,停止并删除旧容器..."
ssh 192.168.1.125 "docker rm -f $EXISTING_CONTAINER"
fi
'''

// 运行新的容器
sh '''
ssh 192.168.1.125 "docker run -d --name ruoyi -p 8080:8080 ruoyi:1.0"
'''
}
}
}
}
}

部署项目所需容器

该项目中要用到nginx、mysql和redis,需提前部署好容器。对应容器版本为nginx:1.18.0、mysql:8.0.19、redis:6.0.8

(1)创建所需目录

1
2
3
mkdir -p /data/ruoyi
mkdir -p /data/ruoyi/nginx/conf
mkdir -p /data/ruoyi/mysql/db

(2)创建nginx临时容器,修改配置文件

1
2
docker run --rm -v /data/ruoyi/nginx/conf:/backup nginx:1.18.0 \
sh -c "cp -r /etc/nginx/. /backup"

修改/data/ruoyi/nginx/conf/conf.d中的default.conf文件

1
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
server {
listen 80;

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;

server_name localhost;

location / {
root /usr/share/nginx/html/dist;
index index.html index.htm;
try_files $uri /index.html;
}

location /prod-api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.1.125:8080/; #注意修改ip
}

if ($request_uri ~ "/actuator") {
return 403;
}
}

(3)将RuoYi-Vue\sql中的sql文件,拷贝到192.168.1.125主机的/data/ruoyi/mysql/db目录

(4)撰写yml,使用docker compose编排部署容器

1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#撰写yml文件
vi ruoyi.yml


services:
nginx:
image: nginx:1.18.0
container_name: nginx
restart: always
volumes:
- /data/ruoyi/nginx/conf:/etc/nginx
- /data/ruoyi/nginx/logs:/var/log/nginx
- /data/ruoyi/nginx/html:/usr/share/nginx/html
environment:
TZ: "Asia/Shanghai"
ports:
- "80:80"
networks:
ruoyi:
ipv4_address: 172.20.112.11
mysql:
container_name: mysql
image: mysql:8.0.19
restart: always
environment:
MYSQL_ROOT_PASSWORD: "password"
MYSQL_ALLOW_EMPTY_PASSWORD: "no"
MYSQL_DATABASE: "ry-vue"
TZ: "Asia/Shanghai"
ports:
- "3306:3306"
volumes:
- /data/ruoyi/mysql/db:/var/lib/mysql
- /data/ruoyi/mysql/conf:/etc/my.cnf
- /data/ruoyi/mysql/init:/docker-entrypoint-initdb.d
command: --default-authentication-plugin=mysql_native_password
networks:
ruoyi:
ipv4_address: 172.20.112.12
redis:
container_name: redis
image: redis:6.0.8
restart: always
environment:
TZ: "Asia/Shanghai"
ports:
- "6379:6379"
volumes:
- /data/ruoyi/redis/conf:/etc/redis/redis.conf
- /data/ruoyi/redis/data:/data
command: redis-server /etc/redis/redis.conf
networks:
ruoyi:
ipv4_address: 172.20.112.13


networks:
ruoyi:
driver: bridge
ipam:
config:
- subnet: 172.20.112.0/24

(5)执行命令创建容器

1
2
3
4
5
6
7
docker compose -f ruoyi.yml up -d
#查看容器运行状态
docker ps
#导入数据库
docker exec -it mysql bash
mysql -u root -ppassword ry-vue < /var/lib/mysql/ry_20250417.sql
mysql -u root -ppassword ry-vue < /var/lib/mysql/quartz.sql

上传代码到GitLab

(1)创建ruoyi-ui和ruoyi-api两个仓库分别存放前端和后端代码

(2)在ruoyi-ui目录下,打开cmd,输入命令上传代码

1
2
3
4
5
6
7
8
9
git init
git remote add origin http://192.168.1.121:82/test/ruoyi-ui.git
#添加该目录下的git权限配置
git config user.name "test1"
git config user.email "test1@gitlab"
#继续上传
git add .
git commit -m "ruoyi-ui"
git push -u origin master

(3)在RuoYi-Vue目录下,打开cmd,输入命令上传代码

1
2
3
4
5
6
7
8
9
git init
git remote add origin http://192.168.1.121:82/test/ruoyi-api.git
#添加该目录下的git权限配置
git config user.name "test1"
git config user.email "test1@gitlab"
#继续上传
git add .
git commit -m "ruoyi-api"
git push -u origin master

配置Jenkins流水线

(1)安装nodejs和NodeJS插件

在jenkins服务器上安装nodejs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
wget https://nodejs.org/dist/latest-fermium/node-v14.21.3-linux-x64.tar.gz
tar -vxzf node-v14.21.3-linux-x64.tar.gz -C /opt
mv /opt/node-v14.21.3-linux-x64 /opt/nodejs
#配置环境变量
echo "
export NODE_HOME=/opt/nodejs
export PATH=$NODE_HOME/bin:$PATH" >> /etc/profile
#变量生效
source /etc/profile
#查看版版本
node -v
npm -v
#配置镜像源
npm config set registry https://registry.npmmirror.com
npm config set sass_binary_site=https://npm.taobao.org/mirrors/node-sass

(2)配置NodeJS设置

Manage Jenkins -Tools-NodeJS 安装中,点击新增NodeJS,填写nodejs的名称为nodejs14,输入在服务器安装的nodejs路径/opt/nodejs,保存应用。

(3)创建ruoyi-ui流水线任务,在流水线-定义中选择Pipeline script from SCM,SCM选择Git,填写ruoyi-ui的git仓库地址和登录凭证,其他选项保持默认,保存应用。

(4)点击Build Now,等待任务执行完成。在浏览器中访问http://192.168.1.125/,查看前端部署情况。

(5)创建ruoyi-api流水线任务,在流水线-定义中选择Pipeline script from SCM,SCM选择Git,填写ruoyi-api的git仓库地址和登录凭证,其他选项保持默认,保存应用。

(6)点击Build Now,等待任务执行完成。在浏览器中访问http://192.168.1.125/,可正常登录,即为成功。

(7)访问sonarQube,分别查看前后端代码的具体质量审查情况。

本篇知识来源于B站视频BV1pF411Y7tq