自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

用代碼實現(xiàn)流水線部署,像詩一般優(yōu)雅

開發(fā) 項目管理
通過本篇的實戰(zhàn)內(nèi)容,我們學習到了通過編寫 pipeline 代碼來實現(xiàn)部署后端項目。推薦大家都用 pipeline 來部署項目,好處是更加靈活。

你好,我是悟空。

本文目錄如下:

圖片圖片

這次我們要接著上面的話題聊下如何通過通過編寫代碼的方式實現(xiàn)自動化部署 Java 項目。

而用代碼方式其實就是使用  Jenkins 強大的 pipeline 功能來實現(xiàn)的。

通過本篇你可以學習到如下內(nèi)容:

  • Pipeline 的概念、優(yōu)點、缺點。
  • 實戰(zhàn):通過編寫 pipeline 來部署一個完整的后端項目。
  • pipeline 傳參的合理利用。
  • 多選插件、遠程傳輸文件、遠程執(zhí)行命令的使用。

一、Pipeline

1.1 流水線

要了解什么是Pipeline,就必須知道什么是流水線。類似于食品工廠包裝食品,食品被放到傳送帶上,經(jīng)過一系列操作后,包裝完成,這種工程就是流水線工程。

1.2 Pipeline 是什么

在自動化部署中,開發(fā)完成的代碼經(jīng)過一系列順序操作后被部署完成,這個就是部署過程中的流水線,我們通常稱作 pipeline。

之前我們的部署步驟都是通過在 Jenkins 的 UI 界面上配置出來的,但其實 Jenkisn 2.x 版本已經(jīng)可以支持編寫代碼的方式來啟動自動化部署了,通過“代碼”來描述部署流水線。

Jenkins pipeline其實就是基于一種聲明式語言,用于描述整條流水線是如何進行的。流水線的內(nèi)容包括執(zhí)行編譯、打包、測試、輸出測試報告等步驟。

1.3 為什么要用 Pipeline

Pipeline 通過代碼來實現(xiàn),其實就具有很多代碼的優(yōu)勢了,比如:

  • 支持傳參:可以在 Pipeline 代碼里面配置用戶要輸入或選擇的參數(shù),這個功能真的太棒了。比如可以傳 Gitlab 分支名、部署哪個服務等。
  • 更好地版本化:將 pipeline 代碼提交到軟件版本庫中進行版本控制。
  • 更好地協(xié)作:pipeline 的每次修改對所有人都是可見的。除此之外,還可以對pipeline進行代碼審查
  • 更好的重用性:手動操作沒法重用,但是代碼可以重用。

當然 pipeline 的缺點也是有的:

  • 學習成本高:需要熟悉 pipeline 的語法規(guī)則。
  • 復雜:代碼不夠直觀,編寫的邏輯可能很復雜,容易出錯。

1.4 如何使用 Pipeline

在之前的文章中,我是通過創(chuàng)建一個自由風格的項目來實現(xiàn)自動化部署,其實還可以通過創(chuàng)建一個Pipeline 來實現(xiàn),如下圖所示:

創(chuàng)建 Pipeline 任務創(chuàng)建 Pipeline 任務

然后就可以在配置流水線的地方編寫代碼了。如下圖所示:

編寫流水線代碼編寫流水線代碼

1.5 Pipeline 基礎結構

Pipeline 基礎結構如下所示:

