手把手教你用 Jenkins 自動(dòng)部署 SpringBoot!
1. 什么是 CI/CD
CI/CD 是一種通過在應(yīng)用開發(fā)階段引入自動(dòng)化來(lái)頻繁向客戶交付應(yīng)用的方法。
CI/CD 的核心概念可以總結(jié)為三點(diǎn):
- 持續(xù)集成
- 持續(xù)交付
- 持續(xù)部署
CI/CD 主要針對(duì)在集成新代碼時(shí)所引發(fā)的問題(俗稱"集成地獄")。
為什么會(huì)有集成地獄這個(gè)“雅稱”呢?大家想想我們一個(gè)項(xiàng)目部署的過程,拉取代碼->構(gòu)建->測(cè)試->打包->部署,如果我們經(jīng)常需要部署項(xiàng)目,特別是在微服務(wù)時(shí)代,服務(wù)特別多的情況下,不停的測(cè)試打包部署,那估計(jì)得有個(gè)人一整天專門做這事了,而這事又是繁瑣的重復(fù)無(wú)意義的。
具體而言,CI/CD 可讓持續(xù)自動(dòng)化和持續(xù)監(jiān)控貫穿于應(yīng)用的整個(gè)生命周期(從集成和測(cè)試階段,到交付和部署),這些關(guān)聯(lián)的事務(wù)通常被統(tǒng)稱為"CI/CD 管道",由開發(fā)和運(yùn)維團(tuán)隊(duì)以敏捷方式協(xié)同支持。
1.1 CI(Continuous Integration)
CI/CD 中的"CI"始終指持續(xù)集成,它屬于開發(fā)人員的自動(dòng)化流程。成功的 CI 意味著應(yīng)用代碼的新更改會(huì)定期構(gòu)建、測(cè)試并合并到代碼倉(cāng)庫(kù)中,該解決方案可以解決在一次開發(fā)中有太多應(yīng)用分支,從而導(dǎo)致相互沖突的問題。
1.2 CD(Continuous Delivery/Continuous Deployment)
CI/CD 中的"CD"指的是持續(xù)交付和/或持續(xù)部署,這些相關(guān)概念有時(shí)會(huì)交叉使用。兩者都事關(guān)管道后續(xù)階段的自動(dòng)化,但它們有時(shí)也會(huì)單獨(dú)使用,用于說(shuō)明自動(dòng)化程度。
持續(xù)交付(Continuous Delivery)通常是指開發(fā)人員對(duì)應(yīng)用的更改會(huì)自動(dòng)進(jìn)行錯(cuò)誤測(cè)試并上傳到代碼倉(cāng)庫(kù)(如 GitHub、GitLab 等),然后由運(yùn)維團(tuán)隊(duì)將其部署到實(shí)時(shí)生產(chǎn)環(huán)境中。這旨在解決開發(fā)和運(yùn)維團(tuán)隊(duì)之間可見性及溝通較差的問題。因此,持續(xù)交付的目的就是確保盡可能減少部署新代碼時(shí)所需的工作量。
持續(xù)部署(Continuous Deployment)指的是自動(dòng)將開發(fā)人員的更改從代碼倉(cāng)庫(kù)發(fā)布到生產(chǎn)環(huán)境,以供客戶使用。通過一套全自動(dòng)化的流程,來(lái)解決手動(dòng)測(cè)試、編譯、打包等操作。持續(xù)部署以持續(xù)交付的優(yōu)勢(shì)為根基,實(shí)現(xiàn)了管道后續(xù)階段的自動(dòng)化。
2. 什么是 Jenkins
前面說(shuō)的 CI/CD 算是一種思想,思想要落地,就需要對(duì)應(yīng)的工具。
Jenkins 是一款開源的 CI/CD 軟件,可以算是 CI/CD 軟件領(lǐng)導(dǎo)者,它提供了超過 1000 個(gè)插件來(lái)支持構(gòu)建、部署、自動(dòng)化,基本上能夠滿足任何項(xiàng)目的需要。
整體來(lái)說(shuō),Jenkins 有如下六大特點(diǎn):
- 持續(xù)集成和持續(xù)交付
作為一個(gè)可擴(kuò)展的自動(dòng)化服務(wù)器,Jenkins 可以用作簡(jiǎn)單的 CI 服務(wù)器,或者變成任何項(xiàng)目的持續(xù)交付中心。
- 簡(jiǎn)易安裝
Jenkins 是一個(gè)基于 Java 的獨(dú)立程序,可以立即運(yùn)行,包含 Windows、Mac OS X 和其他類 Unix 操作系統(tǒng)。
- 配置簡(jiǎn)單
Jenkins 可以通過其網(wǎng)頁(yè)界面輕松設(shè)置和配置,其中包括即時(shí)錯(cuò)誤檢查和內(nèi)置幫助。
- 插件
通過更新中心中的 1000 多個(gè)插件,Jenkins 集成了持續(xù)集成和持續(xù)交付工具鏈中幾乎所有的工具。
- 擴(kuò)展
Jenkins 可以通過其插件架構(gòu)進(jìn)行擴(kuò)展,從而為 Jenkins 可以做的事提供幾乎無(wú)限的可能性。
- 分布式
Jenkins 可以輕松地在多臺(tái)機(jī)器上分配工作,幫助更快速地跨多個(gè)平臺(tái)推動(dòng)構(gòu)建、測(cè)試和部署。
其實(shí) Jenkins 有很多好玩的用法,今天我還是想先通過一個(gè)簡(jiǎn)單的案例,先來(lái)和大家捋一捋如何使用 Jenkins 來(lái)實(shí)現(xiàn)一個(gè) Spring Boot 項(xiàng)目的自動(dòng)發(fā)布部署,這樣大家對(duì) Jenkins 現(xiàn)有一個(gè)直觀的認(rèn)知,各種其他使用細(xì)節(jié)松哥在以后的文章中再來(lái)和大家細(xì)聊。
3. 準(zhǔn)備工作
3.1 整體規(guī)劃
我們先來(lái)通過如下一張圖片來(lái)看下 Jenkins 在整個(gè)流程中扮演的角色:
結(jié)合第一二小節(jié)的介紹,這張圖應(yīng)該很好理解。
3.2 準(zhǔn)備代碼
提前準(zhǔn)備好測(cè)試代碼,并上傳到代碼倉(cāng)庫(kù)中。為了更加逼真一些,小伙伴們可以將這個(gè)代碼倉(cāng)庫(kù)設(shè)置為私有的,這樣將來(lái)可以檢驗(yàn) Jenkins 中的配置是否正確。
考慮到 GitHub 網(wǎng)絡(luò)有時(shí)候不穩(wěn)定,我這里使用了 Gitee,一個(gè)很簡(jiǎn)單的 Spring Boot 工程,里邊有一個(gè) hello 接口,僅此而已。
我的代碼倉(cāng)庫(kù)地址(私有倉(cāng)庫(kù)):
https://gitee.com/lenve/jenkins_demo.git
3.3 準(zhǔn)備服務(wù)器
理論上,我們需要一臺(tái)服務(wù)器用來(lái)跑 Jenkins,還需要一臺(tái)服務(wù)器作為我的應(yīng)用服務(wù)器,但是我手頭沒有多余的服務(wù)器,所以我就將 Jenkins 和我的 Spring Boot 項(xiàng)目部署到一臺(tái)服務(wù)器上,在接下來(lái)的文章中我會(huì)和大家說(shuō)明每個(gè)配置是針對(duì) Jenkins 的還是針對(duì) Spring Boot 的。
另外,有的小伙伴可能是在虛擬機(jī)上做實(shí)驗(yàn),因?yàn)閷?lái)我們的代碼提交到 Gitee 之后,Gitee 會(huì)通過一個(gè) POST 請(qǐng)求將這個(gè)事件告知 Jenkins,進(jìn)而觸發(fā) Jenkins 的構(gòu)建操作。所以這就要求 Gitee 能夠訪問到你的 Jenkins 服務(wù)器,所以如果你的 Jenkins 剛好搭建在服務(wù)器上,這事就很容易了,但如果是搭建在虛擬機(jī)里,就得通過花生殼之類的內(nèi)網(wǎng)穿透工具來(lái)輔助你的工作了,比較麻煩,而且花生殼網(wǎng)速也慢。
不過小伙伴們不必?fù)?dān)心,如果你在虛擬上搭建的 Jenkins,并且不愿意折騰花生殼,那么也可以通過手動(dòng)構(gòu)建/定時(shí)構(gòu)建的方式去完成項(xiàng)目構(gòu)建的。
4. 搭建 Jenkins
為了省事,我決定用 Docker 搭建 Jenkins,一行命令搞定。
為了操作方便,我們將 Jenkins 的工作目錄映射到我的宿主機(jī)中來(lái),因此首先在宿主機(jī)中準(zhǔn)備一個(gè)數(shù)據(jù)目錄(不是必須):
# 創(chuàng)建 jenkins 目錄
mkdir /data/jenkins_home/
# 修改目錄的所有者,以便于 Jenkins 容器能夠操作該目錄
chown -R 1000:1000 /data/jenkins_home/
接下來(lái)創(chuàng)建并啟動(dòng) Jenkins 容器,同時(shí)掛載數(shù)據(jù)卷:
docker run -d --name jenkins -p 8088:8080 -p 50000:50000 -v /data/jenkins_home:/var/jenkins_home jenkins/jenkins
由于 Jenkins 在運(yùn)行的時(shí)候需要用到 maven,所以有的人會(huì)選擇將 maven 目錄也作為掛載點(diǎn),但是我覺得沒有必要,特別是對(duì)于初學(xué)者而言,這塊很容易出錯(cuò),不如將 maven 將來(lái)直接拷貝到 Jenkins 容器中,這樣反而省事一些。
執(zhí)行如上命令,安裝成功之后,瀏覽器輸入 http://localhost:8088 就可以訪問了。
然后稍等片刻,就可以訪問 Jenkins 了:
訪問之前,首先需要解鎖 Jenkins,解鎖密碼位置網(wǎng)頁(yè)上列出來(lái)了,但是由于我們創(chuàng)建容器的時(shí)候設(shè)置了數(shù)據(jù)卷,所以,現(xiàn)在直接去宿主機(jī)的 /data/jenkins_home/secrets/initialAdminPassword 位置查看初始化密碼,如下:
在網(wǎng)頁(yè)中,輸入密碼然后繼續(xù)。接下來(lái)會(huì)讓我們選擇需要的插件,第一次使用,安裝推薦插件即可。
如果因?yàn)榫W(wǎng)絡(luò)原因安裝失敗,可以點(diǎn)擊重試按鈕進(jìn)行重試。
接下來(lái)創(chuàng)建一個(gè)新的用戶,也可以不創(chuàng)建新的用戶,直接使用 admin 即可:
再設(shè)置 Jenkins 訪問地址:
這個(gè)頁(yè)面有亂碼,不過不影響,設(shè)置完成后,我們點(diǎn)擊保存并完成按鈕即可。接下來(lái)就可以進(jìn)入到 Jenkins 中了。
整個(gè)過程執(zhí)行完畢后,建議執(zhí)行如下命令重啟一下 Jenkins,因?yàn)橛械牟寮枰貑⒅蟛艜?huì)生效。
docker restart jenkins
5. 安裝插件
Jenkins 啟動(dòng)成功之后,接下來(lái)我們安裝三個(gè)必要的插件:
- Maven Integration:Maven 構(gòu)建工具
- Publish Over SSH:整個(gè)工具,將來(lái)把 Jenkins 打包好的 jar 上傳到應(yīng)用服務(wù)器上。
- Gitee:協(xié)助使用 Gitee 倉(cāng)庫(kù)。
安裝步驟如下:
點(diǎn)擊左邊的系統(tǒng)管理,然后點(diǎn)擊右邊的插件管理,進(jìn)行配置。
然后在可選插件中,搜索 Maven Integration 和 Publish Over SSH 以及 Gitee 三個(gè)插件:
搜索完成后,點(diǎn)擊 Install without restart。
安裝成功之后,重啟 Jenkins。
建議執(zhí)行 docker restart jenkins 去重啟,點(diǎn)擊網(wǎng)頁(yè)上的重啟,會(huì)卡很久,還是執(zhí)行 docker 重啟命令靠譜一些。
6. 配置 Jenkins
6.1 基本的環(huán)境配置
插件安裝成功之后,接下來(lái)我們開啟 Jenkins 的配置,在正式開始配置之前,先做一點(diǎn)準(zhǔn)備工作。
這個(gè)需要我們提前準(zhǔn)備好 Maven,由于 Jenkins 容器中已經(jīng)包含一個(gè) JDK 了,所以我們可以不用提前準(zhǔn)備 JDK,只需要提前準(zhǔn)備 Maven 即可。為了避免權(quán)限問題,我們可以直接將 Maven 上傳到 jenkins 容器中,然后去配置即可。
如下將宿主機(jī)中的 maven 拷貝到 Jenkins 容器中:
# 這個(gè)命令表示將宿主機(jī)中的 maven 目錄拷貝到 jenkins 容器中的 /opt/ 目錄下
docker cp maven jenkins:/opt/
接下來(lái)就可以開始配置了,配置的位置如下圖:
6.2 JDK
首先我們來(lái)配置 JDK,Jenkins 中默認(rèn)安裝了 JDK,我們只需要將其配置配出出來(lái)即可:
別名隨意取,JAVA_HOME 則根據(jù)實(shí)際情況配置。
6.3 Maven
Maven 就是我們剛剛上傳到 docker 中期中的 Maven,配置一下位置即可,Jenkins 將來(lái)會(huì)自動(dòng)從 Gitee 上將代碼拉下來(lái),然后就利用你這里配置的 Maven 進(jìn)行構(gòu)建:
名字隨意取,MAVEN_HOME 則是前面剛剛上傳到容器中的 MAVEN 目錄。
6.4 Git
配置 Git,由于 Jenkins 容器中已經(jīng)存在 git 了,所以這里不需要額外安裝 git,默認(rèn)即可。
所有都配置完成,點(diǎn)擊保存按鈕。
6.5 遠(yuǎn)程的憑證配置
接下來(lái)還需要我們配置兩個(gè)遠(yuǎn)程登錄憑證。
6.5.1 應(yīng)用服務(wù)器信息
應(yīng)用服務(wù)器,就是將來(lái) Jenkins 將代碼構(gòu)建成 jar 包后,要上傳的服務(wù)器的信息(地址、用戶名以及密碼)。
配置步驟如下,首先找到配置的位置:
往下拉找到 Publish Over SSH,然后點(diǎn)擊新增,開始配置,Hostname 位置填寫你服務(wù)器的域名或者 IP:
配置成功后,點(diǎn)擊測(cè)試連接進(jìn)行測(cè)試,確保連接是成功的。
有的小伙伴反饋這里用戶名密碼會(huì)導(dǎo)致 jar 包上傳失敗,要在應(yīng)用服務(wù)器上生成 ssh 密鑰對(duì),然后將私鑰配置給 Jenkins(這塊大家結(jié)合自己情況來(lái)看,如果后面 jar 上傳失敗,可以回來(lái)改一下這里)。
6.5.2 Gitee 的信息
接下來(lái)我們配置 Gitee 的信息。
首先配置倉(cāng)庫(kù)的基本信息:
接下來(lái)配置 Gitee 的憑證,要根據(jù)這些憑證,才能從 Gitee 上拉取代碼下來(lái),點(diǎn)擊 添加->Jenkins,添加憑證:
添加成功之后,就可以選擇這個(gè)令牌了。
最后點(diǎn)擊測(cè)試連接,確保可以連上 Gitee。
所有配置工作都做完了,接下來(lái)我們就可以開始構(gòu)建一個(gè)項(xiàng)目了。
7. 開始一個(gè)項(xiàng)目的構(gòu)建
首先我們新建一個(gè)任務(wù):
接下來(lái)我們選擇構(gòu)建一個(gè) Maven 項(xiàng)目:
點(diǎn)擊確定之后,拉到源碼管理位置,開始配置。
首先選擇 Git,填入 Gitee 上的倉(cāng)庫(kù)地址,然后憑證就寫 Gitee 的用戶名/密碼。
這里有一個(gè)需要注意的地方,就是默認(rèn)的分支名稱,GitHub 上現(xiàn)在默認(rèn)的主分支名稱是 main,Gitee 似乎還是 master,這個(gè)無(wú)所謂了,但是小伙伴們注意圖片下面的分支,按你實(shí)際的情況填寫。
這里也要添加憑證信息:
這里也要注意下,有小伙伴反饋 Gitee 上的用戶名和用戶空間不是一回事(如果用的 GitHub 就不存在這個(gè)問題),我這里用戶名位置實(shí)際填入用戶空間名(如果你也不知道什么是用戶空間,那么恭喜你,直接寫用戶名就行了)。
加上時(shí)間,我們看下打印的過程:
接下來(lái)輸入項(xiàng)目構(gòu)建命令,將來(lái) Jenkins 從 Gitee 上拉取代碼下來(lái)之后,就執(zhí)行該命令對(duì)項(xiàng)目進(jìn)行打包:
最后,配置上傳構(gòu)建好的文件,并執(zhí)行啟動(dòng)命令,如下:
配置的詳細(xì)信息:
根據(jù)上圖的配置,我們使用 root 用戶登錄,root 登錄成功之后,默認(rèn)進(jìn)入到 /root 目錄下,接下來(lái)會(huì)自動(dòng)進(jìn)入到 data 目錄,然后我們的 jar 包就上傳到這個(gè)位置上。
然后我們?cè)趹?yīng)用服務(wù)器上也提前準(zhǔn)備好一個(gè) shell 腳本叫做 deploy.sh,位于 /root/data 目錄下,這個(gè)腳本內(nèi)容如下:
export JAVA_HOME=/opt/java
export PATH=$JAVA_HOME/bin:$PATH
JAR_PATH=/root/data
JARFILE=jenkins_demo-0.0.1-SNAPSHOT.jar
ps -ef | grep $JARFILE | grep -v grep | awk '{print $2}' | xargs kill -9
java -jar $JAR_PATH/$JARFILE > out.log &
if [ $? = 0 ];then
sleep 30
tail -n 50 out.log
fi
這個(gè)腳本其實(shí)很好理解,前面先配置一下環(huán)境變量,注意這個(gè)是應(yīng)用服務(wù)器的環(huán)境變量,不是 Jenkins 的。
然后先檢查一下,如果應(yīng)用程序已經(jīng)在運(yùn)行了,就先將之停止掉。然后運(yùn)行我們最新的 jar 即可。
另外,可以開啟 SSH 操作日志,開啟日志之后,就可以看到 Jenkins 中操作應(yīng)用服務(wù)器其的過程了,特別是大家第一次配置的時(shí)候,容易出錯(cuò),配置了日志,將來(lái)出錯(cuò)就知道什么原因?qū)е碌腻e(cuò)誤了。
配置方式如下圖:
至此,這個(gè)項(xiàng)目就配置完成了。
保存之后,點(diǎn)擊立即構(gòu)建按鈕,就可以開始構(gòu)建了:
開始構(gòu)建之后,可以點(diǎn)擊構(gòu)建按鈕,查看構(gòu)建過程:
點(diǎn)擊控制臺(tái)輸出,可以查看整個(gè)構(gòu)建過程:
構(gòu)建完成后,來(lái)到應(yīng)用服務(wù)器,執(zhí)行 jps 命令查看運(yùn)行的 Java 進(jìn)程,就可以看到我們的應(yīng)用程序已經(jīng)跑起來(lái)了。
8. 自動(dòng)構(gòu)建
好了,現(xiàn)在我們的項(xiàng)目還不是自動(dòng)構(gòu)建,也就是當(dāng)我們向 Gitee 上的代碼倉(cāng)庫(kù)提交代碼之后,并不會(huì)觸發(fā) Jenkins 的自動(dòng)構(gòu)建,得我們手動(dòng)點(diǎn)擊構(gòu)建按鈕,接下來(lái)我們?cè)賮?lái)繼續(xù)配置,實(shí)現(xiàn)自動(dòng)觸發(fā)構(gòu)建。
為了實(shí)現(xiàn)自動(dòng)觸發(fā)構(gòu)建,我們需要修改兩個(gè)地方。
8.1 修改 Jenkins
首先在 Jenkins 的當(dāng)前項(xiàng)目中,配置一下觸發(fā)構(gòu)建的規(guī)則:
大家注意,在網(wǎng)頁(yè)上 Jenkins 已經(jīng)給出了將來(lái)要配置的 Webhook 的地址了,大家直接拷貝該地址即可。
8.2 配置 Webhook
接下來(lái)在 Gitee 的項(xiàng)目中,配置 WebHook,在當(dāng)前項(xiàng)目中,選擇管理選項(xiàng)卡,左邊菜單點(diǎn)擊 WebHooks,然后點(diǎn)擊添加 WebHook。
由于 Jenkins 是要登錄之后才可以操作的,處于公網(wǎng)的 Jenkins 我們也不能降至設(shè)置為匿名訪問,所以這里我們將 Jenkins 的用戶名密碼放在請(qǐng)求地址中,最終地址類似這樣:http://username:password@11.11.11.11:8088/xxxx。
好啦,這就行了,配置完成后,接下來(lái)我們向 Gitee 代碼倉(cāng)庫(kù)提交代碼,提交成功之后,我們?nèi)ゲ榭词欠駮?huì)觸發(fā) Jenkins 自動(dòng)構(gòu)建功能。
9. 小結(jié)
好啦,關(guān)于 Jenkins 還有很多好玩的用法,今天的文章限于篇幅我就先通過一個(gè)簡(jiǎn)單的案例來(lái)和大家分享一下 Jenkins 的基本用法,以便于小伙伴們對(duì) Jenkins 建立一個(gè)直觀的印象,更多的玩法,松哥將在后續(xù)的文章中和大家繼續(xù)介紹,小伙伴們也可以留言說(shuō)說(shuō)你想看 Jenkins 怎么玩。
參考資料:
https://www.redhat.com/zh/topics/devops/what-is-ci-cd