1. 程式人生 > >乾貨 | Jenkins2.0 Pipeline框架(iPipeline)優化實踐之路(一)

乾貨 | Jenkins2.0 Pipeline框架(iPipeline)優化實踐之路(一)

點選上方“中興開發者社群”,關注我們

每天讀一篇一線開發者原創好文

640?wx_fmt=png&wxfrom=5&wx_lazy=1

概述

XXX專案原CI系統由專案自行搭建,使用Jenkins傳統的Job方式來實現VerifyCI和MergeCI以及DailyBuild。隨著專案規模越來越大,分支越來越多,合程式碼的頻率也逐漸增大的情況下,現有系統呈現出諸多不便之處。為解決這些問題,專案嘗試引入一系列現成公司級Devops研發工具並結合Jenkins2.0的Pipeline新特性來改造本專案Pipeline流程。

Pipeline as Code 是 Jenkins 2.0 版本的精華所在,是幫助 Jenkins 實現從 CI 到 CD 華麗轉身的關鍵工具。所謂 Pipeline,簡單來說,就是一套運行於 Jenkins 上的工作流框架,將原本獨立運行於單個或者多個節點的任務連線起來,實現單個任務難以完成的複雜釋出流程。落實到程式碼級別,即我們只需要把精力集中在編寫 Jenkinsfile 檔案上,然後將其隨同程式碼庫一起託管,Jenkins可以根據Jenkinsfile來迅速拉起專案的CI流程,方便高效。

但是隨著多個專案的試行、落地,發現基於Jenkins2.0的Pipeline功能強大,但是具體應用到各個專案還有如下幾個痛點:

  • 各個專案都在編寫自己特色的Jenkinsfile,很多時候互相複製修改一下程式碼實現,Jenkinsfile冗餘度非常高;

  • 按照Jenkins1.x時代的思路,訂製化自己的CI/CD流程、郵件通知、報告輸出,轉換過程緩慢而痛苦;

  • 遇到技術問題沒有能力解決、採用一些過時的方法和工具,而其他專案組已經解決一些技術問題或者採用了更加先進的方法和工具,互相併不能及時分享;

為了解決這些問題,經過專案反覆調研和摸底,最終採用了中開社上開源的Jenkins2.0的Pipeline共創庫iPipeline(又稱plll庫)來輔助本專案重構CI流程。

iPipeline是簡化CI Pipeline部署的工具集,是面向開發人員和CI配置管理員的函式庫,其封裝了Jenkins 2.0的常用函式,集成了Gerrit、製品庫、雲CI、度量、告警採集、郵件通知,另外提供docker封裝的工具集(複雜度、Klocwork、度量分析、度量匯入等)。利用其可以幫助我們節省很多精力,避免重複造輪子,因此非常滿足我們專案的需求。

問題描述

iPipeline框架在本專案的實踐過程中確實提高了很多效率和幸福感,但結合本專案一些實際的使用情況,發現其仍然存在一些優化和改進的點。為此針對我們專案的需要,我們對iPipeline做了如下一些優化並實踐。

  • 問題1

利用plll庫提供的

pdocker介面,可以很方便地在指定的節點上執行指定的Docker容器來完成相關CI任務。比如本專案圈複雜度檢查已經Docker化,因此可以利用pdocker介面,通過配置上映象名、對映目錄以及需要執行的指令與指令碼來執行程式碼的圈複雜度檢查。

但是實際在對pdocker介面的使用過程中發現,plll庫每次都會去節點上pull映象,然後再執行,這對於映象其實已經存在於本地節點的情況其實並沒有必要,因此需要改造。

  • 問題2

目前plll庫提供的Update介面僅支援Gerrit程式碼倉庫的程式碼檢出更新,但本專案執行某些用例測試需要的報文儲存於SVN庫上,因此有必要擴充plll庫原有介面,使其支援SVN庫的程式碼更新

帶著這兩個問題,我們對plll庫做出了對應的一些優化並且實踐之。

優化實踐

優化1:pdocker介面是否需要拉取映象由使用者自定義

改造pdocker介面,新增引數來控制是否需要pull映象,介面程式碼片段如下:

  1. /**

  2. * 工具名稱:docker執行

  3. * 工具描述:

  4. *         image      - 映象的全路徑

  5. *         needPull   - 是否需要pull映象

  6. *         before_cmd - 以root執行的命令列,在執行user_cmd前執行

  7. *         volumes    - 路徑對映清單,"a:b,c:d"

  8. *         params     - 執行引數

  9. *         profile    - 環境檔案,可執行

  10. *         user_cmd   - 以當前使用者執行的命令列(需要映象支援adduser命令)

  11. *         after_cmd  - 以root執行的命令列,在執行user_cmd後執行

  12. *         local_dir  - 存放臨時檔案的目錄(要求有許可權對映到容器內)

  13. *         shared_dir - 存放程式碼和產出檔案的目錄(要求有許可權對映到容器內)

  14. *         sh_exec    - shell程序,預設為sh

  15. **/

  16. def call(image, needPull, before_cmd, volumes='',params='', profile='', user_cmd='', after_cmd='',

  17.            local_dir=env.LOCAL, shared_dir=env.SHARED, sh_exec='sh'){

  18. // ...此處程式碼省略...

  19. if( needPull =="no"){

  20.        echo "no need to pull image !!! The image exists in local!"

  21.        writeFile file:docker_entry_file,   text:"""

  22.            set -e

  23.            docker run --rm ${params} ${volumes} ${image} ${sh_exec} -x -c ${docker_run_file}

  24.        """

  25. }elseif( needPull =="yes"){

  26.        writeFile file:docker_entry_file,   text:"""

  27.            set -e

  28.            docker pull ${image}

  29.            docker run --rm ${params} ${volumes} ${image} ${sh_exec} -x -c ${docker_run_file}

  30.        """

  31. }

  32. // ...此處程式碼省略...

  33. }

