10分鐘搞定讓你困惑的 Jenkins 環境變量

前言

Jenkins, DevOps 技術棧的核心之一,CI/CD 離不開編寫 Pipeline 腳本,上手 Jenkins ,簡單查一下文檔,你就應該不會被 agent,stages,step 這類關鍵詞弄懵,也能很快構建出 pipeline 的骨架

但是當向骨架中填充內容的時候,尤其如何利用環境變量(系統內置 | 自定義),多數人都會變得比較混亂,浪費很多時間,本文就幫助大家快速通關環境變量

準備

如果你想一邊閱讀本文,一邊實踐,但是沒有 Jenkins 服務可用,又想快速嘗試,可以應用 Docker 一個命令快速搭建 Jenkins 服務

docker container run --rm -p 8080:8080 -p 50000:50000 --name=jenkins -v $(pwd):/var/jenkins_home jenkins/jenkins

2021 年了,本地沒有 Docker 說不過去了,過來瞧瞧 Docker 系列是否入得了你的法眼?

打開瀏覽器輸入:localhost:8080

  1. 找到終端的臨時密碼登陸
  2. 安裝推薦的依賴
  3. 創建新的 Pipeline 類型的 Item
  4. 點擊左側 Config,然後在頁面底部 Pipeline 部分輸入我們接下來寫的腳本進行測試就好了

就是這麼簡單.....

認識 Jenkins 環境變量

Jenkins 環境變量就是通過 env 關鍵字暴露出來的全局變量,可以在 Jenkins 文件的任何位置使用

其實和你使用的編程語言中的全局變量沒有實質差別

查看 Jenkins 系統內置環境變量

Jenkins 在系統內置了很多環境變量方便我們快速使用,查看起來有兩種方式:

方式一:

直接在瀏覽器中訪問 ${YOUR_JENKINS_HOST}/env-vars.html 頁面就可以,比如 http://localhost:8080/env-vars.html ,每個變量的用途寫的都很清楚

方式二

通過執行 printenv shell 命令來獲取:

pipeline {
    agent any

    stages {
        stage("Env Variables") {
            steps {
                sh "printenv"
            }
        }
    }
}

直接 Save - Build, 在終端 log 中你會看到相應的環境變量,並且可以快速看到他們當前的值

通常這兩種方式可以結合使用

讀取環境變量

上面我們說了 env 是環境變量的關鍵字,但是讀取 Jenkins 內置的這些環境變量,env 關鍵字是可有可無, 但不能沒了底褲,都要使用 ${xxx} 包圍起來。以 BUILD_NUMBER 這個內置環境變量舉例來說明就是這樣滴:

如果你在 Jenkins 文件中使用 shell 命令,使用這些內置環境變量甚至可以不用 {}, 來看一下:

pipeline {
    agent any

    stages {
        stage("Read Env Variables") {
            steps {
                echo "帶 env 的讀取方式:${env.BUILD_NUMBER}"
                echo "不帶 env 的讀取方式:${BUILD_NUMBER}"
                sh 'echo "shell 中讀取方式 $BUILD_NUMBER"'
            }
        }
    }
}

可以看到結果是一樣一樣滴,不管有幾種,記住第一種最穩妥

內置的環境變量雖好,但也不能完全滿足我們自定義的 pipeline 的執行邏輯,所以我們也得知道如何定義以及使用自定義環境變量

自定義 Jenkins 環境變量

Jenkins pipeline 分聲明式(Declarative)和 腳本式(imperative)寫法,相應的環境變量定義方式也略有不同,歸納起來有三種方式:

還是看個實際例子吧:

pipeline {
    agent any

    environment {
        FOO = "bar"
    }

    stages {
        stage("Custom Env Variables") {
            environment {
                NAME = "RGYB"
            }

            steps {
                echo "FOO = ${env.FOO}"
                echo "NAME = ${env.NAME}"

                script {
                    env.SCRIPT_VARIABLE = "Thumb Up"
                }

                echo "SCRIPT_VARIABLE = ${env.SCRIPT_VARIABLE}"

                withEnv(["WITH_ENV_VAR=Come On"]) {
                    echo "WITH_ENV_VAR = ${env.WITH_ENV_VAR}"
                }
            }
        }
    }
}

來看運行結果:

注意:withEnv(["WITH_ENV_VAR=Come On"]) {} 這裏的 = 號兩側不能有空格,必須是 key=value 的形式

一個完整的 pipeline 通常會有很多個 stage,環境變量在不同的 stage 有不同的值是很常見的,知道如何設置以及讀取環境變量後,我們還得知道如何重寫環境變量

重寫 Jenkins 環境變量

Jenkins 讓人相對困惑最多的地方就是重寫環境變量,但是隻要記住下面這三條規則,就可以搞定一切了

  1. withEnv(["WITH_ENV_VAR=Come On"]) {} 內置函數的這種寫法,可以重寫任意環境變量
  2. 定義在 environment {} 的環境變量不能被腳本式定義的環境變量(env.key="value")重寫
  3. 腳本式環境變量只能重寫腳本式環境變量

