Gitlab-CICD

CICD是什麼

我們的開發模式經歷瞭如下的轉變:瀑布模型->敏捷開發→DevOps(Development、Operations的組合詞,是一組過程、方法與系統的統稱)

後來隨着DevOps的興起,出現了持續集成(Continuous Integration)、持續交付(Continuous Delivery) 、持續部署(Continuous Deployment) 的新方法,關於持續集成、持續交付、持續部署,總結如下:

  • 持續集成的重點是將各個開發人員的工作集合到一個代碼倉庫中。通常,每天都要進行幾次,主要目的是儘早發現集成錯誤,使團隊更加緊密結合,更好地協作。
  • 持續交付的目的是最小化部署或釋放過程中固有的摩擦。它的實現通常能夠將構建部署的每個步驟自動化,以便任何時刻能夠安全地完成代碼發佈(理想情況下)。
  • 持續部署是一種更高程度的自動化,無論何時對代碼進行重大更改,都會自動進行構建/部署。

持續集成的好處是什麼?

持續集成可以使問題儘早暴露,從而也降低了解決問題的難度,正如老馬所說,持續集成無法消除bug,但卻能大大降低修復的難度和時間。

持續交付的好處是什麼?

持續交付的好處在於快速獲取用戶反饋;適應市場變化和商業策略的變化。開發團隊保證每次提交的修改都是可上線的修改,那麼決定何時上線,上線哪部分功能則完全由產品業務團隊決定。

雖然持續交付有顯著的優點,但也有不成立的時候,比如對於嵌入式系統的開發,往往需要軟硬件的配合。

持續部署的好處是什麼?

持續部署的目標是通過減少批量工作的大小,並加快團隊工作的節奏,幫助開發團隊在其開發流程中消除浪費。這使團隊能夠一直處於一種可持續的平穩流狀態, 讓團隊更容易去創新、試驗,並達到可持續的生產率

市面上的CI有很多,如果在github上搜一下ci工具,也會搜到很多,比如:

相關概念

runner

部署 Gitlab runner 官方文檔:Run GitLab Runner in a container | GitLab
關聯 runner 到 gitlab 官方文檔:Registering runners | GitLab

我們可以簡單的把 Gitlab runner 給理解成.gitlab-ci.yml 文件內容的執行者,.gitlab-ci.yml 告訴了 Gitlab runner 去做什麼。
Gitlab runner 不是一個配置項,它是需要專門部署的,比如用 docker 部署一個 runner 鏡像到可以連接內網的容器。也可以使用公司內配好的 shared runners.

runner是一個單獨的程序需要安裝,並配置到gitlab

pipeline(管道流水線)

  • 一次 Pipeline 其實相當於一次構建任務,裏面可以包含多個流程(Stage),比如自動構建、自動進行單元測試、自動進行代碼檢查等流程 ;
  • 任何提交或者 Merge Request 的合併都可以觸發 Pipeline ;

Stage(構建階段)

  • Stage表示構建階段,就是上面提到的流程 ;
  • 可以在一次 Pipeline中定義多個 Stage;
  • Stage有如下特點 :
    • 所有 stages 會按照順序運行,即當一個 stage 完成後,下一個 Stage纔會開始
    • 只有當所有 Stage 成功完成後,該構建任務 Pipeline 纔算成功
    • 如果任何一個 Stage失敗,那麼後面的 Stage 不會執行,該構建任務 (Pipeline) 失敗

 

階段是對批量的作業的一個邏輯上的劃分,每個 pipeline都必須包含至少一個 Stage。多個 Stage是按照順序執行的,如果其中任何一個 Stage失敗,則後續的 Stage不會被執行,整個 CI 過程被認爲失敗。

Jobs(任務)

  • job表示構建工作,表示某個stage裏面執行的工作 ;
  • 一個stage裏面可以定義多個job ;
  • jobs有如下特點 :
    • 相同 stage 中的jobs 會並行執行
    • 相同 stage 中的 jobs 都執行成功時,該 stage 纔會成功
    • 如果任何一個job 失敗,那麼該 stage 失敗,即該構建任務 (Pipeline) 失敗

.gitlab-ci.yml 文件

.gitlab-ci.yml 文件被用來管理項目的 runner 任務,Gitlab CI通過.gitlab-ci.yml文件管理配置job,該文件定義了statge順序、job應該如何觸發和工作、執行什麼腳本、如何構建pipeline等流程

Yaml Syntax 寫法詳情具體請見 => YAML Syntax ‒ Ansible Documentation

yml和json寫法的對比

例子1

1.數組寫法

{
    "array": ["red", "blue", "yellow"]
}

2.yml寫法

array:
  - red
  - blue
  - yellow

例子2

1.對象寫法

{
  "student1": {
    "name": "小明"
  },
  "array": ["red", "blue", "yellow"],
  "student2": {
    "name": "小明"
  }
}

2.json寫法

# 我是註釋
student1:
  name: 小明
