《Jenkins 2.x實踐指南》讀書筆記-環境變量與構建工具

1. 環境變量

環境變量可以被看作是pipeline與Jenkins交互的媒介。比如,可以在pipeline中通過BUILD_NUMBER變量知道構建任務的當前構建次數。環境變量可以分爲Jenkins內置變量和自定義變量。

1.1 內置變量

在pipeline執行時,Jenkins通過一個名爲env的全局變量,將Jenkins內置環境變量暴露出來。其使用方法有多種,示例如下:

pipeline {
  agent any
  stages {
    stage('Example') {
      steps {
         echo "Running ${env.BUILDNUMBER} on ${env.JENKINS_URL}" # 方法1 推薦
         echo "Running $env.BUILDNUMBER on $env.JENKINS_URL"  # 方法2
         echo "Running ${BUILDNUMBER} on ${JENKINS_URL}"   # 方法3 不推薦,難排查
      }
    }
  }
}

通過訪問<Jenkins master的地址>/pipeline-syntax/globals#env來獲取完整列表。在列表中,當一個變量被聲明爲"For a multibranch project"時,代表只有多分支項目纔會有此變量。

下面簡單介紹幾個在實際工作中經常用到的變量。

  • BUILD_ NUMBER:構建號,累加的數字。在打包時,它可作爲製品名稱的一部分,比如server-2.jar
  • BRANCH_ NAME:多分支pipeline項目支持。當需要根據不同的分支做不同的事情時就會用到,比如通過代碼將release分支發佈到生產環境中、master分支發佈到測試環境中。
  • BUILD_ URL:當前構建的頁面URL。如果構建失敗,則需要將失敗的構建鏈接放在郵件通知中,這個鏈接就可以是BUILD _URL
  • GIT_BRANCH:通過git拉取的源碼構建的項目纔會有此變量。

在使用env變量時,需要注意不同類型的項目,env變量所包含的屬性及其值是不一樣的。比如普通pipeline任務中的GIT_BRANCH變量的值爲origin/master,而在多分支pipeline任務中GIT_BRANCH變量的值爲master
所以,在pipeline中根據分支進行不同行爲的邏輯處理時,需要留意。

1.2 自定義pipeline環境變量

當pipeline變得複雜時,我們就會有定義自己的環境變量的需求。聲明式pipeline提供了environment指令,方便自定義變量。比如:

pipeline {
    agent any
    environment {
        CC = "clang"
    }
    stages {
        stage("Example") {
            environment {
                DEBUG_FLAGS = "-g"
            }
            steps {
                sh "${CC} ${DEBUG_FLAGS}"
                sh "printenv"
            }
        }
    }
}

environment指令可以用在pipeline中定義,作用域就是整個pipeline,當定義在stage階段,只在當前stage有效。

但是這些變量都不是跨pipeline的,比如pipeline a訪問不到pipeline b的變量。在pipeline之間共享變量可以通過參數化pipeline來實現。

環境變量的互相引用:

environment {
    __server_name = 'mail-server'
    __version = "${BUILD_NUMBER}"
    __artifact_name = "${__server_name}-${__version}.jar"
}

小技巧 :

  1. 在調試pipeline時,可以在pipeline的開始階段加一句:sh 'printenv',將env變量的屬性值打印出來。這樣可以幫助我們避免不少問題。
  2. 自定義變量時,爲避免命名衝突,可根據項目或公司加上統一前綴,如__server_name__就是前綴。

1.3 自定義全局環境變量

定義全局環境變量可以跨pipeline使用。
進入Jenkins→Manage Jenkins→Confiure System找到Global properties→勾選"Environment variables"複選框,單擊“Add”按鈕,在輸入框中輸入變量名和變量值即可。

自定義全局環境變量會被加入env屬性列表中,所以使用時可以直接用${env.g_name}引用。

2. 構建工具

構建是指將源碼轉換成一個可使用的二進制程序的過程。這個過程可以包括但不限於這幾個環節:下載依賴、編譯、打包。構建過程的輸出——比如一個zip包,我們稱之爲製品(有些書籍也稱之爲產出物)。而管理製品的倉庫,稱爲製品庫。

2.1 構建工具的選擇

對構建工具的選擇,還取決於團隊對工具本身的接受程度。建議是,團隊中同一技術棧的所有項目都使用同一個構建工具。

2.2 tools指令介紹

tools指令能幫助我們自動下載並安裝所指定的構建工具,並將其加入PATH變量中。這樣,我們就可以在sh步驟裏直接使用了。但在agent none的情況下不會生效。

tools指令默認支持3種工具:JDK、Maven、Gradle。通過安裝插件,tools指令還可以支持更多的工具。接下來,我們介紹幾種常用的構建環境的搭建。

2.3 JDK環境搭建

2.3.1 自動安裝JDK

進入Manage Jenkins→Global Tool Configuration→JDK頁,單擊“Add JDK”:

注意

  1. 這裏需要oracle帳戶驗證。
  2. Jenkins不會馬上下載JDK,而是當pipeline使用到時纔會直接執行下載操作。

2.3.2 自定義JDK路徑

基於安全的考慮,公司的內網可能無法直接訪問因特網或者因爲無法訪問官方插件地址,所以使用自動下載會失敗。這時就需要在Jenkins agent上準備JDK,然後在Manage Jenkins→Global Tool Configuration→JDK頁中指定名稱和JAVA_HOME路徑:

注意

  1. 使用docker agent或者kubernetes agent時,可使用agent基礎鏡像內安裝JDK定製成自定義鏡像。
  2. 可以腳本自動化,即在使用tools安裝JDK前,腳本自動提前準備好這個JAVA_HOME的JDK。

