返回文章列表

Jenkins Pipeline as Code 實踐

本文探討 Jenkins Pipeline as Code 的實踐,涵蓋 Jenkinsfile 基本結構、Scripted 與 Declarative Pipeline 語法、多分支 Pipeline、GitFlow 分支模型、環境變數定義、Post 階段處理、測試驅動開發、以及使用 Jenkins

DevOps CI/CD

Jenkins Pipeline as Code 已成為現代 CI/CD 流程的根本,本文將探討如何利用 Jenkinsfile 建立穩固且可擴充套件的自動化Pipeline。從 Jenkinsfile 的基本結構開始,我們將會比較 Scripted 和 Declarative 兩種 Pipeline 語法,並探討如何定義環境變數、使用 Post 區塊進行後續處理,以及如何結合 GitFlow 分支模型管理程式碼版本。此外,本文還會介紹多分支 Pipeline 的概念,並提供一些測試驅動開發的實踐技巧,包含使用 Jenkins 的重播按鈕和命令列工具進行Pipeline檢查,以提升開發效率和程式碼品質。

使用 Jenkins 實作 Pipeline as Code

Jenkinsfile 的基本結構與階段介紹

Jenkinsfile 是 Jenkins Pipeline 的核心,它以 Groovy 語言編寫,定義了一系列的階段(stages)來自動化 CI/CD 流程。以下是一個基本的 Jenkinsfile 範例:

pipeline {
    agent any
    stages {
        stage('Checkout') {
            steps {
                echo "Pulling the latest changes from the source code repository"
            }
        }
        stage('Quality tests') {
            steps {
                echo "Executing static code analysis"
            }
        }
        stage('Unit tests') {
            steps {
                echo "Running unit tests"
            }
        }
        stage('Security tests') {
            steps {
                echo "Identifying project dependencies and checking for known vulnerabilities"
            }
        }
        stage('Build') {
            steps {
                echo "Compiling source code and building artifact"
            }
        }
        stage('Push') {
            steps {
                echo "Versioning and storing artifact in a remote repository"
            }
        }
        stage('Deploy') {
            steps {
                echo "Deploying artifact to a sandbox/testing environment"
            }
        }
        stage('Acceptance Tests') {
            steps {
                echo "Running smoke and validation tests against the deployed application"
            }
        }
    }
    try {
        // 執行 pipeline
    } catch (err) {
        echo "Handling errors"
    } finally {
        echo "Cleaning up"
    }
}

內容解密:

  1. pipeline {}: 定義了一個 Jenkins Pipeline。
  2. agent any: 表示這個 pipeline 可以在任何可用的 agent 上執行。
  3. stages {}: 定義了 pipeline 中的不同階段。
  4. stage('Stage Name') {}: 定義了一個特定的階段,例如 CheckoutQuality tests 等。
  5. steps {}: 在每個階段中定義了具體的步驟。
  6. try-catch-finally: 用於錯誤處理和資源清理。

Jenkinsfile 的階段詳解

  1. Checkout: 從原始碼倉函式庫中提取最新的變更。
  2. Quality tests: 執行靜態程式碼分析,以衡量程式碼品質並識別潛在問題。
  3. Unit tests: 執行單元測試,並生成程式碼覆寫率報告。
  4. Security tests: 識別專案依賴並檢查是否存在已知漏洞。
  5. Build: 編譯原始碼並構建 artifact(例如 Docker 映像、zip 檔案、Maven JAR 等)。
  6. Push: 將構建好的 artifact 版本化並儲存在遠端倉函式庫中。
  7. Deploy: 將 artifact 佈署到沙箱/測試環境或生產環境。
  8. Acceptance Tests: 對已佈署的應用程式執行煙霧測試和驗證測試。

Pipeline Stage View 外掛

為了更好地視覺化 pipeline 的執行過程,可以安裝 Pipeline Stage View 外掛。它以矩陣形式展示了每次構建的階段狀態,方便追蹤每個階段的進度和日誌。

