目錄

  • 簡介
    • 持續集成
    • 持續部署
  • Gitlab CICD
    • 如何使用 Gitlab CI/CD
    • CICD 工作流
  • .gitlab-ci.yml 文件結構
    • stages
    • variables
    • before_script
    • test_stage
      • stage
      • script
      • artifacts
      • allow_failure
    • build_stage
      • when
      • only
    • deploy_stage

簡介

CICD 是 持續集成(Continuous Integration)和持續部署(Continuous Deployment)簡稱。指在開發過程中自動執行一系列腳本來減低開發引入 bug 的概率,在新代碼從開發到部署的過程中,盡量減少人工的介入。

持續集成

持續集成指在和向遠程倉庫 push 代碼后,在這次提交合并入主分支前進行一系列測試,構建等流程。假設現在有個應用的代碼存儲在 gitlab 上,每天開發者都 push 很多次提交,針對每次 push,你可以創建一系列腳本進行自動測試,降低往應用里引入錯誤的概率。這就是持續集成,它可應用在包括開發分支在內的多個分支上。

持續部署

持續部署在持續集成的基礎上更進一步,指將推送指倉庫默認分支的部署至產品環境。如果這部分需要手動觸發,這就是一個持續交付(Continuous Delivery)環節。

Gitlab CICD

Gitlab 內置了 CICD 工具,不需要使用第三方工具。

如何使用 Gitlab CICD

使用 Gitlab 的 CICD ,只需要在 Gitlab 的倉庫的根目錄中添加 .gitlab-ci.yml 文件。

這個文件中,可以定義CICD 的各個環節,配置每個環節執行的命令,觸發方式等。這個配置文件其實就是按照 YAML 規定了一些結構的 shell 腳本,里面的命令會在符合條件時逐一執行。一旦在倉庫中添加這個文件,Gitlab 會檢測到它并用名為 Gitlab Runner 工具執行它。每次觸發的 CICD 會把配置中的腳劃分為不同的 job,多個 job 組成一個 pipeline。最簡單的 .gitlab-ci.yml 文件可以包含:

before_script:
 - apt-get install rubygems ruby-dev -y

run-test:
  script:
    - ruby --version

其中 before_scripts 屬性會在執行任一腳本前預裝一些需要的依賴(類似 unittestsetUp 方法),此后名為 run-test 的腳本會顯示當前系統的 ruby 版本。這兩個步驟組成了一個 pipeline 會在這個倉庫的每次push后執行。這行任務的執行情況也可以在 Gitlab 的對應頁面上查看,就像在 Terminal 中看日志一樣。

CICD執行日志

而每個 pipeline 的 job 的執行情況也可以在頁面上查看

pipeline查看

如果中途報錯了,可以一鍵回滾

回滾按鈕

CICD 工作流

假設你在本地修改了一些代碼以增加一些特性,當你把這些改動 push 到遠程倉庫的特性分支后,項目里設定的 CICD pipeline 就被觸發了,一般流程如下:

  • 運行自動腳本(串行或并行):
    • 構建并測試應用
    • 在合并前 review 改動

上述流程如果沒有問題就可以把改動合并入主分支,CD 會自動把它部署到產品中,如果發現了任何問題,還能一鍵回滾。

工作流程圖如下:

workflow_chart

該圖簡要顯示了基本的工作流,想要了解 Gitlab CICD 的更多特請,請參閱CICD 索引表

.gitlab-ci.yml 文件結構