array:
  - red
  - blue
  - yellow
student2:
  name: 小明

簡單例子

 

這裏的四個Statge(階段): Verify、Build、Dockerpush、Deploy四個,這四個階段組成一條Pipeline

每個階段都有一個job,所以總共四個job,也就是unit-testjava-packagedocker-pushservice-1這四個,當然,每個stage可以由多個job組成

 

對應.gitlab-ci.yml

## 定義pipeline流程:verify->build->dockerpush->deploy
stages:
  - verify
  - build
  - dockerpush
  - deploy
 
#單元測試

 
#java編譯
java-package:
  stage: build
  tags:
    - test-cicd
  script:
    - echo build
 
#push鏡像
docker-push:
  stage: dockerpush
  tags:
    - test-cicd
  script:
    - echo docker-push
 
#deploy
service-1:
  stage: deploy
  tags:
    - test-cicd
  script:
    - echo deploy

 

runner執行流程 

Gitlab-CI 關鍵字

Gitlab CI 的關鍵字有很多,但實際常用的只有較小一部分。在此部分會對常用關鍵字進行詳解。
如果需要特殊配置可參考關鍵字文檔=> Keyword reference for the .gitlab-ci.yml file | GitLab

script

需要被運行的腳本。以數組形式配置。

pipeline_job:
  ......
  script:
    - cd <文件夾目錄路徑>
    - npm install
    - npm build
  ......

before_script和after_script

隨着項目越來越大,Job 越來越多,Job 中包含的重複邏輯可能會讓配置文件臃腫不堪。.gitlab-ci.yml 中提供了 before_script 和 after_script 兩個全局配置項。這兩個配置項在所有 Job 的 script 執行前和執行後調用。

before_script 和 script 在一個上下文中是串行執行的,after_script 是獨立執行的。所以根據執行器(在runner註冊的時候,可以選擇執行器,docker,shell 等)的不同,工作樹之外的變化可能不可見,例如,在before_script中執行軟件的安裝。

你可以在任務中定義 before_scriptafter_script,也可以將其定義爲頂級元素,定義爲頂級元素將爲每一個任務都執行相應階段的腳本或命令。

variables 變量

在 Gitlab-CI 中,變量大致可分爲三類:

1.Gitlab 給我們預先定義的變量,比如CI_COMMIT_BRANCH.

Predefined variables reference | GitLab

2.Setting => Gitlab CI/CD => variables 中定義的變量

3.在.gitlab-ci.yml 中定義的變量(如下示例)
variables:
  TEST_VAR: "All jobs can use this variable's value"

job1:
  variables:
    TEST_VAR_JOB: "Only job1 can use this variable's value"
  script:
    - echo "$TEST_VAR"
  ......

image

CI 流水線運行環境的 docker 鏡像(任何相關的代碼運行環境鏡像皆可),比如docker鏡像安裝了代碼質量掃碼工具

.sonarqube:
  stage: check
  tags:
    - "public"
  image: sonarsource/sonar-scanner-cli:4.6
  allow_failure: false
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
    GIT_DEPTH: "0"  # Tells git to fetch all the branches of the project, required by the analysis task
  cache:
    key: "SONAR_${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - |
      if [ -f "sonar-project.properties" ];then
      sonar-scanner -Dsonar.sources=. -Dsonar.branch.name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
      fi
  only:
    refs:
      - merge_requests

stages

Gitlab CI 允許我們進行自定義的流水線階段配置,我們可以將自己的流水線自我劃分爲若干stages,然後在不同的 stage 來做不同的事

 
## 定義pipeline流程:verify->build->dockerpush->deploy
stages:
  - verify
  - build
  - dockerpush
  - deploy

stage

stage 爲 stages 的一個子項,在我們自定義單個流水線任務時可以配置

unit-test:
  stage: verify # 屬於哪個流程
  tags:
    - test-cicd # 在哪個runner上面執行,在註冊runner可以自定義
  script:
    - echo unit-test # 執行腳本

cache

緩存多個流水線任務之間共用的文件,目錄, etc.

cache:
  key: cache-node-modules
  # 在這裏寫出需要緩存的文件的路徑,在此爲node_modules
  paths:
    - node_modules

retry

一個 job 可以被重新執行的最大數量。必須是個正整數, 0-2, 2 爲最大值

  • when 可設置在特定失敗原因的情況下執行
job:
  script: rspec
  retry:
    max: 2
    when: runner_system_failure

when

when可以設置以下值:

  1. on_success - 只有前面stages的所有工作成功時才執行。 這是默認值。
  2. on_failure - 當前面stages中任意一個jobs失敗後執行。
  3. always - 無論前面stages中jobs狀態如何都執行。
  4. manual - 手動執行(GitLab8.10增加)。
stages:
- build
- cleanup_build
- test
- deploy
- cleanup
 
build_job:
  stage: build
  script:
  - make build
 
cleanup_build_job:
  stage: cleanup_build
  script:
  - cleanup build when failed
  when: on_failure
 
