你好,我是悟空。
本文目錄如下:
圖片
這次我們要接著上面的話題聊下如何通過通過編寫代碼的方式實現自動化部署 Java 項目。
而用代碼方式其實就是使用 Jenkins 強大的 pipeline 功能來實現的。
通過本篇你可以學習到如下內容:
要了解什么是Pipeline,就必須知道什么是流水線。類似于食品工廠包裝食品,食品被放到傳送帶上,經過一系列操作后,包裝完成,這種工程就是流水線工程。
在自動化部署中,開發完成的代碼經過一系列順序操作后被部署完成,這個就是部署過程中的流水線,我們通常稱作 pipeline。
之前我們的部署步驟都是通過在 Jenkins 的 UI 界面上配置出來的,但其實 Jenkisn 2.x 版本已經可以支持編寫代碼的方式來啟動自動化部署了,通過“代碼”來描述部署流水線。
Jenkins pipeline其實就是基于一種聲明式語言,用于描述整條流水線是如何進行的。流水線的內容包括執行編譯、打包、測試、輸出測試報告等步驟。
Pipeline 通過代碼來實現,其實就具有很多代碼的優勢了,比如:
當然 pipeline 的缺點也是有的:
在之前的文章中,我是通過創建一個自由風格的項目來實現自動化部署,其實還可以通過創建一個Pipeline 來實現,如下圖所示:
創建 Pipeline 任務
然后就可以在配置流水線的地方編寫代碼了。如下圖所示:
編寫流水線代碼
Pipeline 基礎結構如下所示:
pipeline{//指定運行此流水線的節點agent any//流水線的階段stages{ //階段1 獲取代碼 stage("CheckOut") { steps { script { echo "獲取代碼" } } }}
以上每一個部分都不能少,否則 Jenkins 會報錯。
Jenkins 承擔的角色如下圖所示:
圖片
Jenkins 打包部署原理圖
我們項目是 Java 項目,所以通過流水線來部署項目的步驟如下圖所示:
流水線部署步驟
Pipeline 的強大之處是可以支持傳參以及獲取參數,為了讓用戶可以選擇獲取不同的分支代碼,我在 pipeline 代碼中配置了一個參數:獲取指定的 Gitlab 分支代碼。
在 流水線代碼中添加 parameters 節點,指定類型為 string,配置相關的屬性。
pipeline { parameters { string ( name: 'GIT_BRANCH', // 參數名,后面 steps 中會用到 defaultValue: 'dev-01.30', // 默認值,會顯示在界面上,用戶可以改。 description: '請選擇部署的分支' // 說明 ) } // 其他代碼 ...}
通過參數部分,定義了一個名為GIT_BRANCH的參數,它允許用戶在構建過程中選擇要構建的分支。默認情況下,分支被設置為dev-01.30,用戶可以選擇不同的分支。
在腳本中,這個參數可以通過params.GIT_BRANCH 獲取到。
保存配置后,需要先運行一次這個項目才能看到參數配置。如下圖所示:右邊就是參數配置。
接著我們還需要定義一些常用的環境變量信息,比如 Gitlab 的倉庫地址,代碼如下所示:
pipeline { parameters { // 配置信息 ... } // 環境變量:定義 GitLab 倉庫的 URL 和分支 environment { GIT_URL = 'https://xxx/xxx.git' } // 其他代碼 ...}
environment 節點為環境變量信息,GIT_URL 變量代表 Gitlab 的倉庫地址。在腳本中,這個變量可以通過${GIT_URL}使用。
接下來我們來看下如何在 pipeline 中添加一個獲取 gitlab 倉庫代碼的步驟。
pipeline { agent any parameters { string( name: 'GIT_BRANCH', defaultValue: 'dev-01.30', description: '請選擇部署的分支') } // 定義 GitLab 倉庫的 URL 和分支 environment { GIT_URL = 'https://XXX/xxx.git' } stages { stage('獲取最新代碼') { steps { script { // 使用 params 對象獲取參數值 def branchName = params.GIT_BRANCH echo "Building branch: ${branchName}" // 使用 git 插件檢出倉庫的特定分支 checkout([ $class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[ credentialsId: '211583e9-8ee1-4fa2-9edd-d43a963de8f2', // 在 Jenkins 憑據中定義的 GitLab 憑據 ID url: "${GIT_URL}" ]] ]) } } } }}
注意:獲取分支的憑證是一個 ID,這個憑證信息是在 Jenkins 系統配置中加的。可以按照如下頁面路徑添加憑證:Dashboard->Manage Jenkins->Credentials->System->Add domain。也可以通過如下 URL 訪問
http://<你的服務器 IP>:8080/manage/credentials/store/system/
圖片
我們可以運行一下這個項目來測試 pipeline 代碼。運行結果如下圖所示,可以看到右側的階段視圖,整體耗時和每個步驟的耗時,以及每個步驟的成功與否都顯示出來了,非常直觀。
圖片
本篇主要講解的是部署 Java 項目,所以編譯項目也是采用 Maven 打包的方式。在 pipeline 腳本中執行 mvn 打包命令即可。
stage('編譯代碼') { steps { script { echo "--------------- 步驟:開始編譯 --------------- " bat 'mvn clean package' echo "--------------- 步驟:編譯完成 --------------- " } } }
核心代碼:bat 'mvn clean package'
因為我的 Jenkins 是部署在 Windows 機器上,所以執行命令用的 windows 自帶的 bat 工具來執行的。
關于 maven 工具的配置可以看之前寫的第二篇內容:
喝杯咖啡,一鍵部署完成!(建議收藏)
編譯完成后,就可以將 Jenkins 工作空間的 JAR 包上傳到服務器的 temp 目錄下。
如果你想部署指定的某些微服務,可以通過傳參的方式來上傳和更新指定的微服務。原理圖如下所示:
圖片
為了實現可以選擇部署哪些微服務,需要安裝一個多選插件:Extended Choice Parameter。
圖片
Extended Choice Parameter 插件
接下來是編寫的參數配置代碼:
parameters { extendedChoice ( defaultValue: 'All', description: '需要部署的微服務', multiSelectDelimiter: ',', name: 'SERVICE_NAME', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', value:'All, passjava-account, passjava-file', visibleItemCount: 10 )}
配置保存后并運行一次后,就可以在 pipeline 中看到配置選項:
圖片
實現的效果如下圖右下角所示,可以支持多選。
圖片
上傳需要使用 sshPublisher 插件,在第二篇文章中已介紹了。
下面上傳代碼的作用是遍歷 filesToCopy 列表中的文件,然后通過 SSH 將這些文件上傳到遠程服務器的指定目錄中。
filesToCopy.eachWithIndex { file, index -> echo "開始上傳 JAR 包 ${file} ..." sshPublisher( failOnError: true, publishers: [ sshPublisherDesc( configName: "${SSH_URL}", verbose: true, transfers: [ sshTransfer( execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'apps/temp/', remoteDirectorySDF: false, removePrefix: removePrefixs[index], sourceFiles: file ) ] ) ] ) echo "完成上傳 JAR 包 ${file}"}
filesToCopy 就是通過用戶勾選的服務名轉成了對應的本地 JAR 包路徑。
switch(service) { case 'passjava-account': filesToCopy.add("passjava-modules/passjava-module-account/passjava-module-account-core/target/passjava-account.jar") removePrefixs.add("passjava-modules/passjava-module-account/passjava-module-account-core/target") break case ... }
備份的思路:逐個處理 serviceNameList 中的服務名稱,然后通過 SSH 連接到遠程服務器執行備份操作。serviceNameList 就是用戶勾選的服務名的集合。原理圖如下所示:
備份服務器 JAR 包
核心代碼如下:
serviceNameList.each { service -> echo "開始備份微服務 ${service} 包" sshPublisher( failOnError: true, publishers: [ sshPublisherDesc( configName: "${SSH_URL}", verbose: true, transfers: [ sshTransfer( execCommand: "mkdir -p /nfs-data/wukong/apps/bak/${timestamp} && cd /nfs-data/wukong/apps && mv ${service}.jar ./bak/${timestamp}/${service}-${timestamp}.jar" ) ] ) ] )
這段代碼的作用是遍歷 serviceNameList 列表中的服務名稱,然后通過 SSH 連接到遠程服務器執行備份操作,將每個服務的 JAR 包移動到指定的備份目錄,并根據時間戳進行命名。
更新最新的 JAR 包就是將最新的 JAR 包放到對應的容器映射的目錄,后面重啟容器的時候,就能用最新的 JAR 包啟動了。原理圖如下所示:
更新 JAR 包
serviceNameList.eachWithIndex { service, index -> echo "開始更新第 ${index + 1} 個 JAR 包,/nfs-data/wukong/apps/temp/${service}.jar ..." sshPublisher( failOnError: true, publishers: [ sshPublisherDesc( configName: "${SSH_URL}", verbose: true, transfers: [ sshTransfer( execCommand: "cd /nfs-data/wukong/apps && mv -f ./temp/${service}.jar ${service}.jar", execTimeout: 120000 ) ] ) ] ) echo "----- 完成更新 JAR 包 -----"}
這段代碼的作用是遍歷 serviceNameList 列表中的服務名稱,然后通過 SSH 連接到遠程服務器執行更新操作,將每個服務在 /nfs-data/wukong/apps/temp/ 目錄下的 JAR 包移動到對應的位置,完成更新。
啟動服務就是將 docker swarm 管理的服務重啟下,原理圖如下所示:
圖片
后端項目使用 Docker Swarm 部署的,重啟服務的命令如下:
sudo docker service update --force <服務名>
我們可以編寫遠程執行這行命令的代碼,pipeline 核心代碼如下:
serviceNameList.eachWithIndex { service, index -> echo "開始重啟第 ${index + 1} 個微服務,${service} ..." sshPublisher( failOnError: true, publishers: [ sshPublisherDesc( configName: "${SSH_URL}", verbose: true, transfers: [ sshTransfer( execCommand: "sudo docker service update --force ${commands[service]}", execTimeout: 120000 ) ] ) ] ) echo "----- 完成重啟微服務 -----"}
這段代碼的作用是遍歷 serviceNameList 列表中的服務名稱,然后通過 SSH 連接到遠程服務器執行重啟操作,完成微服務的重啟。
最后整個執行結果如下圖所示:總共耗時 3min41s。
圖片
通過本篇的實戰內容,我們學習到了通過編寫 pipeline 代碼來實現部署后端項目。推薦大家都用 pipeline 來部署項目,好處是更加靈活。
另外本篇還沒有對 Jenkins pipeline 的版本管理,我們其實可以將 pipeline 代碼作為一個文件上傳到 Gitlab,然后通過 Jenkins 拉取最新的 jenkins pipeline 文件來執行部署,這樣更便于管理 pipeline 文件。
本文鏈接:http://www.tebozhan.com/showinfo-26-81249-0.html用代碼實現流水線部署,像詩一般優雅
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 加速 Rust 編譯時間,掌握這個技巧,速度全面提升 30 ~ 40 %
下一篇: 幾個祖傳代碼不遵守就想罵的代碼規范