使用Jenkins實現自動化構建
一個大型平臺的微服務架構設計通常會產生很多專案工程,因此會有很多服務和應用需要部署,並且需要不斷地迭代和更新,這是一個龐大的工程,所以我們需要藉助自動化工具,實現各個微服務工程的CICD工作流程。
CICD是持續整合(Continuous Integration)和持續部署(Continuous Deployment)的總稱,是指透過自動化的構建、測試和部署,實現軟體產品可迴圈使用的快速交付流程。
Jenkins是一個基於Java開發的功能強大的自動化構建工具,並且有一個非常豐富的外掛倉庫,可以很好地擴充和豐富其本身的功能。因此,Jenkins是實現自動化構建的一個很不錯的工具。
單擊Jenkins首頁上的Plugins選項,可以檢視各種外掛的介紹,如圖15-1所示。
本章我們使用Jenkins,結合Maven、Docker、Selenium和JMeter等工具,建立一個可持續交付的自動化設施。
持續交付工作流程從程式碼提交開始,建立一個包括自動測試和自動部署的持續交付工作流程如圖15-2所示。
這個工作流程的步驟如下所示:
(1)開發者向GitLab提交程式碼。
(2)GitLab使用 WebHook通知Jenkins有程式碼更新。
(3)Jenkins 從節點(Slave)拉取程式碼,打包並構建映象。
(4)Jenkins使用從節點上構建的映象執行測試用例。
(5)如果測試(Test)透過,則將映象推送到映象倉庫。
(6)Jenkins在應用伺服器上進行更新部署。
(7)Jenkins將構建報告以郵件方式通知開發者。
在開發者向程式碼庫提交程式碼之後,整個流程都是自動進行的。如果中間某個環節出現錯誤,則中止流程的執行,並將結果通知相關人員。提交的程式碼不僅包括應用程式,還包括構建映象的指令碼、測試用例的指令碼和部署的編排指令碼等。
其中,各個步驟的操作可以使用外掛或直接在命令列中使用各種工具來完成。
例如,拉取專案程式碼會用到Git外掛;打包專案會用到 Maven;構建映象和應用部署可直接透過命令列使用Docker或docker-compose;整合測試可透過命令列執行由Selenium、JMeter等生成的指令碼。
下面,我們透過一個簡單的案例,演示和說明Jenkins 的使用方法。
Jenkins的安裝下面的安裝過程以MacOS為例進行說明。
因為Jenkins需要JVM的支援,所以請確保機器上已經安裝了JDK 1.8或以上版本。為了完成後面的自動化演示,請確保機器中已經安裝了Maven、Git客戶端和 Docker等。
開啟Jenkins官網,進入下載頁面,選擇左邊的LTS穩定版中的Mac OSX版本進行下載,如圖15-3所示。
下載完成後,單擊安裝包“jenkins-2.89.1.pkg”開始安裝。
http://localhost:8080
第一次開啟後會看到如圖15-4所示頁面。
在“全域性工具配置”對話方塊中單擊“Maven安裝”選項,配置一個名字,並設定Maven的安裝路徑,如圖15-7所示。
注意,在設定settings.xml配置中的repositys路徑時,如果是在本機測試,則最好與IDEA的配置相同,這樣打包時將不用再重新下載一次依賴包。
在Jenkins的命令列配置中,為了能夠正常使用Docker 和 docker-compose,我們需要對Jenkins的系統許可權進行設定。因為Jenkins 使用預設使用者“jenkins”開啟服務,所以許可權設定就是為這個使用者進行授權。
透過如下操作步驟,為“jenkins”使用者設定一個免密碼配置,這樣,在Jenkins 的命令列配置中,就可以使用超級管理員的命令“sudo”了。
在MacOS的終端中,執行下列命令,切換到超級管理員root
輸入root的密碼:
appledeMacBook-Air:/ apples suPassword:
編輯“sudoers”,並找到如下所示資訊:
sh-3.2# vi/etc/sudoers
# root and users in group wheel can run anything on any machine as any userroot
ALL = (ALL) ALL%adminALL- (ALL) ALL
在上面資訊的後面,參照root的許可權設定,新增如下所示的配置並儲存:
jenkins ALL=(ALL) NOPASSWD: ALL%admin ALL=(ALL) NOPASSWD: ALL
使用“dscl”命令把“jenkins”使用者加進 admin使用者組中,這個命令等同於Linux作業系統中的“usermod”命令:
sh-3.2# dscl . -append /Groups/admin GroupMembership jenkins
至此,就完成了Jenkins的許可權設定。
Jenkins的自動部署例項為了演示Jenkins的使用,下面建立一個自動部署例項。
在這個例項中使用的是一個功能非常簡單的專案,專案中只有一個主程式,程式碼如下所示
@SpringBootApplication@RestControllerpublic class DemoApplication {public static void main (String[] args){SpringApplication.run(DemoApplication.class,args) ;}@RequestMapping (value = "/")public String index(){return "Hello world! ";}}
應用啟動後,開啟首頁將輸出“Hello World!”。
下面介紹這個自動部署專案的實現過程。
建立任務
在Jenkins首頁中單擊“新建”選項,開啟建立任務頁,如圖15-9所示。
配置任務
在圖15-10中,單擊“原始碼管理”選項,顯示如圖15-11所示對話方塊。在圖15-11中勾選“Git選項,在程式碼庫的位址列中輸入“demo”專案的存放地址。
因為這是一個公開專案,所以不用設定訪問專案的許可權。如果是一個私有專案,則必須在圖15-11的“Credentials”中配置對專案有存取許可權的使用者名稱和密碼。
單擊圖15-11中的“構建觸發器”選項,在“構建觸發器”對話方塊中勾選“Poll SCM”選項,配置一個定時任務的日程表,如圖15-12所示。
圖15-12中的日程表“00 20***”,表示在每天的20:00點整執行任務構建。在本例項中不使用定時任務。
接下來,使用 Maven 配置專案的打包。單擊“構建”選項,在“增加構建步驟”下拉列表中選擇“Invoke top-level Maven targets”選項,如圖15-13所示。
其中,在“Maven Version”中選擇前面安裝的Maven,在“Goals”中輸人如下所示的打包命令:
clean package
配置建立映象和部署的操作命令,這裡會用到Dockerfile和 docker-compose.yml,這兩個檔案已經包含在專案工程的docker目錄中。
Dockerfile 中的內容如下所示:FROM java:8VOLUME/tmpADDdemo-0.0.1-SNAPSHOT.jar app.jarRUN bash 一c'touch /app.jar'EXPOSE8080ENTRYPOINT, "/app.jar"]["java", "-Djava.security.egd=file:/dev/./urandom", "-jar
docker-compose.yml中的部署指令碼如下所示:
demo:build:ports:"8888:8080"
單擊“構建”選項,在“增加構建步驟”下拉列表中選擇“Execute shell”選項,在“Command"中輸入如下所示命令:
cd /Users/Shared/Jenkins/Home/workspace/demo /dockercp -f ../target/demo-0.0.1-SNAPSHOT .jarsudo /usr/local/bin/docker-compose down --rmi allsudo /usr/local/bin/docker-compose up -d
這些命令與我們在主機上直接使用Docker等工具部署應用的命令相同,即先停止正在執行的容器,再刪除容器和映象,最後重新進行部署,如圖15-14所示。
執行任務
當手動執行任務時,首先單擊任務的名稱,返回任務首頁。然後在任務首頁中單擊左側選單中的“立即構建”選項即可,如圖15-15所示。
在任務執行過程中,會在控制檯中輸出資訊,一個完整的執行過程的輸出日誌如下所示
Started by user mr.csjBuilding in workspace /Users/Shared/Jenkins/Home/workspace/demo>git rev-parse --is-inside-work-tree # timeout=10Fetching changes from the remote Git repository>git config remote.origin.url https://gitee.com/chenshaojian/demo.git #timeout=10Fetching upstream changes from https://gitee.com/chenshaojian/demo.git>git --version # timeout=10>git fetch --tags --progress https://gitee.com/chenshaojian/demo.git+refs/heads/* :refs/remotes/origin/*>git rev-parse refs/remotes/origin/master^ { commit] # timeout=10>git rev-parse refs/remotes/origin/origin/master"{ commit}# timeout=10Checking out Revision 1b0348a999cee3a1920b1b20576b54e58a50ab2(refs/remotes/origin/master)>git config core.sparsecheckout # timeout=10>git checkout-f 1b0348a999cee3a1920b1b2c576b54e58a50ab2Commit message: "add docker-compose">git rev-list 8791f0a371ab67a83d1005197744475de5f177df # timeout=10[demo]$/Users/apple/apache-maven-3.5.0/bin/mvn clean package[INFO]Scanning for projects. . .[INFO][INFO]-------------[INFO] Building demo 0.0.1-SNAPSHOT[INFO][INFO][INFO]--- maven-clean-plugin:2.6.1:clean (default-clean)& demo ---[INFO] Deleting /Users/Shared/Jenkins/Home/workspace/demo/target[INFO][INFO] ---maven-resources-plugin:2.6:resources (default-resources)& demo -[INFO] Using 'UTF-8' encoding to copy filtered resources.[INFO]Copying 1 resource[INEO]Copying 0 resource[INFO][INFO] --- maven-compiler-plugin:3.1:compile (default-compile) demo ---[ INFO] Changes detected - recompiling the module![INFO] Compiling 1 source file to/Users/Shared/Jenkins/Home/workspace/demo/target/classes[INEO][INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) edemo ---[INFO] Using 'UTF-8'encoding to copy filtered resources.[INFO] skip non existing resourceDirectory/Users/Shared/Jenkins/Home/workspace/demo/src/test/resources[INFO][INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile)Cdemo[INFO] Changes detected - recompiling the module![INFO] Compiling 1 source file to/Users/Shared/Jenkins/Home/workspace/demo/target/test-classes[INEO][ INFO] ---maven-surefire-plugin:2.20:test (default-test) C demo ---[INFO] Tests are skipped.[INFO][INFO] --- maven-jar-plugin:2.6:jar (default-jar) demo --[INFO] Building jar:/Users/Shared/Jenkins/Home/workspace/demo/target/demo-0.0.1-SNAPSHOT.jar[INFO][INFO] --- spring-boot-maven-plugin:1.5.8.RELEA.SE:repackage (default) demo[INFO][INEO] BUILD SUCCESS[INFO][INFO]Total time: 5.095 s[INFO] Finished at: 2017-10-30T16:18:18+08:00[INFO] Final Memory:29M/182M[INFO][demo]$ /bin/sh -xe/Users/Shared/Jenkins/tmp/jenkins4696633078670494346.sh+cd /Users/Shared/ Jenkins/Home/workspace/demo/docker+ cp -f ../target/demo-0.0.1-SNAPSHOT.jar .+ sudo /usr/local/bin/docker-compose down --rmi allRemoving image docker_demoFailed to remove image for service demo:404 Client Error: Not Found ("No suchimage: docker_demo: latest")+ sudo /usr/local/bin/docker-compose up -dBuilding demoStep 1/6 : FROM java: 8--->d23bdf 5b1b1bStep 2/6:VOLUME /tmp---> Using cache--->64c36a425bbfStep 3/6: ADD demo-0.0.1-SNAPSHOT.jar app.jar--->1788813d23d2step 4/6:RUN bash-c 'touch /app.jar'---> Running in e4cfd4447b78--->2c44a754963bRemoving intermediate container e4cfd4447b78Step 5/6 :EXPOSE 8080---> Running in 95b96954618e---> 8bc53f642637Removing intermediate container 95b96954618eStep 6/6:ENTRYPOINT java-Djava.security.egd=file:/dev/./urandom-jar/app.:一-->Running in al92a418f4f1--->3a27629ceba9Removing intermediate container a192a4184f1Successfully built 3a27629ceba9Successfully tagged docker demo: latestImage for service demo was built because it did not already exist. To rebuithis image you must use `docker-compose build' or 'docker-compose up --buildCreating docker demo_1..Creating docker_demo_1-[1A-[2KCreating docker demo 1 ...一[ 32mdone-[Om--[1BFinished:sUCCESS
從控制檯的輸出日誌中可以看到構建已經成功完成。這時,我們可以透過下面的網址開啟應用執行的首頁:
http://localhost:8888
從中可以看到我們預期的結果,即輸出“Hello World!”,如圖15-16所示。
在本節的輸出日誌中,有一個如下所示的錯誤提示:
+ sudo /usr/local /bin/docker-compose down --rmi allRemoving image docker demoFailed to remove image for service demo:404 Client Error:Not Found ("No suchimage: docker demo: latest")
出現這個錯誤提示的原因是在第一次構建時,並不存在可以移除的映象,但這並不影響整個構建過程的執行。
現在驗證一下專案更新的自動化部署效果。首先將專案主程式的輸出結果“Hello World ! ”改為“Hello Jerkins! ”,然後提交程式碼。完成之後,再在Jenkins 中單擊“立即構建”選項,構建完成後,重新整理訪問應用的瀏覽器,即可看到如圖15-17所示的效果。
再次檢視控制檯的輸出日誌,現在,移除映象的命令已經不再顯示錯誤,而是輸出瞭如下所示的結果,表示已經停止了執行的容器,並移除了原來的容器和映象:
+ sudo /usr/local/bin/docker-compose down--rmi allStopping docker demo 1 ...-[1A-[2KStopping docker demo 1 ... -[32mdone-[ Om-[1BRemoving docker demo 1 ...一-[1A[2KRemoving docker demo 1 ...-[32mdone-[ Om一[1BRemoving image docker demo
這裡只是一個簡單的自動部署的演示,在實際使用中,可以透過定時任務,或結合使用WebHook 的程式碼提交通知,實現自動部署。另外,還可以透過Selenium、JMeter等工具生成測試指令碼,增加自動測試的功能。
小結本章介紹瞭如何使用自動化構建工具Jenkins 設計持續交付的工作流程,並以一個簡單的例項演示了自動部署的實現過程。在該例項中,我們使用Git進行程式碼拉取、使用 Maven進行程式打包、使用Docker進行映象的建立和應用的更新與部署。從這個例項中可以看出Jenkins的強大的可擴充套件性。
透過對本章的學習,相信讀者能夠根據實際情況,建立一個完善的自動化基礎設施,從而實現在微服務釋出中整合測試和持續部署的自動化構建流程。