圖表翻譯: 此圖示展示了 Jenkins Pipeline 的不同階段,從原始碼簽出到驗收測試的整個流程。

Blue Ocean 外掛

Blue Ocean 是 Jenkins 團隊推出的一個現代化使用者介面,提供直觀的 CI/CD pipeline 視覺化和編輯功能。它支援與 Git 和 GitHub 無縫整合,允許使用者透過圖形介面建立和除錯 pipeline。

使用 Blue Ocean,使用者可以:

  • 圖形化建立和編輯 pipeline。
  • 直觀地檢視 pipeline 的執行狀態和日誌。
  • 輕鬆除錯失敗的 pipeline 階段。

Jenkinsfile 與 Pipeline as Code 介紹

在 Jenkins 2 中,Pipeline as Code(PaC)是一個重要的概念,它允許使用者將 CI/CD 流程以程式碼的形式定義和版本控制。本章節將介紹 Jenkinsfile 的基本概念,以及兩種主要的 Pipeline 語法:Scripted Pipeline 和 Declarative Pipeline。

Scripted Pipeline

Scripted Pipeline 是傳統的 Pipeline 編寫方式,使用 Groovy 語言編寫 Jenkinsfile。Pipeline 的步驟被包在 node 區塊中,node 代表 Jenkins 的代理節點(agent)。node 可以透過標籤(label)對映到 Jenkins 叢集中的特定節點。

node('node-label') {
    stage('Checkout') {
        // Git checkout code
    }
    stage('Build') {
        // Build project Docker image
    }
}

#### 內容解密:
此段程式碼定義了一個簡單的 Scripted Pipeline,包含兩個階段:Checkout  Build。`node` 區塊指定了執行 Pipeline 的節點標籤。`stage` 用於劃分邏輯功能單元,將步驟和 Groovy 程式碼分組以實作特定的功能。

Scripted Pipeline 使用嚴格的 Groovy 語法,因為它根據 Groovy 基礎。然而,由於 Groovy 的靈活性對於某些使用者來說可能過於複雜,因此引入了 Declarative Pipeline 以提供更簡單、更具選項的語法。

Declarative Pipeline

Declarative Pipeline 是相對較新的功能(在 Pipeline 2.5 中引入),支援 PaC 方法。它使 Pipeline 程式碼更容易閱讀和編寫,特別是對於新使用者。

Declarative Pipeline 的程式碼寫在 Jenkinsfile 中,可以被提交到版本控制系統(VCS)或原始碼管理(SCM)系統,如 GitHub、GitLab 或 Bitbucket。

pipeline {
    agent {
        label 'workers'
    }
    stages {
        stage('Checkout') {
            steps {
                // Git checkout code
            }
        }
        stage('Build') {
            steps {
                // Build project Docker image
            }
        }
    }
}

#### 內容解密:
 Declarative Pipeline 定義了一個簡單的 CI 流程,包含兩個階段:Checkout  Build。`agent` 部分指定了執行 Pipeline 的節點標籤。`stages` 區塊包含了所有的階段定義,而每個 `stage` 內使用 `steps` 定義具體的執行步驟。

Declarative Pipeline 提供了一種更具限制性的語法,每個 Pipeline 必須使用預定義的區塊屬性或區段,如 agentenvironmentpoststagessteps

Scripted vs Declarative Pipelines

兩種 Pipeline 語法的主要差異在於其結構和語法限制。Scripted Pipeline 提供更大的靈活性,使用 Groovy 語法,可以包含變數、迴圈和條件判斷等。Declarative Pipeline 則提供了一種更簡單、更結構化的方式來定義 Pipeline,但其語法限制較多。

圖表翻譯: 此圖表比較了 Scripted Pipeline 和 Declarative Pipeline 的特點。Scripted Pipeline 使用 Groovy 語法,提供了高度的靈活性,但也增加了複雜性和學習難度。Declarative Pipeline 則採用結構化的語法,易於閱讀和編寫,但其限制性語法使其更適合簡單的流程。

