Warning: 本文不是面對初學者的,若是你看不懂pipeline,那我也沒辦法.若是許多概念不明白的話,能夠點下面的官方文檔多看看.node
簡單的翻譯一下 官方文檔 的原話: 在多個流水線之間共享步驟以此來減小代碼的冗餘.
git
那麼這究竟是什麼意思呢? 咱們知道當咱們使用聲明式的流水線的時候,必需要在項目的代碼倉庫中放一個 Jenkinsfile
文件, 當咱們項目愈來愈多的時候, Jenkinsfile
也會愈來愈多,而後構建的過程也大同小異,這時候你就會發現一些問題:github
共享庫的最原始的用法就是解決代碼冗餘的問題的,那麼咱們來看一個比較官方的用法docker
文中的全部內容均在: https://github.com/jinyunboss/jenkins-libraries服務器
# 基本的結構就是這樣的 . ├── src │ └── com │ └── lotbrick │ └── jenkins └── vars
// vars/execShell.groovy def call(params) { // 讓咱們來執行個echo命令 sh "echo ${params}" }
至於爲何是配置全局共享庫,請看這裏: https://www.jenkins.io/doc/book/pipeline/shared-libraries/#global-shared-librarieside
在 Jenkins > 系統配置 > Global Pipeline Libraries
中添加一個共享庫,名爲 lotbrick
函數
@Library('lotbrick') _ pipeline { agent any stages { stage("第一步") { steps { script { execShell("我是一個執行sh命令的例子") } } } } }
好像看起來這個例子並無怎麼簡化Jenkinsfile呀,沒事,來再看一個ui
// vars/inputMsg.groovy def call(params){ try { input( id: "${params.id}", message: "${params.msg}" ) } catch(err) { // 獲取執行Input的用戶 env.user = err.getCauses()[0].getUser().toString() userInput = false env.QATEST_TEST = false echo "Aborted by: [${user}]" // 拋出異常確保流程終止 throw err } }
@Library('lotbrick') _ pipeline { agent any stages { stage("第一步") { steps { script { execShell("我是一個執行sh命令的例子") } } } stage("第一步") { steps { script { inputMsg([id:"input1",msg:"我是一個input步驟"]) } } } } }
這回咱們獲得了一個input的步驟,雖然看起來也沒簡化多少,可是,咱這只是一個input,若是是比較長的執行ansible的步驟呢?
咱們來看一下調用ansible playbook須要的代碼this
ansiColor('xterm') { ansiblePlaybook( playbook: 'lotbrick.yml', inventory: 'production', disableHostKeyChecking: true, //inventoryContent: 'master', credentialsId: 'lotbrick-test1-46a8-91cd-185a08255a53', colorized: true, ) }
執行一個playbook就須要這些代碼,若是執行十個呢?量變就會引發質變,其餘的就要靠本身去發掘了.lua
剛纔咱們簡單的瞭解了一下共享庫是怎麼簡化Jenkinsfile的,那麼我們來點正經的.
官方給的例子基本都是腳本式的流水線,那我們也來一個正點的腳本式的流水線
// vars/build.groovy def call(params) { node { stage("拉一個代碼") { git url: "${params.git_url}" } stage("執行一個命令"){ execShell("${params.cmd}") } stage("打印如今的時間"){ sh "date" } stage("input步驟"){ inputMsg([id:"input1",msg:"我是一個input步驟"]) } } }
@Library('lotbrick') _ build([ git_url:"https://github.com/jinyunboss/docker-compose.git", cmd:"ls -al" ])
上面咱們看到了腳本式的pipeline,固然聲明式的也能夠.來瞅瞅
// vars/buildDeclarative.groovy def call(params) { pipeline { agent any options { // 禁止同時運行多個流水線 disableConcurrentBuilds() } environment { examples_var1 = sh(script: 'echo "當前的時間是: `date`"', returnStdout: true).trim() } stages{ stage("聲明式流水線: 拉一個代碼") { steps { git url: "${params.git_url}" } } stage("聲明式流水線: 執行一個命令"){ steps { script { sh "${params.cmd}" } } } stage("聲明式流水線: 打印如今的時間"){ steps { script { inputMsg([id:"${params.input_id}",msg:"${params.input_msg}"]) } } } } } }
@Library('lotbrick') _ buildDeclarative([ git_url:"https://github.com/jinyunboss/docker-compose.git", cmd:"ls -al", input_id: "input1", input_msg: "聲明式流水線的input" ])
經過上面的例子,我以爲應該瞭解來基本的共享庫的用法了.
那麼來點騷操做來解決咱們開頭的幾個問題,
首先,既然是多分支的倉庫,那麼確定要兩個Jenkinsfile,對應不一樣的環境和發佈步驟
其次,在項目倉庫中全部分支的Jenkinsfile內容要一致,解決合併衝突的問題
綜合上面的問題來看,咱們須要的解決的問題只有一個,隱藏咱們的Jenkinsfile
# 由於咱們要用多分支的Job,因此,咱們的目錄結構要這樣 # # 目錄結構以下: ├── jenkins.lotbrick.com │ ├── dev.groovy │ └── master.groovy └── www.lotbrick.com ├── dev.groovy └── master.groovy
def call(params) { pipeline { agent any options { // 禁止同時運行多個流水線 disableConcurrentBuilds() } environment { examples_var1 = sh(script: 'echo "當前的時間是: `date`"', returnStdout: true).trim() } stages{ stage("master: 執行一個命令"){ steps { script { sh "ls -al" } } } stage("master: 打印如今的時間"){ steps { echo "${examples_var1}" } } stage("master: 打印JOB_NAME"){ steps { echo "${JOB_NAME}" } } } } } // 記得要return喲,由於咱們是調用這個文件 return this
// vars/run.groovy def call(params){ // 定義jenkinsfile的路徑 def jenkinsfile_dir = "/data/jenkins-jenkinsfile/" node { // echo "${jenkinsfile_dir}" // echo "${params.env.JOB_NAME}" // 加載Jenkinsfile的groovy文件 def jenkinsfile = load("${jenkinsfile_dir}/${params.env.JOB_NAME}.groovy") // 調用groovy中的call函數,將params也就是job運行時的全部公開的函數和變量傳進去 jenkinsfile.call(params) // "${name}"(params) //evaluate('aaa(params)') } }
[root@jenkins jenkins-jenkinsfile]# ll total 8 drwxr-xr-x 2 root root 4096 Jun 12 18:07 jenkins.lotbrick.com drwxr-xr-x 2 root root 4096 Jun 12 18:07 www.lotbrick.com [root@jenkins jenkins-jenkinsfile]# tree . ├── jenkins.lotbrick.com │ ├── dev.groovy │ └── master.groovy └── www.lotbrick.com ├── dev.groovy └── master.groovy 2 directories, 4 files [root@jenkins jenkins-jenkinsfile]# pwd /data/jenkins-jenkinsfile [root@jenkins jenkins-jenkinsfile]#
@Library('lotbrick') _ run(this)
創建好Job以後就能看到Jenkins已經發現了咱們倉庫的兩個分支了,接下來分別運行兩個分支的Job
最後咱們來分析一下執行的過程:
仔細看上面的執行過程,第4步,克隆庫文件到workspace/JOB_NAME@libs,若是咱們有十個JOB,那麼Jenkins就會克隆十次.
當咱們把實際的pipeline寫在vars目錄下的時候,日積月累這個目錄文件不少的時候,那麼就會致使重複克隆,影響執行效率
最要命的是,vars目錄下的文件會直接變成全局的變量,能夠直接調用的,變量太多.JAVA的內存消耗能夠很恐怖的(感受會這樣)
我沒有考慮多個node的狀況,咱這只是個小公司,沒這麼多項目來發布可是我知道的一點就是,當pipeline的 agent選項爲any的時候,Jenkins會默認把代碼拉到當前node的workspace下,因此不須要再去拉一遍代碼