2.4 Maven

2.4.1 使用Maven進行構建

Jenkins pipeline的tools指令默認就支持Maven。所以,使用Maven只需要兩步。

  1. 進入Manage Jenkins→Global Tool Configuration→Maven頁,單擊“Add Maven”:


2. 在Jenkinsfile中指定Maven版本,並使用mvn命令。

2.4.2 使用Managed files設置Maven

Maven默認使用的是其官方倉庫,國內下載速度很慢。所以,我們通常會使用國內的Maven鏡像倉庫。這時就需要修改 Maven 的配置文件 settings.xmlsettings.xml 文件的默認路徑爲${M2_HOME}/conf/settings.xml。但是,我們是不可能登錄上Jenkins的機器,然後手動修改這個文件的。
Config File Provider插件能很好地解決這個問題。只需要在Jenkins的界面上填入settings.xml的內容,然後在pipeline中指定settings.xml就可以了。也就是說,對於不同的pipeline,可以使用不同的settings.xml
具體實現方法如下:

  1. 安裝Config File Provider插件。
  2. 進入Manage Jenkins頁面,就可以看到多出一個“Managed files”菜單。
  3. 單擊“Managed files”進入,在左側菜單欄中選擇“Add a new Config”,就會看到該插件支持很多種配置文件的格式及方式,
  4. 選擇“Global Maven settings.xml”選項。因爲我們的設置是全局的。填寫“ID”字段,Jenkins pipeline會引用此變量名。假如使用的ID爲maven-global-settings。
  5. 在編輯頁將自定義的Maven settings.xml的內容粘貼到“Content”字段中,
  6. 在Jenkins pipeline中使用的方法如下:
configFileProvider([configFile(fileId: "maven-global-settings", variable: "MAVEN_GLOBAL_ENV")]) {
    sh "mvn -s $MAVEN_GLOBAL_ENV clean install"
}

2.5 Go語言環境搭建

Jenkins支持Golang的構建,只需要以下幾步。

  1. 安裝Go插件
  2. 進入Manage Jenkins→Global Tool Configuration→Go頁


3. 在pipeline中加入tools部分。

pipeline {
    agent none
    environment {
        GOPATH = "${env.WORKSPACE}/"
    }
    tools {
        go 'go1.10'
    }    
    stages {
        stage('build') {
            steps {
                sh "go build"
            }
        }
    }
}

此時,在環境變量中會增加一個GOROOT變量。
4. 設置GOPATH。瞭解Go語言開發的讀者都會知道,編譯時需要設置GOPATH環境變量。直接在environment指令中添加就可以了。

2.6 Python環境搭建

Python環境很容易產生Python版本衝突、第三方庫衝突等問題。所以,Python開發通常會進行工程級別的環境隔離,也就是每個Python工程使用一個Python環境。

在Jenkins環境下,我們使用Pyenv Pipeline插件可以輕鬆地實現。
首先,準備Python基礎環境。

  1. 在Jenkins機器上安裝python、pip、virtualenv。
  • pip:Python的包管理工具。
  • virtualenv:Python中的虛擬環境管理工具。
  1. 安裝Pyenv Pipeline插件。
    然後,在pipeline中使用Pyenv Pipeline插件提供的withPythonEnv方法。
withPythonEnv("/usr/bin/python") {
    sh "python --version"
}

withPythonEnv方法會根據第一個參數——可執行python路徑——在當前工作空間下創建一個virtualenv環境。
withPythonEnv方法的第二個參數是一個閉包。閉包內的代碼就執行在新建的virtualenv環境下。

3. 利用環境變量支持更多的構建工具

不是所有的構建工具都需要安裝相應的Jenkins插件纔可以使用。
平時,開發人員在搭建開發環境時做的就是:首先在機器上安裝好構建工具,然後將這個構建工具所在目錄加入PATH環境變量中。
如果想讓Jenkins支持更多的構建工具,也是同樣的做法:在Jenkins agent上安裝構建工具,並記錄下它的可執行命令的目錄,然後在需要使用此命令的Jenkins pipeline的PATH環境變量中加入該可執行命令的目錄。示例如下:

pipeline {
    agent none
    environment {
        PATH = "/usr/local/customtool/bin:$PATH"
    }
    stages {
        stage('build') {
            steps {
                sh "customtool build"
            }
        }
    }
}

還可以有另一種寫法:

pipeline {
    agent none
    environment {
        CUSTOM_TOOL_HOME = "/usr/local/customtool/bin"
    }
    stages {
        stage('build') {
            steps {
                sh "${CUSTOM_TOOL_HOME}/customtool build"
            }
        }
    }
}

4. 利用tools作用域實現多版本編譯

在實際工作中,有時需要對同一份源碼使用多個版本的編譯器進行編譯。tools指令除了支持pipeline作用域,還支持stage作用域。所以,我們可以在同一個pipeline中實現多版本編譯。代碼如下:

pipeline {
    agent none
    stages {
        stage('build with jdk-10.0.2') {
            tools {
                jdk "jdk-10.0.2"
            }
            steps {
                sh "printenv"
            }
        }
        stage('build with jdk-9.0.4') {
            tools {
                jdk "jdk-9.0.4"
            }
            steps {
                sh "printenv"
            }
        }       
    }
}

在打印出來的日誌中,會發現每個stage下的JAVA_HOME變量的值都不一樣。

參考資料:
[1] 《Jenkins 2.x實戰指南》
[2] https://jenkins.io/zh/doc/book/pipeline/syntax/
[3] https://jenkins.io/zh/doc/pipeline/steps/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章