Jenkins Pipeline as Code 詳解

Jenkins Pipeline as Code 是一種將 CI/CD 流程以程式碼形式定義的方法,提供了更大的彈性和可維護性。本章節將探討 Jenkins Pipeline 的基本結構、多分支 Pipeline 的概念,以及如何利用 Jenkinsfile 實作自動化流程。

環境變數定義

在 Jenkins Pipeline 中,environment 區塊用於定義環境變數,這些變數可以在 Pipeline 的不同階段中使用。以下是一個範例:

pipeline {
    environment {
        REGISTRY_CREDENTIALS = credentials('DOCKER_REGISTRY')
        REGISTRY_URL = 'https://registry.domain.com'
    }
    stages {
        stage('Push') {
            steps {
                sh 'docker login $REGISTRY_URL --username $REGISTRY_CREDENTIALS_USR --password $REGISTRY_CREDENTIALS_PSW'
            }
        }
    }
}

內容解密:

  • environment 區塊定義了兩個環境變數:REGISTRY_CREDENTIALSREGISTRY_URL
  • credentials('DOCKER_REGISTRY') 用於取得儲存在 Jenkins 中的 Docker Registry 憑證。
  • REGISTRY_CREDENTIALS_USRREGISTRY_CREDENTIALS_PSW 分別代表憑證的使用者名稱和密碼。
  • stage('Push') 中,使用 sh 步驟執行 Docker 登入命令,利用環境變數進行身份驗證。

Post 階段處理

post 區塊用於在 Pipeline 或階段完成後執行特定的命令或指令碼。以下是一個 Slack 通知的範例:

pipeline {
    post {
        always {
            echo 'Cleaning up workspace'
        }
        success {
            slackSend(color: 'GREEN', message: "${env.JOB_NAME} Successful build")
        }
        failure {
            slackSend(color: 'RED', message: "${env.JOB_NAME} Failed build")
        }
    }
}

內容解密:

  • post 區塊包含多個條件區塊,如 alwayssuccessfailure
  • always 區塊中的指令無論構建狀態如何都會執行,用於清理工作空間。
  • successfailure 區塊分別用於傳送成功或失敗的 Slack 通知,顏色和訊息內容根據構建結果動態調整。

多分支 Pipeline

多分支 Pipeline 是 Jenkins 中的一個強大功能,能夠根據程式碼倉函式庫中的不同分支自動建立和管理 Pipeline。以下是其工作原理:

  1. 自動掃描分支:Jenkins 會掃描指定的程式碼倉函式庫,並為包含 Jenkinsfile 的分支建立對應的 Pipeline。
  2. 獨立的 Pipeline 組態:每個分支可以有自己的 Jenkinsfile,定義不同的構建和佈署流程。
  3. Pull Request 驗證:多分支 Pipeline 可以組態為在合併 Pull Request 前執行預整合測試,確保程式碼品質。

圖表說明

@startuml
skinparam backgroundColor #FEFEFE

title Jenkins Pipeline as Code 實踐

|開發者|
start
:提交程式碼;
:推送到 Git;

|CI 系統|
:觸發建置;
:執行單元測試;
:程式碼品質檢查;

if (測試通過?) then (是)
    :建置容器映像;
    :推送到 Registry;
else (否)
    :通知開發者;
    stop
endif

|CD 系統|
:部署到測試環境;
:執行整合測試;

if (驗證通過?) then (是)
    :部署到生產環境;
    :健康檢查;
    :完成部署;
else (否)
    :回滾變更;
endif

stop

@enduml

圖表翻譯: 此圖示展示了 Jenkins 如何掃描程式碼倉函式庫,並為包含 Jenkinsfile 的分支建立對應的 Pipeline。隨後,Jenkins 執行構建和測試流程,最後根據結果傳送通知。

使用Jenkins進行持續整合的實踐

2.3 探索GitFlow分支模型

在軟體開發過程中,分支管理策略是至關重要的。GitFlow是一種廣泛採用的分支模型,它規範了不同分支的功能與用途,以實作高效的團隊協作。

