1. 程式人生 > >Jenkins Pipeline的高效使用

Jenkins Pipeline的高效使用

最近在對公司的Jenkins進行優化,發現每個運維人員針對自己的專案都寫了一個自己的指令碼,70%都是拷貝複製的,剩下的30%風格迥異。我現在也正在負責對整個CI/CD的過程進行進行優化,目前這種狀況下如果新增或縮減一個關鍵,需要把所有的指令碼都改一遍,這次的人力成本真的有點高啊。

既然要動刀子,那就一步到位,引入點黑科技為以後鋪好路,希望以後做CI/CD環節優化時不要再這麼痛苦。

如何提高Jenkins指令碼的複用性

根據專案語言抽象出5pipelineGitlab中的專案webhook保持不變,仍然觸發Jenkins中對應的Job,該Job只負責將定製化的引數傳給與專案語言匹配的Pipeline

Pipeline的stage細節

將每種語言Jenkins中的pipeline拆成如下4-5個環節(有些語言不需要build),環節中規定要執行的命令,專案之間的差異性以變數形式體現。

將每種語言Jenkins中的pipeline拆成如下4-5個環節(有些語言不需要build),環節中規定要執行的命令,專案之間的差異性以變數形式體現。

一次編譯多個版本

現有的Jenkins任務中存在這種使用場景,gitlab打tag後Jenkins需要分別編譯和交付到測試環境和生產環境。這種情況下呼叫兩次公用pipeline:

實現細節:

1 Gitlab準備部分:

詳見:https://blog.csdn.net/yejingtao703/article/details/83065591

2 Jenkins安裝

下載地址:https://jenkins.io/download/

jenkins.war方式最簡單,準備好java環境直接執行命令:

$java -jar jenkins.war --httpPort=8080

如果不指定httpPort預設埠是8080,第一次啟動時注意留意輸出日誌中最後有admin登陸的密碼。

 

3 準備外掛

先預設安裝Jenkins初始化外掛。

Jenkins實現Pipeline的核心外掛有2個,其中實現pipeline 的外掛在Jenkins啟動時預設安裝就可以裝好。需要手動安裝的第二個外掛叫“Parameterized Trigger plugin”,該外掛負責Jenkins的Job之間傳遞引數。

4 pipeline指令碼

Jenkins Pipeline以groovy語法定義出每個stage要乾的事情,例如我的指令碼:

node {
   def staticPara
   def gittag
   
   stage('validate') {
      echo "${params.build_env}"
      echo "${params.project_name}"
      echo "${params.git_commit}"
   }
   
   stage('Preparation') {
      staticPara = 'static-hello'
      echo "${staticPara}"
      sh 'mkdir -p ~/repository/${project_name}/${build_env}'
   }
   
   stage('checkout') {
       echo 'checkout'
       checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '3b762ad3-0fab-4115-8c0c-17b32454d72d', url: '[email protected]:root/${project_name}.git']]])
       gittag = sh(returnStdout: true, script: 'git describe --tags ${git_commit}').trim()
       echo "${gittag}"
   }
   
   stage('build'){
       echo 'build'
       sh 'mvn clean package -DskipTests'
       echo "Finish Build"
   }
   
   stage('deploy') {
      echo "deploy"
      echo "${gittag}"
      sh "mv target/${project_name}.jar ~/repository/${project_name}/${build_env}/${project_name}-${gittag}.jar"
   }
}

定義了5個環節,每個環節規定了要做的事情,專案差異性部分以變數來代替,而變數分為staticPara這種pipeline內部宣告的變數和build_envproject_namegit_commit這種前端Jenkins job傳來的引數。 

此類引數定義宣告:

5 Gitlab整合 

5.1 gitlab新增webhook

 由於我們只在打tag的時候觸發Jenkins,所以webhook監聽事件這裡只需配置Tag Push

5.2 給每個專案在Jenkins中建立一個私有的job

 

Build Trigger那裡配置一個輪詢SCM,預設即可,預設是每秒鐘都去檢查一次。 

指令碼很簡單,只需要列印做下日誌就好,因為主要工作都在後面pipeline job中,這裡核心的工作是將定製化業務引數傳給pipeline

 

這樣就打通了gitlab—>jenkins私有job—>Jenkins公共job這條線。

6 細節部分:

6.1 pipeline併發問題

Jenkins私有job支援一次觸發多個公共job,為了保證公共job專案間不會相互干擾可以有兩個方案進行選擇:需要把pipeline job配置為“不允許併發構建”,或者在pipeline中自己定義執行目錄的方式進行隔離。根據自己應用場景的併發程度來定,我的場景併發概率很小,所以選擇前者,如果選擇後者一定要仔細檢查是否會有衝突。

6.2 gitlab打tag的問題

gitlab上專案打tag的方式沒有要求,可以maintainer直接在控制檯打tag,也可以本地將tag push到伺服器,都可以觸發jenkins。

 

重要:這種模式下如何提高併發

公共的pipeline(java-job)在執行時,回到自定義(java-odin)的jenkins的workspace工作目錄下去執行pipeline指令碼,這樣操作會帶來2大優點:

1 可以放開公共pipeline併發限制,因為他們指令碼工作目錄是相互隔離的,不會互相干擾

2 公共pipeline中不需要git,提高了單次執行的效率。

指令碼如下:

node {
   def staticPara
   def gittag
   
   stage('Preparation') {
      staticPara = 'static-hello'
      echo "${params.build_env}"
      echo "${params.project_name}"
      echo "${params.git_commit}"
      echo "${staticPara}"
      echo "${params.job_name}"
   }
   
   dir("../${params.job_name}"){
       stage('cd workspace') {
       echo 'cd workspace'
       gittag = sh(returnStdout: true, script: 'git describe --tags ${git_commit}').trim()
       echo "${gittag}"
       }
   
       stage('sleep') {
           sleep 180
       }
   
       stage('build'){
           echo 'build'
           sh 'mvn clean package -DskipTests'
           echo "Finish Build"
       }
   
       stage('deploy') {
          echo "deploy"
          echo "${gittag}"
          sh "mv target/${project_name}.jar ~/jenkins/repository/${project_name}/${build_env}/${project_name}-${gittag}.jar"
       }
   }
   
   
}

這裡的核心程式碼是: dir("../${params.job_name}")

可能你會問有這麼好的方案為什麼一開始推薦不支援並行呢?因為這種方案受限於你Jenkins所在機器的物理資源的約束。

Jenkins預設只能並行執行2個Job,雖然我們可以修改這個限制,但是一般不能超過CPU核數,所以說對於一個雙核CPU的Jenkins機器來說,這兩種方案並沒啥本質區別,只有當你Jenkins伺服器硬體上去之後採用第二種方案才會提現它的價值。

檢視CPU核數:

cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l