3.1 Jenkins項目構建類型(1)-Jenkins構建的項目類型介紹
Jenkins中自動構建項目的類型有很多,常用的有以下三種:
-
自由風格軟件項目(FreeStyle Project)
-
Maven項目(Maven Project)
-
流水線項目(Pipeline Project)
每種類型的構建其實都可以完成一樣的構建過程與結果,只是在操作方式、靈活度等方面有所區別,在實際開發中可以根據自己的需求和習慣來選擇。(PS:個人推薦使用流水線類型,因為靈活度非常高)
3.2 Jenkins項目構建類型(2)-自由風格項目構建
演示創建一個自由風格項目來完成項目的集成過程:
拉取代碼->編譯->打包->部署
3.2.1 拉取代碼
1)創建項目
2)配置源碼管理,從gitlab拉取代碼
3.2.2 編譯打包
構建->添加構建步驟->Executor Shell
echo "開始編譯和打包"
mvn clean package
echo "編譯和打包結束"
3.2.3 部署
把項目部署到遠程的Tomcat里面
1)安裝 Deploy to container插件
Jenkins本身無法實現遠程部署到Tomcat的功能,需要安裝Deploy to container插件實現
2)添加Tomcat用戶憑證
3)添加構建后操作
點擊"Build Now",開始構建過程
4)部署成功后,訪問項目
http://192.168.5.5:8080/web_demo-1.0-SNAPSHOT/
3.2.4 演示改動代碼后的持續集成
1)IDEA中源碼修改並提交到gitlab
2)在Jenkins中項目重新構建
3)訪問Tomcat
http://192.168.5.5:8080/web_demo-1.0-SNAPSHOT/
3.3 Jenkins項目構建類型(3)-Maven項目構建
1)安裝Maven Integration插件
Maven Integration
2)創建Maven項目
3)配置項目
拉取代碼和遠程部署的過程和自由風格項目一樣,只是"構建"部分不同
3.4 Jenkins項目構建類型(4)-Pipeline流水線項目構建
3.4.1 Pipeline簡介
1)概念 Pipeline,簡單來說,就是一套運行在 Jenkins 上的工作流框架,將原來獨立運行於單個或者多個節點的任務連接起來,實現單個任務難以完成的復雜流程編排和可視化的工作。
2)使用Pipeline有以下好處(來自翻譯自官方文檔):
代碼:Pipeline以代碼的形式實現,通常被檢入源代碼控制,使團隊能夠編輯,審查和迭代其傳送流程。 持久:無論是計划內的還是計划外的服務器重啟,Pipeline都是可恢復的。 可停止:Pipeline可接收交互式輸入,以確定是否繼續執行Pipeline。 多功能:Pipeline支持現實世界中復雜的持續交付要求。它支持fork/join、循環執行,並行執行任務的功能。 可擴展:Pipeline插件支持其DSL的自定義擴展 ,以及與其他插件集成的多個選項。
3)如何創建 Jenkins Pipeline
-
Pipeline 腳本是由 Groovy 語言實現的,但是我們沒必要單獨去學習 Groovy
-
Pipeline 支持兩種語法:Declarative(聲明式)和 Scripted Pipeline(腳本式)語法
-
Pipeline 也有兩種創建方法:可以直接在 Jenkins 的 Web UI 界面中輸入腳本;也可以通過創建一個 Jenkinsfile 腳本文件放入項目源碼庫中(一般我們都推薦在 Jenkins 中直接從源代碼控制(SCM)中直接載入 Jenkinsfile Pipeline 這種方法)。
3.4.2 安裝Pipeline插件
Manage Jenkins->Manage Plugins->可選插件
pipeline
安裝插件后,創建項目的時候多了“流水線”類型
3.4.3 Pipeline語法快速入門
1)Declarative聲明式-Pipeline
創建項目
流水線->選擇HelloWorld模板
生成內容如下:
pipeline {
agent any
stages {
stage('Hello') {
steps {
echo 'Hello World'
}
}
}
}
stages:代表整個流水線的所有執行階段。通常stages只有1個,里面包含多個stage
stage:代表流水線中的某個階段,可能出現n個。一般分為拉取代碼,編譯構建,部署等階段。
steps:代表一個階段內需要執行的邏輯。steps里面是shell腳本,git拉取代碼,ssh遠程發布等任意內容。
編寫一個簡單聲明式Pipeline:
pipeline {
agent any
stages {
stage('拉取代碼') {
steps {
echo '拉取代碼'
}
}
stage('編譯構建') {
steps {
echo '編譯構建'
}
}
stage('項目部署') {
steps {
echo '項目部署'
}
}
}
}
2)Scripted Pipeline腳本式-Pipeline
創建項目
本次選擇"Scripted Pipeline"
node {
def mvnHome
stage('Preparation') { // for display purposes
}
stage('Build') {
}
stage('Results') {
}
}
-
Node:節點,一個 Node 就是一個 Jenkins 節點,Master 或者 Agent,是執行 Step 的具體運行環境,后續講到Jenkins的Master-Slave架構的時候用到。
-
Stage:階段,一個 Pipeline 可以划分為若干個 Stage,每個 Stage 代表一組操作,比如:Build、Test、Deploy,Stage 是一個邏輯分組的概念。
-
Step:步驟,Step 是最基本的操作單元,可以是打印一句話,也可以是構建一個 Docker 鏡像,由各類 Jenkins 插件提供,比如命令:sh ‘make’,就相當於我們平時 shell 終端中執行 make 命令一樣。
編寫一個簡單的腳本式Pipeline
node {
def mvnHome
stage('拉取代碼') { // for display purposes
echo '拉取代碼'
}
stage('編譯構建') {
echo '編譯構建'
}
stage('項目部署') {
echo '項目部署'
}
}
構建結果和聲明式一樣!
3.4.4 拉取代碼
pipeline {
agent any
stages {
stage('拉取代碼') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: '290fa226-a185-4097-aff6-77d2aab6dcf4', url: 'git@192.168.5.4:root/web_demo.git']]])
}
}
}
}
3.4.5 編譯打包
pipeline {
agent any
stages {
stage('拉取代碼') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: '290fa226-a185-4097-aff6-77d2aab6dcf4', url: 'git@192.168.5.4:root/web_demo.git']]])
}
}
stage('編譯構建') {
steps {
sh 'mvn clean package'
}
}
}
}
3.4.6 部署
pipeline {
agent any
stages {
stage('拉取代碼') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: '290fa226-a185-4097-aff6-77d2aab6dcf4', url: 'git@192.168.5.4:root/web_demo.git']]])
}
}
stage('編譯構建') {
steps {
sh label: '', script: 'mvn clean package'
}
}
stage('項目部署') {
steps {
deploy adapters: [tomcat8(credentialsId: '87f9d1b2-7b05-4a7f-8647-ffb54c042645', path: '', url: 'http://192.168.5.5:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
}
3.4.7 Pipeline Script from SCM
之前都是直接在Jenkins的UI界面編寫Pipeline代碼,這樣不方便腳本維護,建議把Pipeline腳本放在項目中(一起進行版本控制)
1)在項目根目錄建立Jenkinsfile文件,把內容復制到該文件中
把Jenkinsfile上傳到Gitlab
2)在項目中引用該文件
3.5 Jenkins項目構建細節(1)-常用的構建觸發器
Jenkins內置4種構建觸發器:
-
觸發遠程構建
-
其他工程構建后觸發(Build after other projects are build)
-
定時構建(Build periodically)
-
輪詢SCM(Poll SCM)
3.5.1 觸發遠程構建
觸發構建url:http://192.168.5.3:808/job/test03_pipeline01/build?token=1118
3.5.2 其他工程構建后觸發
1)創建pre_job流水線工程
2)配置需要觸發的工程
3.5.3 定時構建
定時字符串從左往右分別為: 分 時 日 月 周
一些定時表達式的例子:
每30分鍾構建一次:H代表形參 H/30 * * * * 10:02 10:32
每2個小時構建一次: H H/2 * * *
每天的8點,12點,22點,一天構建3次: (多個時間點中間用逗號隔開) 0 8,12,22 * * *
每天中午12點定時構建一次 H 12 * * *
每天下午18點定時構建一次 H 18 * * *
在每個小時的前半個小時內的每10分鍾 H(0-29)/10 * * * *
每兩小時一次,每個工作日上午9點到下午5點(也許是上午10:38,下午12:38,下午2:38,下午
4:38) H H(9-16)/2 * * 1-5
3.5.4 輪詢SCM
輪詢SCM,是指定時掃描本地代碼倉庫的代碼是否有變更,如果代碼有變更就觸發項目構建。
注意:這次構建觸發器,Jenkins會定時掃描本地整個項目的代碼,增大系統的開銷,不建議使用。
3.6 Jenkins項目構建細節(2)-Git hook自動觸發構建
剛才演示到在Jenkins的內置構建觸發器中,輪詢SCM可以實現Gitlab代碼更新,項目自動構建,但是該方案的性能不佳。那有沒有更好的方案呢? 有的。就是利用Gitlab的webhook實現代碼push到倉庫,立即觸發項目自動構建。
3.6.1 安裝Gitlab Hook插件
需要安裝兩個插件:
Gitlab Hook
GitLab
3.6.2 Jenkins設置自動構建
等會需要把生成的webhook URL配置到Gitlab中。
3.6.3 Gitlab配置webhook
1)開啟webhook功能
使用root賬戶登錄到后台,點擊Admin Area -> Settings -> Network
勾選"Allow requests to the local network from web hooks and services"
2)在項目添加webhook
點擊項目->Settings->Integrations
注意:在Jenkins控制台完成以下設置,否則會報錯
Manage Jenkins->Configure System
3.7 Jenkins項目構建細節(3)-Jenkins的參數化構建
有時在項目構建的過程中,我們需要根據用戶的輸入動態傳入一些參數,從而影響整個構建結果,這時可以使用參數化構建。
Jenkins支持非常豐富的參數類型
接下來演示通過輸入gitlab項目的分支名稱來部署不同分支項目。
3.7.1 項目創建分支,並推送到Gitlab上
新建分支:v1,代碼稍微改動下,然后提交到gitlab上。 這時看到gitlab上有一個兩個分支:master和v1
3.7.2 在Jenkins添加字符串類型參數
3.7.3 改動pipeline流水線代碼
3.7.4 點擊Build with Parameters
輸入分支名稱,構建即可!構建完成后訪問Tomcat查看結果
3.8 Jenkins項目構建細節(4)-配置郵箱服務器發送構建結果
3.8.1 安裝Email Extension插件
Email Extension Template
3.8.2 Jenkins設置郵箱相關參數
Manage Jenkins->Configure System
設置郵件參數
設置Jenkins默認郵箱信息
測試郵箱是否可以發送成功
3.8.3 准備郵件內容
在項目根目錄編寫email.html,並把文件推送到Gitlab,內容如下:
<!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>
3.8.4 編寫Jenkinsfile添加構建后發送郵件
pipeline {
agent any
stages {
stage('拉取代碼') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: '290fa226-a185-4097-aff6-77d2aab6dcf4', url: 'git@192.168.5.4:root/web_demo.git']]])
}
}
stage('編譯構建') {
steps {
sh 'mvn clean package'
}
}
stage('項目部署') {
steps {
deploy adapters: [tomcat8(credentialsId: '87f9d1b2-7b05-4a7f-8647-ffb54c042645', path: '', url: 'http://192.168.5.5:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
post {
always {
emailext(
subject: '構建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS}!',
body: '${FILE,path="email.html"}',
to: 'xxx@qq.com'
)
}
}
}
測試郵件發送情況
郵件發送格式存在問題,可以修改以下字段
PS:郵件相關全局參數參考列表:
3.9 Jenkins+SonarQube代碼審查(1) - 安裝SonarQube
3.9.1 SonaQube簡介
SonarQube是一個用於管理代碼質量的開放平台,可以快速的定位代碼中潛在的或者明顯的錯誤。目前 支持java,C#,C/C++,Python,PL/SQL,Cobol,JavaScrip,Groovy等二十幾種編程語言的代碼質量管理與檢 測。
3.9.2 環境配置說明
名稱 | IP地址 | 安裝軟件 |
---|---|---|
持續基礎服務器 | 192.168.5.3 | ... SonarQube6.7.4,Mysql5.7 |
代碼托管服務器 | 192.168.5.4 | gitlab-ce-12.4.2 |
應用測試服務器 | 192.168.5.5 | JDK1.8,Tomcat8.5 |
3.9.3 安裝SonarQube
1)安裝MySQL
詳細請參考文檔:
2)安裝SonarQube 在MySQL創建sonar數據庫
create database sonar;
下載sonar壓縮包:
由於SonarQube在7.9版本后開始就不再支持MySQL連接
個人收集:
wget https://cunqi0105-1300757323.cos.ap-shanghai.myqcloud.com/install-pkg/sonarqube-6.7.4.zip
解壓sonar,並設置權限
yum install unzip
# 解壓
cd /root &&unzip sonarqube-6.7.4.zip
mv sonarqube-6.7.4 /usr/local/sonar
useradd sonar && chown -R sonar. /usr/local/sonar
修改sonar配置文件
vim /usr/local/sonar/conf/sonar.properties
sonar.jdbc.username=root
sonar.jdbc.password=Root@123
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false
注意:sonar默認監聽9000端口,如果9000端口被占用,需要更改。
啟動sonar
su - sonar
su sonar ./bin/linux-x86-64/sonar.sh start 啟動
su sonar ./bin/linux-x86-64/sonar.sh status 查看狀態
su sonar ./bin/linux-x86-64/sonar.sh stop 停止
tail -f logs/sonar.logs 查看日志
訪問sonar
http://192.168.5.3:9000
默認賬戶:admin/admin
6c4dd14a866779edf26f4cc741f5fe8ec1bb9379
3.10 Jenkins+SonarQube代碼審查(2) - 實現代碼審查
3.10.1 安裝SonarQube Scanner插件
SonarQube Scanner
3.10.2 添加SonarQube憑證
3.10.3 Jenkins進行SonarQube配置
Manage Jenkins->Configure System->SonarQube servers
Manage Jenkins->Global Tool Configuration
3.10.4 SonaQube關閉審查結果上傳到SCM功能
3.10.5 在項目添加SonaQube代碼審查(非流水線項目)
添加構建步驟:
# must be unique in a given SonarQube instance
sonar.projectKey=tset-01
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=tset-01
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
3.10.6 在項目添加SonaQube代碼審查(流水線項目)
# must be unique in a given SonarQube instance
sonar.projectKey=tset-02
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=tset-02
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
2)修改Jenkinsfile,加入SonarQube代碼審查階段
pipeline {
agent any
stages {
stage('拉取代碼') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: '290fa226-a185-4097-aff6-77d2aab6dcf4', url: 'git@192.168.5.4:root/web_demo.git']]])
}
}
stage('編譯構建') {
steps {
sh 'mvn clean package'
}
}
stage('SonarQube代碼審查') {
steps{
script {
// 引入sonarqubescanner工具
scannerHome = tool 'sonarqube-scanner'
}
//引入sonarqube的服務器環境
withSonarQubeEnv('sonarqube') {
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
stage('項目部署') {
steps {
deploy adapters: [tomcat8(credentialsId: '87f9d1b2-7b05-4a7f-8647-ffb54c042645', path: '', url: 'http://192.168.5.5:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
post {
always {
emailext(
subject: '構建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS}!',
body: '${FILE,path="email.html"}',
to: 'xxx@qq.com'
)
}
}
}
3)到SonarQube的UI界面查看審查結果