test_job:
  stage: test
  script:
  - make test
 
deploy_job:
  stage: deploy
  script:
  - make deploy
  when: manual
 
cleanup_job:
  stage: cleanup
  script:
  - cleanup after jobs
  when: always

本說明:

  • 只有當build_job失敗的時候纔會執行`cleanup_build_job 。
  • 不管前一個job執行失敗還是成功都會執行`cleanup_job 。
  • 可以從GitLab界面中手動執行deploy_jobs。

manual:

  • 在GitLab的用戶界面中顯示該作業的“播放”按鈕
  • 意味着deploy_job僅在單擊“播放”按鈕時纔會觸發job。

修改後例子

stages:
  - verify
  - build
  - dockerpush
  - deploy
  - cleanup
 
before_script:
  - pwd
after_script:
  - echo after_script
 
#單元測試
unit-test:
  stage: verify
  tags:
    - test-cicd
  script:
    - echo unit-test
 
#java編譯
java-package:
  stage: build
  tags:
    - test-cicd
  script:
    - echo build
 
#push鏡像
docker-push:
  stage: dockerpush
  tags:
    - test-cicd
  script:
    - echo docker-push
 
#deploy
service-1:
  stage: deploy
  tags:
    - test-cicd
  script:
    - echo deploy
  when: manual # 手動觸發job,只有點擊按鈕纔會觸發
 
cleanup_job:
  stage: cleanup
  script:
    - echo clean up
  when: always # 前面的job成功與否,都會執行該job

 

 

 

only & except

only和except兩個參數說明了job什麼時候將會被創建:

  • only定義了job需要執行的所在分支或者標籤
  • except定義了job不會執行的所在分支或者標籤

以下是這兩個參數的幾條用法規則:

  • only和except如果都存在在一個job聲明中,則所需引用將會被only和except所定義的分支過濾.
  • only和except允許使用正則
  • onlyexcept可同時使用。如果onlyexcept在一個job配置中同時存在,則以only爲準,跳過except(從下面示例中得出)。
  • onlyexcept允許使用特殊的關鍵字:branchestagstriggers
  • onlyexcept允許使用指定倉庫地址但不是forks的倉庫(查看示例3)

例子1

.job將會只在issue-開頭的refs下執行,反之則其他所有分支被跳過:

job:
    # use regexp
    only:
        - /^issue-.*$/
    # use special keyword
    except:
        - branches

例子2

job只會在打了tag的分支,或者被api所觸發,或者每日構建任務上運行

job:
    # use special keywords
    only:
        - tags      # tag 分支 commit 之後觸發
        - triggers  # API 觸發
        - schedules # 每日構建觸發

例子3

.job將會在父倉庫gitlab-org/gitlab-ce的非master分支有提交時運行。

job:
    only:
        - branches@gitlab-org/gitlab-ce
    except:
        - master@gitlab-org/gitlab-ce

模塊化寫法

隨着流水線任務的變多,把所有的任務都寫在.gitlab-ci.yml 文件中會顯得很臃腫
解決方法是拆分多個任務到不同的模塊

.gitlab.yml文件中按照如下寫法即可引入不同的 yml 文件

include:
  - local: /.gitlab-ci/cache.yml
  - local: /.gitlab-ci/check.yml
  - local: /.gitlab-ci/pre-build.yml
  - local: /.gitlab-ci/build.yml
  - local: /.gitlab-ci/deploy.yml
  - local: /.gitlab-ci/publish-report.yaml

完整例子

例子1

# .gitlab-ci.yml
# 鏡像爲node的環境鏡像,如果用的是別的環境可以更改爲別的項目環境的鏡像
image: node:latest

# 自定義stages
stages:
  - first_stage
  - second_stage
  - third_stage
  - fourth_stage
  - fifth_stage

# 自定義任務1
job_1_push:
  only:
    - pushes
  # 設置使用fe tags標籤的shared runner
  tags:
    - yehanli
  # 當前任務需要執行的腳本
  script:
    - echo 'job1 ========= 完成'
  # 設置當前任務的stage
  stage: first_stage

# 自定義任務2
job_2_push:
  only:
    - pushes
  tags:
    - yehanli
  script:
    - echo 'job2 ========= 完成'
  stage: third_stage
# 自定義任務3
job_3_push:
  only:
    - pushes
  tags:
    - yehanli
  script:
    - echo 'job3 ========= 完成'
  stage: fourth_stage
  # 設置當前任務爲手動觸發
  when: manual

# 自定義任務4
job_4_push:
  only:
    - pushes
    - tags
  tags:
    - yehanli
  script:
    - echo 'job4 ========= 完成'
  stage: fourth_stage
  when: always

# 自定義任務5
job_5_web:
  only:
  # 設置爲點擊run pipeline時觸發,流水線不自動觸發
    - web
  tags:
    - yehanli
  script:
    - echo 'job5 ========= 完成'
  stage: fifth_stage

 

 

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