pipeline{
//指定運行此流水線的節(jié)點
agent any
//流水線的階段
stages{
    //階段1 獲取代碼
    stage("CheckOut") {
        steps {
            script {
                echo "獲取代碼"
            }
        }
    }
}
  • pipeline 部分:代表整條流水線,包含整條流水線的邏輯。
  • stage 部分:代表流水線的某個階段。每個階段都必須有名稱,本例中,"CheckOut" 就是此階段的名稱。
  • stages 部分:流水線中多個stage的容器。stages 部分至少包含一個 stage。steps 部分:代表階段中的一個或多個具體步驟(step)的容器。steps 部分至少包含一個步驟,本例中,echo就是一個步驟。在一個 stage 中有且只有一個steps。
  • agent 部分:指定流水線的執(zhí)行位置(Jenkins agent)。流水線中的每個階段都必須在某個地方(物理機、虛擬機或Docker容器)執(zhí)行,agent 部分即指定具體在哪里執(zhí)行。

以上每一個部分都不能少,否則 Jenkins 會報錯。

二、部署思路

2.1 Jenkins 承擔的角色

Jenkins 承擔的角色如下圖所示:

圖片圖片

Jenkins 打包部署原理圖

  • (1)Jenkins 部署在一臺服務器上,然后安裝了很多必備的 Jenkins 插件。比如拉取 Gitlab 倉庫代碼的插件、遠程執(zhí)行命令和拷貝文件的插件。
  • (2)Jenkins 開始運行一個任務時,通過 Git 插件從 Gitlab 倉庫拉取代碼到本地目錄。
  • (3)Jenkins 通過 JDK 和 Maven 工具對 Java 代碼進行打包部署。
  • (4)Jenkins 將 JAR 包拷貝到遠程服務器的固定目錄下。
  • (5)Jenkins 通過 SSH 插件執(zhí)行遠程命令,將包進行備份操作。
  • (6)Jenkins 通過執(zhí)行遠程命令,更新 JAR 包。
  • (7)Jenkins 通過執(zhí)行遠程命令,重啟容器。

2.2 通過流水線來部署項目

我們項目是 Java 項目,所以通過流水線來部署項目的步驟如下圖所示:

流水線部署步驟流水線部署步驟

三、獲取 Gitlab 分支代碼

Pipeline 的強大之處是可以支持傳參以及獲取參數(shù),為了讓用戶可以選擇獲取不同的分支代碼,我在 pipeline 代碼中配置了一個參數(shù):獲取指定的 Gitlab 分支代碼。

3.1 Gitlab 分支配置

在 流水線代碼中添加 parameters 節(jié)點,指定類型為 string,配置相關的屬性。

pipeline {  
    parameters {  
        string (
            name: 'GIT_BRANCH', // 參數(shù)名,后面 steps 中會用到
            defaultValue: 'dev-01.30', // 默認值,會顯示在界面上,用戶可以改。
            description: '請選擇部署的分支' // 說明
        )
    }
    // 其他代碼
    ...
}

通過參數(shù)部分,定義了一個名為GIT_BRANCH的參數(shù),它允許用戶在構建過程中選擇要構建的分支。默認情況下,分支被設置為dev-01.30,用戶可以選擇不同的分支。

在腳本中,這個參數(shù)可以通過params.GIT_BRANCH 獲取到。

保存配置后,需要先運行一次這個項目才能看到參數(shù)配置。如下圖所示:右邊就是參數(shù)配置。

Build with Parameters

3.2 配置環(huán)境參數(shù)

接著我們還需要定義一些常用的環(huán)境變量信息,比如 Gitlab 的倉庫地址,代碼如下所示:

pipeline {
    parameters {
      // 配置信息
      ...
    }
    // 環(huán)境變量:定義 GitLab 倉庫的 URL 和分支  
    environment {  
        GIT_URL = 'https://xxx/xxx.git'
         
    }
    // 其他代碼
    ...
}

environment 節(jié)點為環(huán)境變量信息,GIT_URL 變量代表 Gitlab 的倉庫地址。在腳本中,這個變量可以通過${GIT_URL}使用。

3.3 獲取 Gitlab 分支代碼

接下來我們來看下如何在 pipeline 中添加一個獲取 gitlab 倉庫代碼的步驟。

pipeline {  
    agent any  
    parameters {  
        string(
            name: 'GIT_BRANCH', 
            defaultValue: 'dev-01.30', 
            description: '請選擇部署的分支')
    }
    // 定義 GitLab 倉庫的 URL 和分支  
    environment {  
        GIT_URL = 'https://XXX/xxx.git'
    }  
     stages {  
        stage('獲取最新代碼') {  
            steps {  
                script {  
                    // 使用 params 對象獲取參數(shù)值  
                    def branchName = params.GIT_BRANCH  
                    echo "Building branch: ${branchName}"  

                    // 使用 git 插件檢出倉庫的特定分支  
                    checkout([  
                        $class: 'GitSCM',  
                        branches: [[name: "${branchName}"]],  
                        doGenerateSubmoduleConfigurations: false,  
                        extensions: [],  
                        submoduleCfg: [],  
                        userRemoteConfigs: [[  
                            credentialsId: '211583e9-8ee1-4fa2-9edd-d43a963de8f2', // 在 Jenkins 憑據(jù)中定義的 GitLab 憑據(jù) ID  
                            url: "${GIT_URL}"  
                        ]]  
                    ])  
                }  
            }  
        }
    }
}
  1. 參數(shù)定義:通過參數(shù)部分,定義了一個名為GIT_BRANCH的參數(shù),它允許用戶在構建過程中選擇要構建的分支。默認情況下,分支被設置為dev-01.30,用戶可以選擇不同的分支。
  2. 環(huán)境變量定義:在環(huán)境部分,設置了GIT_URL變量,它是GitLab倉庫的URL。在腳本中,這個變量可以通過${GIT_URL}使用。
  3. 階段定義:在stages部分,定義了一個名為"獲取最新代碼"的階段。
  4. 步驟定義:在階段內(nèi),使用了script塊來執(zhí)行Groovy腳本。這個腳本首先獲取了GIT_BRANCH參數(shù)的值,然后使用Jenkins的Git插件檢出指定的分支。
  5. 檢出代碼:checkout步驟是用來從GitLab倉庫檢出代碼的關鍵部分。它使用了GitSCM類,并傳遞了相應的參數(shù),包括分支名、GitLab憑據(jù)等。

注意:獲取分支的憑證是一個 ID,這個憑證信息是在 Jenkins 系統(tǒng)配置中加的??梢园凑杖缦马撁媛窂教砑討{證:Dashboard->Manage Jenkins->Credentials->System->Add domain。也可以通過如下 URL 訪問

http://<你的服務器 IP>:8080/manage/credentials/store/system/

圖片圖片

3.4  測試 pipeline 執(zhí)行

我們可以運行一下這個項目來測試 pipeline 代碼。運行結果如下圖所示,可以看到右側的階段視圖,整體耗時和每個步驟的耗時,以及每個步驟的成功與否都顯示出來了,非常直觀。

圖片圖片

四、編譯代碼

本篇主要講解的是部署 Java 項目,所以編譯項目也是采用 Maven 打包的方式。在 pipeline 腳本中執(zhí)行 mvn 打包命令即可。

stage('編譯代碼') {  
   steps {  
     script {  
       echo "--------------- 步驟:開始編譯 --------------- "
       bat 'mvn clean package'
       echo "--------------- 步驟:編譯完成 --------------- "
     }
  }  
}

核心代碼:bat 'mvn clean package'

因為我的 Jenkins 是部署在 Windows 機器上,所以執(zhí)行命令用的 windows 自帶的 bat 工具來執(zhí)行的。

關于 maven 工具的配置可以看之前寫的第二篇內(nèi)容:

喝杯咖啡,一鍵部署完成?。ńㄗh收藏)

五、上傳 JAR 包

編譯完成后,就可以將 Jenkins 工作空間的 JAR 包上傳到服務器的 temp 目錄下。

如果你想部署指定的某些微服務,可以通過傳參的方式來上傳和更新指定的微服務。原理圖如下所示:

圖片圖片

5.1 支持勾選多個服務

為了實現(xiàn)可以選擇部署哪些微服務,需要安裝一個多選插件:Extended Choice Parameter。

圖片圖片

Extended Choice Parameter  插件

接下來是編寫的參數(shù)配置代碼:

parameters {
    extendedChoice ( 
        defaultValue: 'All', 
        description: '需要部署的微服務', 
        multiSelectDelimiter: ',', 
        name: 'SERVICE_NAME', 
        quoteValue: false, 
        saveJSONParameterToFile: false, 
        type: 'PT_CHECKBOX', 
        value:'All, passjava-account, passjava-file',
        visibleItemCount: 10
    )
}
  • defaultValue: 參數(shù)的默認值。在這里,默認值為 'All'。
  • description: 參數(shù)的描述或提示。這里描述為 '需要部署的微服務',表示選擇需要部署的微服務。
  • multiSelectDelimiter: 多選時的分隔符。這里設置為 ',',表示使用逗號作為分隔符。
  • name: 參數(shù)的名稱。這里是 'SERVICE_NAME'。
  • quoteValue: 確定是否對值加上引號。這里設置為 false,表示不加引號。
  • saveJSONParameterToFile: 是否將 JSON 參數(shù)保存到文件。
  • type: 參數(shù)的類型。這里是 'PT_CHECKBOX',表示復選框類型。
  • value: 可選的值列表。在這里,可選的值有 'All'、'passjava-account'、'passjava-file'。
  • visibleItemCount: 可見的選項數(shù)量。這里設置為 10。

配置保存后并運行一次后,就可以在 pipeline 中看到配置選項:

圖片圖片

實現(xiàn)的效果如下圖右下角所示,可以支持多選。

圖片圖片

5.2 上傳 JAR 包

上傳需要使用 sshPublisher 插件,在第二篇文章中已介紹了。

下面上傳代碼的作用是遍歷 filesToCopy 列表中的文件,然后通過 SSH 將這些文件上傳到遠程服務器的指定目錄中。

filesToCopy.eachWithIndex { file, index -> 
    echo "開始上傳 JAR 包 ${file} ..."
    sshPublisher(
        failOnError: true,
        publishers: [
            sshPublisherDesc(
                configName: "${SSH_URL}",
                verbose: true,
                transfers: [
                    sshTransfer(
                        execCommand: '', 
                        execTimeout: 120000, 
                        flatten: false, 
                        makeEmptyDirs: false, 
                        noDefaultExcludes: false, 
                        patternSeparator: '[, ]+', 
                        remoteDirectory: 'apps/temp/', 
                        remoteDirectorySDF: false, 
                        removePrefix: removePrefixs[index], 
                        sourceFiles: file
                    )
                ]
            )
        ]
    )
    echo "完成上傳 JAR 包 ${file}"
}
  1. filesToCopy.eachWithIndex { file, index -> ... }: 這是一個 Groovy 中的迭代循環(huán),對列表 filesToCopy 中的每個文件執(zhí)行相應的操作。file 是當前迭代的文件,index 是該文件在列表中的索引。
  2. echo "開始上傳 JAR 包 ${file} ...": 這是一個打印語句,用于輸出日志,顯示當前正在上傳的 JAR 包的文件名。
  3. sshPublisher { ... }: 這是一個 SSH 發(fā)布器,用于通過 SSH 連接到遠程服務器并執(zhí)行相應的操作。
  4. failOnError: true: 如果 SSH 連接或傳輸過程中出現(xiàn)錯誤,將會終止流水線執(zhí)行。
  5. configName: "${SSH_URL}": 這是 SSH 配置的名稱,${SSH_URL} 是一個變量,指定 SSH 連接的配置信息。
  6. transfers: [sshTransfer { ... }]: 這是 SSH 傳輸操作的列表,包含了將要執(zhí)行的文件傳輸任務。
  7. remoteDirectory: 'apps/temp/': 遠程服務器上的目標目錄,這里設置為 apps/temp/,表示將文件上傳到遠程服務器的 apps/temp/ 目錄下。
  8. removePrefix: removePrefixs[index]: 這是一個用于移除文件路徑前綴的設置,根據(jù)當前文件在列表中的索引,從相應的 removePrefixs 數(shù)組中獲取相應的前綴進行移除。
  9. sourceFiles: file: 要傳輸?shù)脑次募?,即當前迭代的文件?/li>
  10. echo "完成上傳 JAR 包 ${file}": 這是另一個打印語句,用于輸出日志,表示當前文件的上傳已經(jīng)完成。