GitFlow的核心分支

GitFlow主要包含以下幾種分支:

  1. Master分支:代表目前的生產環境程式碼。除非進行熱修復,否則不允許直接對此分支進行提交。可以使用Git標籤為Master分支上的提交標記版本號。

  2. Preprod分支:作為釋出分支,是生產環境的映象。在將新功能從Develop分支合併到Master分支之前,可以在Preprod分支上進行測試。

  3. Develop分支:作為開發整合分支,包含了最新的開發程式碼。

  4. Feature/X分支:用於開發獨立的功能。每個新功能都在自己的分支上進行開發,通常是根據最新的Develop分支建立的。

  5. Hotfix/X分支:當需要在生產環境程式碼中進行修復時,可以建立Hotfix分支,並對Master分支開啟提取請求。此分支根據Master分支。

GitFlow的工作流程

  1. 從Master分支建立Develop分支。
  2. 從Develop分支建立Preprod分支。
  3. 開發者根據Develop分支建立新的Feature分支,完成後開啟提取請求。
  4. Jenkins自動在Feature分支上執行預整合測試,如果測試成功,則標記提交為成功。開發團隊審查變更後,將Feature分支合併到Develop分支,並刪除Feature分支。
  5. Develop分支上的變更會觸發構建,並佈署到沙盒或開發環境。
  6. 當Develop分支合併到Preprod分支時,會觸發Pipeline,將新功能佈署到預生產環境。
  7. 驗證透過後,將Preprod分支合併到Master,並在使用者批准後佈署到生產環境。
  8. 如果在生產環境中發現問題,可以從Master分支建立Hotfix分支。修復完成後,將其合併到Develop和Master分支。

GitFlow的優勢與侷限

GitFlow提供了一個更為邏輯的分支結構和工作流程組織模型,特別是在大型團隊中表現出色。然而,對於較小的專案,它可能會顯得過於複雜。因此,在後續章節中,我們將主要使用三個主要的分支:Master、Preprod和Develop。

2.4 使用Jenkins進行測試驅動開發

使用Jenkinsfile的一個潛在缺點是,當在外部檔案中工作而不是在Jenkins伺服器的環境中工作時,可能更難以提前發現問題。

解決方案

  1. 先在Jenkins伺服器上開發Pipeline專案,然後再轉換為Jenkinsfile。
  2. 使用Blue Ocean模式作為遊樂場,透過現代化的Pipeline編輯器從頭開始設定Jenkinsfile。
  3. 使用宣告式Pipeline檢查工具,在Jenkins外部對Jenkinsfile進行檢查,以提前發現問題。

2.4.1 Jenkins的重播按鈕

Jenkins的重播按鈕允許您在不修改原始Pipeline組態的情況下,對Jenkinsfile進行修改並重新執行作業。這對於快速迭代和原型設計非常有用。

// 以下是一個簡單的Jenkinsfile範例
pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                echo 'Building...'
                // 在此處新增構建步驟
            }
        }
        stage('Test') {
            steps {
                echo 'Testing...'
                // 在此處新增測試步驟
            }
        }
    }
}

#### 內容解密:
Jenkinsfile定義了一個簡單的Pipeline,包含兩個階段:構建和測試。在每個階段中,目前僅輸出簡單的資訊,實際應用中需要替換為具體的構建和測試步驟。

2.4.2 命令列Pipeline檢查工具

對於高階使用者,可以使用Jenkins RESTful API來驗證Jenkinsfile的語法。這需要傳送HTTP/HTTPS POST請求,並在請求中包含必要的引數。

# 使用curl命令驗證Jenkinsfile語法
curl -X POST -F "jenkinsfile=<Jenkinsfile" http://your-jenkins-server:8080/pipeline-model-converter/validate

#### 內容解密:
此命令使用curl工具向Jenkins伺服器傳送POST請求,以驗證Jenkinsfile的語法。需要替換`http://your-jenkins-server:8080`為實際的Jenkins伺服器地址。