.gitlab-ci.yml 是指定了 CICD 相關配置的 YAML 文件。(YAML 是專門用來寫配置文件的語言,簡潔強大,和 python 一樣用縮進代表層級,表達能力和 JSON 基本一致,但格式更方便。相關知識可以參考阮昱峰老師的博文

一般而言,CICD 過程會包含如下最外層的 key:

  • stages: 定義整個 CICD pipeline 的 job 數量和名稱
  • variables: 定義 CICD 流程中的一些環境變量
  • before_scripts: 在每個 jobscripts 執行前進行的命令集,一般是創建目錄,打印 context 目錄等操作,可類比 unittestsetUp 方法
  • stage: 定義了一個 job 的具體流程,可以在前面加上名稱

下面通過一個例子進行一些講解

stages:
  - test
  - build
  - deploy

variables:
  GIT_STRATEGY: none
  PROJECT_REPO_NAMESPACE: test
  PROJECT_REPO_NAME: cicd_learn
  DEPLOYMENT_REPO_NAMESPACE: test
  DEPLOYMENT_REPO_NAME: deploy_test

before_script:
  - export ROOT_PATH=$(pwd)
  - echo 'root path:' $ROOT_PATH
  - mkdir $PROJECT_REPO_NAME
  - cd $PROJECT_REPO_NAME
  - <some git manipulation here>
  - echo 'date:' $DATE

test_stage:
  stage: test
  script:
    - <test related command here>
  artifacts:
    paths:
      - xxxx.html
    when: always
  allow_failure: false

build_stage:
  stage: build
  script:
     - <build related command here>
  when: manual
  allow_failure: false
  only:
    - master

deploy:
  stage: deploy
  script:
    - <deploy related command here>
  allow_failure: false
  only:
    - master

stages

例子中 stages 值為一個數組(p.s. 用 - 代表數組和 markdown 類似)。包含了三個 jobtest, build, deployr 分別實現自動測試,打包項目和部署。下方的 stage 必須在全局定義的 stages 內。

variables

值為鍵值對象,為了后續的流程,此處定義了開發項目和部署項目的 namespace 和 repo_name。同 shell 類似,后續使用其值需要加上 $ 符號。定義的變量也有對應的作用域,定義在頂層就可以作為全局變量供所有 job 使用,如果是一些 job 特有的變量,就定義在 job 內部。

before_script

值為數組,每一個元素其實就是一個 linux 命令,寫的時候裝作自己在寫 shell 就好。該部分主要生成了后續構建需要的鏡像標簽,切換當前目錄等。為了 debug 方便,這些變量最好打印。類似的,如果在 job 完成后有一些時候操作,可以定義 after_script。需要注意的是如果定義在頂層,內部的命令會在每個 job 運行之前執行,如果某些 job 需要特別的預操作,可以在 job 內部再配置一個 before_script 對象,它會復寫外部的全局預操作。

test_stage

名為 testjob 的具體配置,一般是個復合對象。

stage

job 對應的 stage,如果有多個 job 對應同一個 stage,在執行時會并行執行這些 job

script

這個 job 執行的命令,此處是進入的項目倉庫目錄,并且執行了一個 shell 腳本,這個腳本定義了執行項目的所有單元測試。一般建議如果要執行的命令過多,就把這些命令寫成腳本放在項目內。CICD 流程直接執行這個腳本。

artifacts

這個對象用來定義 job 的產出,比如我們讓 test_stage 產出一個 html 格式的報告,顯示每個單元測試的執行情況(報告生成相關代碼寫在項目內)。 數組內的 pathswhen 分別定義報告的路徑和產出場景。此處表示報告放置于根目錄下,任何時候都要提供報告。設定正確后,就可以 Gitlab 的 pipline 頁面上可以下載相關文件。

allow_failure

見名知意,如果值為 true,那么即使沒通過測試,也可以執行后續的 job.

build_stage

該步驟在測試通過的基礎上,把項目編譯打包,方便后續部署。

when

此處的 when 定義在 job 內的頂層,值為 manual 表示其需要在 Gitlab 上手動觸發(頁面上點擊按鈕即可)。

only

only 指明了 job 的執行場景,可以是分支名,表明只有 master 分支可以執行 build,如果要用排除法反向指定,可以用 except

deploy_stage

所有的 key 現在你應該都了解了,這里不再贅述。這一步驟主要是將部署產品的服務器上的內容更新。