由程式碼可以看出,通過新增needPull引數,即可由使用者自定義是否需要pull映象。

使用舉例:

例如本專案呼叫pdocker介面利用自制docker映象完成程式碼圈複雜度檢查:

  1. pnode("${env.NODE_NAME}"){

  2.    plll.Check("CCN_DOCKER","CCN_DOCKER",[

  3.        run_execute:{     pdocker (

  4. /* image      */"docker.zte.com.cn:5000/10010891/lizard:v1",

  5. /* need pull  */"no",

  6. /* cmd           */"cd /home/code/ && chmod -R 777 * && cd script/VerifyCI/CCNCheck/ && sh +x lizard.sh",

  7. /* volumes    */"-v ${env.SHARESPACE}/${env.XXXXX_DIR}:/home",

  8. /* params     */"--privileged",

  9. )

  10. },

  11.        param:[

  12.            report_file:[]

  13. ]

  14. ]);

  15. }

由於docker.zte.com.cn:5000/10010891/lizard:v1已經存在於我們的外掛節點上,因此此處needPull引數置為no即可控制pdocker內部無需再去pull映象。

優化2:擴充框架Update介面,使其支援SVN程式碼更新

優化Plll庫程式碼,加入UpdateSVN介面來支援SVN庫的程式碼檢出與更新

  1. /**

  2. * 功能名稱:Update

  3. * 功能描述:通過SVN更新程式碼

  4. **/

  5. defUpdateSVN(name, desc, args){

  6. LogDebug("[DEBUG] Update: ${name}, ${desc}")

  7.    args.run_execute ={

  8.        dir("${args.scm.path}"){

  9.            svn_checkout( args.scm.keyid, args.scm.repo, args.scm.path )

  10. }

  11. }

  12. /* 呼叫功能適配 */

  13. FunctionAdapter("Update","update", name, desc, args){}

  14. return

  15. }

  16. /**

  17. * 工具名稱:svn_checkout

  18. * 工具描述:svn更新程式碼

  19. * 引數描述:

  20. *     - keyid: SVN庫的Credentials ID

  21. *     - repo:  SVN庫Repo路徑

  22. *     - path:  程式碼下載路徑

  23. **/

  24. def svn_checkout(keyid, repo, path){

  25.    checkout([

  26.        $class:'SubversionSCM',

  27.        additionalCredentials:[],

  28.        excludedCommitMessages:'',

  29.        excludedRegions:'',

  30.        excludedRevprop:'',

  31.        excludedUsers:'',

  32.        filterChangelog:false,

  33.        ignoreDirPropChanges:false,

  34.        includedRegions:'',

  35.        locations:[

  36. [credentialsId:"${keyid}", depthOption:'infinity', ignoreExternalsOption:true,local:".", remote:"${repo}"]

  37. ],

  38.        workspaceUpdater:[$class:'UpdateUpdater']

  39. ])

  40. return

  41. }

使用舉例:

使用者只需要配置上:

  • SVN庫的Credentials ID

  • SVN庫Repo路徑

  • 程式碼下載路徑

即可完成SVN程式碼檢出和更新,示例如下:

  1. // 先配置好SVN相關引數

  2. env.SVN_KEY_ID         ="89a6fe98-8f0c-4fe6-829e-6d1cbda188e1"

  3. env.CASE_DIR           ="/jenkins_ci/CASE_TEST/PATH"

  4. env.CASE_SVN_URL       ="svn://XXX.XX.XXX.XXX/XXXXXXX/case/XXXX"

  5. // 呼叫UpdateSVN介面完成SVN庫程式碼更新

  6. plll.UpdateSVN('SVN_UP','更新SVN上報文',[

  7.        scm:[keyid:"${env.SVN_KEY_ID}", repo:"${env.CASE_SVN_URL}", path:"env.CASE_DIR"],

  8.        run_dir:"${->OUTPUT_PATH}"

  9. ])

推廣建議

本文章相關優化改進可推廣至需要利用docker映象完成相關CI任務和程式碼管控涉及SVN庫的專案

下篇文章將於明天釋出,主要介紹報告/郵件可擴充套件,敬請期待~

拓展閱讀

640?wx_fmt=png