Jenkins Pipeline的高效使用
最近在對公司的Jenkins進行優化,發現每個運維人員針對自己的專案都寫了一個自己的指令碼,70%都是拷貝複製的,剩下的30%風格迥異。我現在也正在負責對整個CI/CD的過程進行進行優化,目前這種狀況下如果新增或縮減一個關鍵,需要把所有的指令碼都改一遍,這次的人力成本真的有點高啊。
既然要動刀子,那就一步到位,引入點黑科技為以後鋪好路,希望以後做CI/CD環節優化時不要再這麼痛苦。
如何提高Jenkins指令碼的複用性
根據專案語言抽象出5種pipeline,Gitlab中的專案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_env、project_name、git_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