CICD 入門指北

錢亦欣發表於2019-06-07

目錄

  • 簡介
    • 持續整合
    • 持續部署
  • 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 現在你應該都瞭解了,這裡不再贅述。這一步驟主要是將部署產品的伺服器上的內容更新。

相關文章