filesToCopy 就是通過用戶勾選的服務名轉成了對應的本地 JAR 包路徑。

switch(service) {
    case 'passjava-account':
        filesToCopy.add("passjava-modules/passjava-module-account/passjava-module-account-core/target/passjava-account.jar")
        removePrefixs.add("passjava-modules/passjava-module-account/passjava-module-account-core/target")
        break
     case ...  
}

六、備份服務器 JAR 包

備份的思路:逐個處理 serviceNameList 中的服務名稱,然后通過 SSH 連接到遠程服務器執(zhí)行備份操作。serviceNameList 就是用戶勾選的服務名的集合。原理圖如下所示:

備份服務器 JAR 包備份服務器 JAR 包

核心代碼如下:

serviceNameList.each { service -> 
  echo "開始備份微服務 ${service} 包"
  sshPublisher(
      failOnError: true,
      publishers: [
          sshPublisherDesc(
              configName: "${SSH_URL}",
              verbose: true,
              transfers: [
                  sshTransfer(
                      execCommand: "mkdir -p /nfs-data/wukong/apps/bak/${timestamp} && cd /nfs-data/wukong/apps && mv ${service}.jar ./bak/${timestamp}/${service}-${timestamp}.jar"
                  )
              ]
          )
      ]
  )
  1. serviceNameList.each { service -> ... }: 這是一個 Groovy 中的迭代循環(huán),對列表 serviceNameList 中的每個服務名稱執(zhí)行備份操作。service 是當前迭代的服務名稱。
  2. echo "開始備份微服務 ${service} 包": 這是一個打印語句,用于輸出日志,顯示當前正在備份的微服務的名稱。
  3. sshPublisher { ... }: 這是一個 SSH 發(fā)布器,用于通過 SSH 連接到遠程服務器并執(zhí)行相應的操作。
  4. failOnError: true: 如果 SSH 連接或執(zhí)行過程中出現(xiàn)錯誤,將會終止流水線執(zhí)行。
  5. configName: "${SSH_URL}": 這是 SSH 配置的名稱,${SSH_URL} 是一個變量,用于指定 SSH 連接的配置信息。
  6. transfers: [sshTransfer { ... }]: 這是 SSH 傳輸操作的列表,包含了將要執(zhí)行的文件傳輸任務。
  7. execCommand: "...": 這是要在遠程服務器上執(zhí)行的命令。在這里,使用了 mkdir 命令創(chuàng)建備份目錄,然后將當前服務的 JAR 包移動到備份目錄下,并加上時間戳作為文件名,以實現(xiàn)備份。

這段代碼的作用是遍歷 serviceNameList 列表中的服務名稱,然后通過 SSH 連接到遠程服務器執(zhí)行備份操作,將每個服務的 JAR 包移動到指定的備份目錄,并根據(jù)時間戳進行命名。

七、更新 JAR 包

更新最新的 JAR 包就是將最新的 JAR 包放到對應的容器映射的目錄,后面重啟容器的時候,就能用最新的 JAR 包啟動了。原理圖如下所示:

更新 JAR 包更新 JAR 包

serviceNameList.eachWithIndex { service, index -> 
    echo "開始更新第 ${index + 1} 個 JAR 包,/nfs-data/wukong/apps/temp/${service}.jar ..."

        sshPublisher(
            failOnError: true,
            publishers: [
                sshPublisherDesc(
                    configName: "${SSH_URL}",
                    verbose: true,
                    transfers: [
                        sshTransfer(
                            execCommand: "cd /nfs-data/wukong/apps && mv -f ./temp/${service}.jar ${service}.jar",
                            execTimeout: 120000
                        )
                    ]
                )
            ]
        )

    echo "----- 完成更新 JAR 包 -----"
}
  1. serviceNameList.eachWithIndex { service, index -> ... }: 這是一個 Groovy 中的迭代循環(huán),對列表 serviceNameList 中的每個服務名稱執(zhí)行更新操作。service 是當前迭代的服務名稱,index 是該服務在列表中的索引。
  2. echo "開始更新第 ${index + 1} 個 JAR 包,/nfs-data/wukong/apps/temp/${service}.jar ...": 這是一個打印語句,用于輸出日志,顯示當前正在更新的 JAR 包的名稱及路徑。
  3. sshPublisher { ... }: 這是一個 SSH 發(fā)布器,用于通過 SSH 連接到遠程服務器并執(zhí)行相應的操作。
  4. failOnError: true: 如果 SSH 連接或執(zhí)行過程中出現(xiàn)錯誤,將會終止流水線執(zhí)行。
  5. configName: "${SSH_URL}": 這是 SSH 配置的名稱,${SSH_URL} 是一個變量,用于指定 SSH 連接的配置信息。
  6. transfers: [sshTransfer { ... }]: 這是 SSH 傳輸操作的列表,包含了將要執(zhí)行的文件傳輸任務。
  7. execCommand: "cd /nfs-data/wukong/apps && mv -f ./temp/${service}.jar ${service}.jar": 這是要在遠程服務器上執(zhí)行的命令。在這里,使用 mv 命令將位于 /nfs-data/wukong/apps/temp/ 目錄下的 ${service}.jar 移動到 /nfs-data/wukong/apps/ 目錄,并覆蓋同名的文件。
  8. execTimeout: 120000: 這是執(zhí)行命令的超時時間,單位是毫秒。在這里,設置為 120000,即 120 秒。
  9. echo "----- 完成更新 JAR 包 -----": 這是另一個打印語句,用于輸出日志,表示當前 JAR 包的更新操作已經(jīng)完成。

這段代碼的作用是遍歷 serviceNameList 列表中的服務名稱,然后通過 SSH 連接到遠程服務器執(zhí)行更新操作,將每個服務在 /nfs-data/wukong/apps/temp/ 目錄下的 JAR 包移動到對應的位置,完成更新。

八、啟動多個服務

啟動服務就是將 docker swarm 管理的服務重啟下,原理圖如下所示:

圖片圖片

后端項目使用 Docker Swarm 部署的,重啟服務的命令如下:

sudo docker service update --force <服務名>

我們可以編寫遠程執(zhí)行這行命令的代碼,pipeline 核心代碼如下:

serviceNameList.eachWithIndex { service, index -> 
    echo "開始重啟第 ${index + 1} 個微服務,${service} ..."
    sshPublisher(
        failOnError: true,
        publishers: [
            sshPublisherDesc(
                configName: "${SSH_URL}",
                verbose: true,
                transfers: [
                    sshTransfer(
                        execCommand: "sudo docker service update --force ${commands[service]}",
                        execTimeout: 120000
                    )
                ]
            )
        ]
    )
    echo "----- 完成重啟微服務 -----"
}

這段代碼的作用是遍歷 serviceNameList 列表中的服務名稱,然后通過 SSH 連接到遠程服務器執(zhí)行重啟操作,完成微服務的重啟。

最后整個執(zhí)行結果如下圖所示:總共耗時 3min41s。

圖片圖片

九、總結

通過本篇的實戰(zhàn)內(nèi)容,我們學習到了通過編寫 pipeline 代碼來實現(xiàn)部署后端項目。推薦大家都用 pipeline 來部署項目,好處是更加靈活。

另外本篇還沒有對 Jenkins pipeline 的版本管理,我們其實可以將 pipeline 代碼作為一個文件上傳到 Gitlab,然后通過 Jenkins 拉取最新的 jenkins pipeline 文件來執(zhí)行部署,這樣更便于管理 pipeline 文件。

責任編輯:武曉燕 來源: 悟空聊架構
相關推薦

2017-03-02 14:12:13

流水線代碼Clojure

2022-01-26 08:12:42

Jenkins開源流水線

2019-11-07 09:00:39

Jenkins流水線開源

2021-06-18 05:48:02

Tekton DevopsKubernetes

2022-07-18 06:05:28

Gitlab流水線

2017-02-28 16:00:45

DevOpsMarkdownreST

2023-05-10 15:08:00

Pipeline設計模式

2013-06-06 09:31:52

2017-02-28 15:40:30

Docker流水線Azure

2021-11-08 07:41:16

Go流水線編程

2024-01-07 12:47:35

Golang流水線設計模式

2021-04-13 06:15:37

開源部署流水線Jenkins

2017-03-15 10:08:26

軟件開發(fā)流水線

2021-06-26 14:22:34

Tekton流水線Kubernetes

2021-04-29 08:55:54

GitLabDevOps項目

2025-04-22 08:24:38

2023-08-18 10:24:52

GitLabCI 流水線

2017-02-14 21:00:33

大數(shù)據(jù)機器學習廣告檢測

2020-10-25 11:28:12

開源端到端流水線

2021-06-28 06:32:46

Tekton Kubernetes Clone
點贊
收藏

51CTO技術棧公眾號