一、持續集成與Jenkins
持續集成(Continuous integration,簡稱CI)指的是,頻繁地(一天多次)將代碼集成到主干。
持續集成的目的,就是讓產品可以快速迭代,同時還能保持高質量。
它的核心措施是代碼集成到主干之前,必須通過自動化測試。只要有一個測試用例失敗,就不能集成。
通過持續集成,團隊可以快速的從一個功能到另一個功能,簡而言之,敏捷軟件開發很大一部分都要歸功于持續集成。
(一)持續集成的步驟
1.提交
流程的第一步,是開發者向代碼倉庫提交代碼。所有后面的步驟都始于本地代碼的一次提交。
2.測試(第一輪)
代碼倉庫對commit操作配置了鉤子(hook),只要提交代碼或者合并進主干,就會跑自動化測試。
3.構建
通過第一輪測試,代碼可以合并進主干,就算可以交付了。
交付后,就先進行構建(build),再進入第二輪測試。所謂構建,指的是將源碼轉換為可以運行的實際代碼,比如安裝依賴,配置各種資源(樣式表、js腳本、圖片)等等。
4.部署
過了測試和構建,當前代碼就是一個可以直接部署的版本(artifact)。將這個版本的所有文件打包存檔,發到生產服務器。
5.回滾
一旦當前版本發生問題,就要回滾到上一個版本的構建結果。最簡單的做法就是修改以下符號鏈接,指向上一個版本的目錄。
(二)持續集成的組成要素
一個自動構建的過程,從檢出代碼、編譯構建、運行測試、結果記錄、測試統計等都是自動完成的,無需人工干預。
一個代碼存儲庫,即需要版本控制軟件來保障代碼的可維護性,同時作為構建過程的素材庫,一般使用SVN或Git。
一個持續集成服務器,jenkins就是一個配置簡單和使用方便的持續集成服務器。
(三)持續集成的好處
1.降低風險,由于持續集成不斷去構建,編譯和測試,可以很早期發現問題,所以修復的代價就少
2.對系統健康持續檢查,減少發布風險帶來的問題。
3.減少重復性工作
4.持續部署,提供可部署單元包
5.持續交付可供使用的版本
6.增強團隊信心。
二、持續集成服務器Jenkins
Jenkins是一款流行的開源持續集成工具,廣泛用于項目開發,具有自動化構建、測試和部署等功能。
(一)環境準備
Jenkins作為持續集成工具,使用Git工具到Git倉庫拉取代碼到集成服務器,再配合JDK,Maven等軟件完成代碼編譯,代碼測試與審查,測試,打包等工作,在這個過程中每一步出錯,都重新再執行一次整個流程。
最后,Jenkins把生成的jar或war包分發到測試服務器或者生產服務器,測試人員或用戶就可以訪問應用。
因此,一個完善的持續集成體系包含一臺Gitlab代碼托管服務器,一臺Jenkins持續集成服務器,一臺測試服務器和一臺生產服務器。
涉及到Gitlab安裝、Jenkins安裝、Maven安裝、Tomcat安裝。
(二)Gitlab安裝
參考我的博客中gitlab安裝教程
gitlab安裝教程
(三)安裝jdk
如果需要安裝最新版本的Jenkins的話,是要下載JDK17的,當然,有時候項目使用jdk8的構建,所以兩種版本都要會安裝。
# 查看yum源可以安裝的jdk版本
yum list | grep jdk
# 可以很方便安裝jdk8
yum install -y java-1.8.0-openjdk
# 如果yum源支持jdk17的話,按下列命令安裝
yum install -y java-17-openjdk-devel
目前國內yum源最多支持到jdk11,多數情況還是需要手動下載jdk17的壓縮包。
# 為避免手動配置環境變量,直接下載rpm包
wget https://download.oracle.com/java/17/archive/jdk-17.0.12_linux-x64_bin.rpm
# 安裝rpm包
rpm -ivh jdk-17.0.12_linux-x64_bin.rpm
該安裝包會把程序安裝在/usr/java/
目錄下。
然后檢查jdk的版本,查看是否成功安裝
# 查看版本
java -version
安裝完成后,應該在“Dashboard - Manage Jenkins - Tools”中將JDK加入到全局配置中。
(四)Jenkins安裝
1.Centos安裝Jenkins
官方網站下載地址:https://www.jenkins.io/download/
不建議在官方網站下載Jenkins.war包,因為還得上傳到服務器并且安裝tomcat。
# 添加Jenkins的yum倉庫
sudo wget -O /etc/yum.repos.d/jenkins.repo \https://pkg.jenkins.io/redhat/jenkins.repo
# 導入Jenkins的GPG密鑰
sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io-2023.key
# 更新yum倉庫
sudo yum upgrade
# 安裝依賴
sudo yum install fontconfig
# 安裝Jenkins
sudo yum install jenkins
然后就可以啟動jenkins了
# 啟動jenkins
systemctl start jenkins
# 查看jenkins狀態
systemctl status jenkins
啟動成功后,接著就可以訪問http://服務器IP:8080
的jenkins網頁了。
如果還不能訪問,可以檢查下防火墻設置。
# 檢查防火墻端口
firewall-cmd --zone=public --list-ports
# 如果8080端口不在列表中,可以添加它
firewall-cmd --permanent --zone=public --add-port=8080/tcp
# 重新加載防火墻規則
firewall-cmd --reload
2.docker安裝jenkins
如果公司有很多開發人員,每個人都想用不同版本的jenkins或者使用不同的插件,那么推薦使用docker安裝jenkins。
# 在宿主機的某個目錄下創建一個"jenkins_home"目錄,用于后面jenkins容器掛載,這里我是在home目錄下創建的
# 修改jenkins目錄的訪問權限
mkdir -p /home/jenkins_home
chmod 777 /home/jenkins_home
# 拉取鏡像,這里我們使用的是帶有lts標簽的鏡像,它代表最新的長期支持版本。
docker pull jenkins/jenkins:lts
# 啟動Jenkins容器
docker run -d -p 8080:8080 -p 50000:50000 --name jenkins-master -v /home/jenkins_home:/var/jenkins_home jenkins/jenkins:lts
使用docker安裝Jenkins的話,需要不斷更新維護自有版本的鏡像文件配置,有點麻煩,不過如果想再換個環境部署遷移的話就很方便。
(五)Jenkins初始化
1.登錄Jenkins
執行完成創建jenkins容器的命令后,通過瀏覽器訪問http://服務器IP:8080
的方式就可以了。
# 查看密碼
cat /var/lib/jenkins/secrets/initialAdminPassword
復制粘貼密碼后等待一段時間,會跳出如下界面。
jenkins默認會連接官網進行插件的安裝,這樣速度比較慢,所以初始化安裝時可以不安裝插件!
所以應該點擊“選擇插件來安裝”,然后選擇“無”
然后系統提示我們創建初始化后的管理員賬號密碼,自己設置一個就可以了。
一路點擊下一步,就完成正常的安裝了
在“Dashboard - Manage Jenkins - Plugins”,可以看到所有可以安裝的插件。
看英文困難的同學可以先安裝一下 Chinese (Simplified) 中文漢化插件。
2.更換插件安裝的鏡像源
由于國外插件的安裝速度較慢,可以替換安裝源為國內鏡像。
不過貌似國內的鏡像源也失效了,如果找到了新的安裝源地址可以自己替換一下。
# 將.xml文件中的"<url>https://updates.jenkins.io/update-center.json</url>"
# 修改為"<url>https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json</url>"
vi /var/lib/jenkins/hudson.model.UpdateCenter.xml# 替換后重啟容器
systemctl restart jenkins
可以看到再“Advanced settings”中替換成了我們的新地址。
(六)安裝憑據管理插件
Jenkins想要訪問Gitlab需要輸入賬號密碼,這個通過安裝Credentials Binding憑證管理來實現。
搜索Credentials Binding插件并安裝,安裝成功后打開憑據管理。
在“憑據-系統-全局”這里可以添加憑證。
如下,可以分為五種憑證:
- username with password 賬號密碼登錄
- SSH username with private key 免密ssh登錄
- Secret file 密鑰文件
- Secret text 密鑰文本
- Certificate 證書PCKS方式
一般賬號密碼登錄的方式比較多,我們可以在此提前錄入Gitlab的賬號密碼。
例如,如下圖,拉取代碼分為SSH克隆(免密ssh登錄)和HTTP克隆(賬號密碼登錄)兩種方式。
填入賬號密碼后,新建工程拉取Git代碼倉庫時就可以用這個信息了。
(七)安裝Git插件
前面憑據管理插件裝之后,我們可以去Gitlab拉取代碼,這個要使用Git工具。
安裝完成后,我們創建一個項目,在源碼管理這里就會多一個Git
選項。
除了要裝git插件,還需要git的工具。
# 安裝git
yum install -y git
# 查看git版本
git --version
(八)安裝maven
1.下載安裝maven
maven可以通過下載壓縮包的方式安裝,也可以直接直接通過yum安裝。
官方下載地址:https://maven.apache.org/download.cgi
maven的3.3.x系列支持jdk6以上版本,3.5.x~3.8.x支持jdk7以上版本,3.9.x支持jdk8以上版本。
這里我選擇的是裝3.9.x系列版本
# 下載maven的安裝包
curl -O "https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz"
# 解壓壓縮包到/usr/local目錄
tar -zxvf apache-maven-3.9.9-bin.tar.gz -C /usr/local
# 修改配置文件
vi /etc/profile
# 在文件末尾添加如下內容:
export MAVEN_HOME=/usr/local/apache-maven-3.9.9
export PATH=$PATH:$MAVEN_HOME/bin
# 添加完成后,使配置文件生效
source /etc/profile
配置生效后,檢查版本
mvn -version
2.配置maven環境變量
安裝完成后,在“Dashboard - Manage Jenkins - Tools”將maven的路徑加入全局配置里。
為了保證Jenkins能正確找到并使用必要的工具和環境,需要在“Dashboard -> Manage Jenkins -> System”中的Environment variables添加全局變量,分別添加JAVA_HOME、M2_HOME、PATH+EXTRA等路徑地址。
- JAVA_HOME:java目錄地址 /usr/lib/jvm/jdk-17.0.12-oracle-x64
- M2_HOME:maven目錄地址 /usr/local/apache-maven-3.9.9
- PATH+EXTRA:環境變量附加bin目錄地址 $M2_HOME/bin
3.配置maven倉庫
# 找個空間大的分區,創建maven倉庫存放的目錄,并賦予權限
mkdir /home/maven-repo
chmod 777 /home/maven-repo
# 編輯maven/conf目錄下的settings.xml的配置文件
vi /usr/local/apache-maven-3.9.9/conf/settings.xml
# 做以下修改:1.去掉注釋然后修改倉庫地址 2.修改為阿里鏡像源
<localRepository>/home/maven-repo</localRepository>
<mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
(九)構建過程
前面的各種插件都安裝完成,接下來我們可以執行構建流程。
再打開項目中的配置菜單中“Dashboard -> test1 -> Configuration -> Build Steps”中選擇Execute Shell
選項,意思是構建步驟中要執行shell命令。
填入shell命令,執行maven的清除和打包命令。
mvn clean package
保存完成后,可以點擊左側的Build Now
執行構建。
點擊正在執行的進度條,可進入控制臺查看構建的詳細過程。
構建成功后,可以在控制臺查看打包好的工程項目的地址。
進入服務器后臺,也會發現在此目錄下生成了一個jar包。
到此Jenkins的編譯打包功能就成功完成了!
(十)遠程部署
遠程部署需要Publish Over SSH的插件,這個要安裝一下。
安裝完成后,就可以在全局配置里設置SSH服務器了。
上面的輸入欄都可以空著。
點擊新增,填入遠程服務器的IP地址、賬號、密碼、目錄等信息。
發送文件
填入傳輸的文件(可以用通配符)、目錄地址以及傳輸完成后執行的命令。
保存后執行構建,查看控制臺的輸出日志,系統連上測試服務器了,并發送了一個文件。
登錄測試服務器,可以看到文件成功傳輸到測試服務器。
只要配置的時候填過執行運行jar包的命令,到此就實現jar包的自動運行了!
三、Jenkins使用進階
(一)Jenkins的項目構建類型
Jenkins自動構建類型分為三種:
- 自由風格軟件項目(FreeStyle Project) 適用于任何類型的項目,比如是Java、Python還是其他語言編寫的項目
- Maven項目(Maven project) 專門為Java項目設計的,特別是遵循Maven標準目錄結構的項目。
- 流水線項目(Pipeline project) 適合于復雜的構建、測試和部署流程,允許將整個過程定義為一段Groovy腳本。
1.自由風格軟件項目
自由風格的軟件項目適用于任何類型的項目,在使用java的自由風格項目時一般是打包成war包發送到tomcat服務器中。
分為三步,拉取代碼-構建代碼-部署到遠程服務器。
前面已經會拉取代碼和編譯構建了,還缺一步,就是需要將代碼傳輸給遠程服務器進行部署。
Jenkins需要安裝一下用于部署的Deploy to Container插件。
安裝完成后,繼續選擇構建后步驟的Deploy war/ear to a container
選項。
輸入工程項目文件的路徑和tomcat的憑證就可以部署到遠程服務器。
2.maven項目
在Jenkins中安裝一下Maven Integration插件。
安裝完成后,就可以在Jenkins上構建maven項目了。
可以看到,maven項目多了不少選項。與自由風格項目的區別是讀取的是POM.xml文件,然后不用寫mvn的前綴。
3.流水線項目
前面兩個項目各構建節點都是分散的,為方便統一管理可以使用Pipeline來管理。
安裝一下Pipeline插件。
安裝之后,就可以建立流水線項目了。
接著就可以通過寫腳本的方式執行構建了。
(二)Pipeline語法
Pipeline腳本可以用來實現從構建、測試到部署的整個過程,它分為聲明式(Declarative)和腳本式(Scripted)的語法。
基礎概念
- Pipeline: 是一組按照特定順序執行的步驟(steps),用于定義整個CI/CD過程。
- Node: 在Jenkins環境中執行Pipeline或部分Pipeline的機器。它可以是master節點或者任何agent節點。
- Stage: 代表了整個流程中的一個階段,例如“Build”,“Test”,“Deploy”。每個stage通常對應于Pipeline中的一組操作。
- Step: 每個單獨的任務稱為step,它是Pipeline的最小執行單位。
1.聲明式語法
pipeline {agent any // 表示可以在任何可用的agent上運行這個pipelinestages { // 所有階段stage('Clone repository') { // 第一階段名稱:克隆倉庫steps {git 'https://github.com/your-repo/your-project.git' // 替換為你的Git倉庫地址}}stage('Build') { // 第二階段名稱:構建項目steps {sh './build.sh' // 假設有一個名為build.sh的shell腳本來進行構建}}stage('Test') { // 第三階段:測試項目steps {sh './test.sh' // 假設有一個名為test.sh的shell腳本來運行測試}}stage('Deploy') { // 第四階段:部署項目steps {sh './deploy.sh' // 假設有一個名為deploy.sh的shell腳本來進行部署}}}post { // 定義在整個pipeline完成后要執行的操作always { // 不管pipeline的結果如何都會執行cleanWs() // 清理工作區}success { // 如果pipeline成功完成,則執行echo 'Pipeline completed successfully.'}failure { // 如果pipeline失敗,則執行echo 'Pipeline failed.'}}
}
2.腳本式語法
node { // 定義將在哪個節點上運行這個pipeline,'node'關鍵字在腳本式Pipeline中用于指定執行環境stage('Clone repository') { // 使用stage來組織不同階段的任務checkout scm // 通過scm步驟從源碼管理系統檢出代碼,默認情況下會使用項目配置的SCM信息// 或者直接指定Git倉庫:// git 'https://github.com/your-repo/your-project.git'}stage('Build') {def buildResult = sh(returnStdout: true, script: './build.sh').trim() // 執行構建命令并捕獲輸出echo "Build result: ${buildResult}"}stage('Test') {sh './test.sh' // 運行測試腳本}stage('Deploy') {try {sh './deploy.sh' // 嘗試執行部署腳本} catch (Exception e) {currentBuild.result = 'FAILURE' // 如果部署失敗,設置當前構建結果為失敗throw e // 重新拋出異常以停止Pipeline}}stage('Post Actions') { // 模擬post部分的功能if (currentBuild.result == null || currentBuild.result == 'SUCCESS') {echo 'Pipeline completed successfully.'} else {echo 'Pipeline failed.'}// 清理工作區cleanWs()}
}
3.流水線語法文檔
pipeline的語法有點復雜,不知道怎么寫的話,在“流水線語法 -> 片段生成器”可以協助生成pipeline語句。
同時,還有在線文檔可以查詢。
4.Jenkins腳本文件
前面的Jenkins的Pipeline腳本都是寫在web頁面里的,這樣比較麻煩,不方便做版本控制。
可以在項目根目錄新建Jenkinsfile的文件,并將其推送到Git倉庫中。
在流水線設置中選擇“Pipeline script from SCM”,意思是pipeline腳本來自版本控制系統。
填寫好Git倉庫地址及憑證。
系統就會默認去根目錄拉取Jenkinsfile文件進行執行了。
(三)構建觸發器
前面的項目都是手動觸發構建,持續集成至少要做到全自動化。也就是說,開發人員提交代碼并審查完成后,代碼就應該全自動部署到服務器中運行。
當然,建議測試環境全自動運行,生產環境手動觸發比較好。
Jenkins內置4種構建觸發器:
- 觸發遠程構建
- 其他工程構建后觸發(Build after other projects are build)
- 定時構建(Build periodically)
- 輪詢SCM (Poll SCM)
1.觸發遠程構建
如圖,選擇”觸發遠程構建“選項,這里的身份驗證令牌應該填一個加密字符串。
為方便演示,我直接填了123456
。
接著通過瀏覽器訪問http://你的服務器IP/job/pipeline-test/build?token=123456
就可以觸發構建了。
2.其他工程構建后觸發
有時候Jenkins項目之間有前后依賴關系,則可以在前置工程構建時,自動觸發下游工程的構建。
3.定時構建
如果有需要每天凌晨趁沒人用系統的時候部署更新代碼,而又不想加班,可以選擇定時構建代碼。
這里需要填一個變種的cron表達式。
cron表達式表示如下:
分 時 日 月 周
cron表達式編寫示例(H代表形參):
# 每十五分鐘一次(可能在:07, :22, :37, :52):
H/15 * * * *
# 每小時的前半段每十分鐘執行一次(三次,可能在:04, :14, :24):
H(0-29)/10 * * * *
# 每個工作日從早上9:45到下午3:45,每兩小時執行一次(即9:45 AM, 11:45 AM, 1:45 PM, 3:45 PM):
45 9-16/2 * * 1-5
# 每個工作日在8 AM到4 PM之間的每兩個小時內隨機時間執行一次(可能在9:38 AM, 11:38 AM, 1:38 PM, 3:38 PM):
H H(8-15)/2 * * 1-5
# 每月的1號和15號每天執行一次,除了12月:
H H 1,15 1-11 *
4.輪詢SCM
輪詢SCM意思是每隔一段時間去輪詢Git倉庫的整個項目代碼有沒有變化,若有變化就執行構建,沒有則不構建。
若項目很大會遍歷每個文件是否變化,嚴重影響性能,所以一般不推薦這種方式構建。
這里的Poll SCM也是填寫cron表達式來定期輪詢。
5.Gitlab Hook鉤子
為了有更好的性能,應該把主動權放在代碼倉庫這邊,當代碼發生變更時,再通知Jenkins執行構建。
這里我們需要安裝一下Gitlab Hook鉤子插件。
插件安裝完成后,就會發現觸發器多了個選項。這里勾上,下面就會多出很多配置,比如有推送時執行構建,合并代碼時執行構建等等,根據自己的需要進行選擇。
完成Jenkins服務器這邊的配置后,還需要改Gitlab服務器上的配置。
打開Gitlab服務器上的項目的“設置 - 集成 - Jenkins”菜單。
將前面Jenkins構建選項的URL復制下來,粘貼到Jenkins服務器URL處并填寫項目名稱。
填好之后,可以點擊測試是否配置成功。
發現測試失敗了,給了個“連接失敗。請檢查您的集成設置。 驗證失敗:Urlis blocked: Requests to the local network are not allowed”的報錯。
其實,這是不允許本地網絡發送請求的原因。
在“管理員 - 設置 - 網絡 -出站請求”的菜單中,把“允許來自 webhooks 和集成對本地網絡的請求”勾上。
再點擊測試,就可以連接成功了。
可以點擊測試推送事件來查看是否生效,這里報了個錯誤。
這是因為gitlab觸發Jenkins的構建需要做下認證。
在Jenkins中取消“Enable authentication for ‘/project’ end-point”選項的勾選,即取消身份驗證的功能。
再進行測試發送。
就可以發現項目成功執行構建了。