🔜什么是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)创建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 <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呢?
在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种构建触发器:
轮询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 > 项目名称 : ${PROJECT_NAME}</li > <li > 构建编号 : 第${BUILD_NUMBER}次构建</li > <li > 触发原因: ${CAUSE}</li > <li > 构建日志: <a href ="${BUILD_URL}console" > ${BUILD_URL}console</a > </li > <li > 构建 Url : <a href ="${BUILD_URL}" > ${BUILD_URL}</a > </li > <li > 工作目录 : <a href ="${PROJECT_URL}ws" > ${PROJECT_URL}ws</a > </li > <li > 项目 Url : <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=" %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 System、 Administer、 Execute Analysis、Create 权限。单击右上角头像下拉框,选择 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=**/testtarget
流水线任务添加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=**/testtarget
(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 { 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 { 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: #修改后 const baseUrl = 'http:
(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 { 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 { withSonarQubeEnv('SonarQube-jenkins' ) { sh '${scannerHome}/bin/sonar-scanner' } } } stage('打包,部署网站' ) { steps { script { nodejs(nodeJSInstallationName: 'nodejs14' ) { sh ''' npm install # 构建生产环境 npm run build:prod ''' } 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 { 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 { 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 ''' 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/; } 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 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