這三點是硬規則,沒涵蓋在這 3 點規則之內的也就是被允許的了

三條規則就有點讓人頭大了,農夫選豆種,舉例爲證吧

pipeline {
    agent any

    environment {
        FOO = "你當像鳥飛往你的山"
        NAME = "Tan"
    }

    stages {
        stage("Env Variables") {
            environment {
              	// 會重寫第 6 行 變量
                NAME = "RGYB" 
              	// 會重寫系統內置的環境變量 BUILD_NUMBER
                BUILD_NUMBER = "10" 
            }

            steps {
              	// 應該打印出 "FOO = 你當像鳥飛往你的山"
                echo "FOO = ${env.FOO}" 
              	// 應該打印出 "NAME = RGYB"
                echo "NAME = ${env.NAME}" 
              	// 應該打印出 "BUILD_NUMBER = 10"
                echo "BUILD_NUMBER =  ${env.BUILD_NUMBER}" 

                script {
                  	// 腳本式創建一個環境變量
                    env.SCRIPT_VARIABLE = "1" 
                }
            }
        }

        stage("Override Variables") {
            steps {
                script {
                  	// 這裏的 FOO 不會被重寫,違背 Rule No.2
                    env.FOO = "Tara"
                  	// SCRIPT_VARIABLE 變量會被重寫,符合 Rule No.3
                    env.SCRIPT_VARIABLE = "2" 
                }

              	// FOO 在第 37 行重寫失敗,還會打印出 "FOO = 你當像鳥飛往你的山"
                echo "FOO = ${env.FOO}" 
              	// 會打印出 "SCRIPT_VARIABLE = 2"
                echo "SCRIPT_VARIABLE = ${env.SCRIPT_VARIABLE}" 

              	// FOO 會被重寫,符合 Rule No.1
                withEnv(["FOO=Educated"]) { 
                  	// 應該打印 "FOO = Educated"
                    echo "FOO = ${env.FOO}" 
                }

              	// 道理同上
                withEnv(["BUILD_NUMBER=15"]) {
                  	// 應該打印出 "BUILD_NUMBER = 15"
                    echo "BUILD_NUMBER = ${env.BUILD_NUMBER}"
                }
            }
        }
    }
}

來驗證一下結果吧

看到這,基本的設置應該就沒有什麼問題了,相信你也發現了,Jenkins 設置環境變量和編程語言的那種設置環境變量還是略有不同的,後者可以將變量賦值爲對象,但 Jenkins 就不行,因爲在 Jenkins 文件中,所有設置的值都會被當成 String, 難道沒辦法應用 Boolean 值嗎?

Jenkins 中使用 Boolean 值

如果設置一個變量爲 false ,Jenkins 就會將其轉換爲 "false", 如果想使用 Boolean 來做條件判斷,必須要調用 toBoolean() 方法做轉換

pipeline {
    agent any

    environment {
        IS_BOOLEAN = false
    }

    stages {
        stage("Env Variables") {
            steps {
                script {
                  	// Hello 會被打印出來,因爲非空字符串都會被認爲是 Boolean.True
                    if (env.IS_BOOLEAN) {
                        echo "Hello"
                    }

                  	// 真正的 Boolean 比較
                    if (env.IS_BOOLEAN.toBoolean() == false) {
                        echo "日拱一兵"
                    }
                  
                  	// 真正的 Boolean 
                    if (!env.IS_BOOLEAN.toBoolean()) {
                        echo "RGYB"
                    }
                }
            }
        }
    }
}

來看運行結果:

如果你寫過 Pipeline,你一定會知道,寫 Pipeline 是離不開寫 shell 的,有些時候,需要將 shell 的執行結果賦值給環境變量,Jenkins 也有方法支持

Shell 結果賦值給環境變量

實現這種方式很簡單,只需要記住一個格式:sh(script: 'cmd', returnStdout:true)

pipeline {
    agent any

    environment {
      	// 使用 trim() 去掉結果中的空格
        LS_RESULT = "${sh(script:'ls -lah', returnStdout: true).trim()}"
    }

    stages {
        stage("Env Variables") {
            steps {
                echo "LS_RESULT = ${env.LS_RESULT}"
            }
        }
    }
}

總結

關於 Jenkins 環境變量,瞭解這些基本上就滿足絕大多數應用場景了,當再遇到環境變量問題時,可以回過來翻看一下了,有解決的困惑嗎?

個人博客:https://dayarch.top
加我微信好友, 進羣娛樂學習交流,備註「進羣」

歡迎持續關注公衆號:「日拱一兵」

  • 前沿 Java 技術乾貨分享
  • 高效工具彙總 | 回覆「工具」
  • 面試問題分析與解答
  • 技術資料領取 | 回覆「資料」

以讀偵探小說思維輕鬆趣味學習 Java 技術棧相關知識,本着將複雜問題簡單化,抽象問題具體化和圖形化原則逐步分解技術問題,技術持續更新,請持續關注......


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