JB的git之旅--.gitlab-ci.yml介紹

jb發表於2018-07-05

前言

之前有專門寫過一篇文章,對gitlab ci進行介紹,其中有涉及到gitlab-ci.yml進行介紹,那可能會有疑問,為什麼要再開一篇來再說yml這玩意?

主要是因為之前在用gitlab-ci遇到不少問題,一路上摸索不容易,雖然有前車之鑑,但仍然遇到不可描述的問題,因為想重新瞭解下這塊,當做是一個筆記;
上一篇關於gitlab ci介紹的連結:
https://juejin.im/post/5afd42be6fb9a07aaa11793f

gitlab-ci執行介紹

由以下兩個模組組成:

gitlab-ci server
gitlab-ci-runner
複製程式碼

其中,gitlab-ci server負責排程、觸發Runner,以及獲取返回結果.
而gitlab-ci-runner則是主要負責來跑自動化CI(測試,編譯,打包等)。

基本流程是:

使用者提交程式碼
檢查是否有.gitlab-ci.yml檔案
如果無,則結束;
如果有,則呼叫runner執行指令碼
獲取返回的結果。
複製程式碼

.gitlab-ci.yml

從7.12版本開始,GitLab CI使用YAML檔案(.gitlab-ci.yml)來管理專案配置。
該檔案存放於專案倉庫的根目錄,它定義該專案如何構建。

開始構建之前YAML檔案定義了一系列帶有約束說明的任務。
這些任務都是以任務名開始並且至少要包含script部分:

job1:
  script: 
      - echo "jb1"
  
job2:
  script: 
      - echo "jb2"
複製程式碼

上面例子是一個簡單且帶有兩個獨立任務的CI配置,每個任務分別執行echo輸出對應的內容。

script可以直接執行系統命令
(例如:./configure;make;make install)或者是直接執行指令碼(test.sh)

任務是由Runners接管並且由伺服器中runner執行。
每一個任務的執行過程都是獨立執行的

例子1:

# 定義 stages
stages:
    - build
    - test

# 定義 job
job1:
    stage: test
    script:
        - echo "I am jb1"
        - echo "I am in test stage"

# 定義 job
job2:
    stage: build
    script:
        - echo "I am jb2"
        - echo "I am in build stage"
複製程式碼

根據在 stages 中的定義,build 階段要在 test 階段之前執行,
所以 stage:build 的 jobs 會先執行,
之後才會執行 stage:test 的 jobs。

再來個複雜的例子2:

image: ruby:2.1
services:
  - postgres

before_script:
  - bundle install

after_script:
  - rm secrets

stages:
  - build
  - test
  - deploy

job1:
  stage: build
  script:
    - execute-script-for-job1
  only:
    - master
  tags:
    - docker5+4X5=25
複製程式碼

下面列出保留欄位,這些保留欄位不能被定義為job名稱:

關鍵字 是否必須 描述
image 用於docker映象,檢視docker文件
services 用於docker服務,檢視docker文件
stages 定義構建階段
types stages 的別名(已廢除)
before_script 定義在每個job之前執行的命令
after_script 定義在每個job之後執行的命令
variable 定義構建變數
cache 定義一組檔案列表,可在後續執行中使用

image和services
這兩個關鍵字允許使用一個自定義的Docker映象和一系列的服務,並且可以用於整個job週期。

before_script
before_script用來定義所有job之前執行的命令,包括deploy(部署) jobs,
但是在修復artifacts之後。它可以是一個陣列或者是多行字串。

after_script

GitLab 8.7 開始引入,並且要求Gitlab Runner v1.2
複製程式碼

after_script用來定義所有job之後執行的命令。它必須是一個陣列或者是多行字串;

stages
stages用來定義可以被job呼叫的stages。

stages中的元素順序決定了對應job的執行順序:

1. 相同stage的job可以平行執行。
2. 下一個stage的job會在前一個stage的job成功後開始執行。
複製程式碼

這裡劃重點:下一個stage的job會在前一個stage的job成功後開始執行
正因為如此,所以可以在stage設定很多相互依賴的步驟,而且不需要判斷是否成功狀態,因為能執行下來的,必定是成功的!

看會上方的例子1:

stages:
    - build
    - test
複製程式碼
    1. 首先,所有build的job都是並行執行的
    1. 所有build的jobs執行成功後,test的jobs才會開始並行執行
  • 3.所有的test的jobs執行成功,commit才會標記為success
  • 4.任何一個前置的jobs失敗了,commit都會標記為failed並且下一個stages的jobs都不會執行。

這裡提兩個特殊例子:

1.如果.gitlab-ci.yml中沒有定義stages,那麼jobs的stages會預設定義成build,test和deploy
2.如果一個job沒有指定stage,那麼這個任務會分配到test stage
複製程式碼

types

已廢除,將會在10.0中移除。用stages替代,含義與stages一致
複製程式碼

variable
GItLab CI 允許在.gitlab-ci.yml檔案中新增變數,並在job環境中起作用。
因為這些配置是儲存在git倉庫中,所以最好是儲存專案的非敏感配置,例如:

variables:
  jb: "jb is here"
複製程式碼

這裡注意,:號後面是帶上空格的,不然會說語法錯誤 這些變數可以被後續的命令和指令碼使用.

除了使用者自定義的變數外,Runner也可以定義它自己的變數。
CI_COMMIT_REG_NAME就是一個很好的例子,它的值表示用於構建專案的分支或tag名稱。
除了在.gitlab-ci.yml中設定變數外,還有可以通過GitLab的介面上設定私有變數。

cache
用來指定需要在job之間快取的檔案或目錄。只能使用該專案工作空間內的路徑。

從GitLab 9.0開始,pipelines和job就預設開啟了快取

如果cache定義在jobs的作用域之外,那麼它就是全域性快取,所有jobs都可以使用該快取。

快取git中沒有被跟蹤的檔案:

rspec:
  script: test
  cache:
    untracked: true
複製程式碼

快取binaries下沒有被git跟蹤的檔案:

rspec:
  script: test
  cache:
    untracked: true
    paths:
    - binaries/
複製程式碼

快取key
key指令允許我們定義快取的作用域(親和性),可以是所有jobs的單個快取,也可以是每個job,也可以是每個分支或者是任何你認為合適的地方。

cache:key可以使用任何的預定義變數

快取每個job:

cache:
  key: "$CI_JOB_NAME"
  untracked: true
複製程式碼

快取每個分支:

cache:
  key: "$CI_COMMIT_REF_NAME"
  untracked: true
複製程式碼

快取每個job且每個分支:

cache:
  key: "$CI_JOB_NAME/$CI_COMMIT_REF_NAME"
  untracked: true
複製程式碼

快取每個分支且每個stage:

cache:
  key: "$CI_JOB_STAGE/$CI_COMMIT_REF_NAME"
  untracked: true
複製程式碼

如果使用的Windows Batch(windows批處理)來跑指令碼需要用%替代$

cache:
  key: "%CI_JOB_STAGE%/%CI_COMMIT_REF_NAME%"
  untracked: true
複製程式碼

Jobs

.gitlab-ci.yml允許指定無限量jobs。
每個jobs必須有一個唯一的名字,而且不能是上面提到的關鍵字。
job由一列引數來定義jobs的行為。

job_name:
  script:
    - rake spec
    - coverage
  stage: test
  only:
    - master
  except:
    - develop
  tags:
    - ruby
    - postgres
  allow_failure: true
複製程式碼
關鍵詞 是否必需 描述
script yes Runner執行的命令或指令碼
image no 所使用的docker映象,查閱使用docker映象
services no 所使用的docker服務,查閱使用docker映象
stage no 定義job stage(預設:test)
type no stage的別名(已棄用)
variables no 定義job級別的變數
only no 定義一列git分支,併為其建立job
except no 定義一列git分支,不建立job
tags no 定義一列tags,用來指定選擇哪個Runner(同時Runner也要設定tags)
allow_failure no 允許job失敗。失敗的job不影響commit狀態
when no 定義何時開始job。可以是on_success,on_failure,always或者manual
dependencies no 定義job依賴關係,這樣他們就可以互相傳遞artifacts
cache no 定義應在後續執行之間快取的檔案列表
before_script no 重寫一組在作業前執行的命令
after_script no 重寫一組在作業後執行的命令
environment no 定義此作業完成部署的環境名稱
coverage no 定義給定作業的程式碼覆蓋率設定

script
script是Runner執行的yaml指令碼。

job:
  script: "bundle exec rspec"
複製程式碼

該引數也可以用陣列包含多個命令:

job:
  script:
    - uname -a
    - bundle exec rspec
複製程式碼

這裡需要注意一點,如果script命令裡面包含冒號:時,script需要被包在雙引號內,這樣YAML解析器才可以正確解析為一個字串,而不是一個鍵值對(key:value);
使用下面這些特殊字元的時候,都要注意下:

:,{,},[,],,,&,*,#,?,|,-,<,>,=,!。
複製程式碼

stage
stage允許一組jobs進入不同的stages。
jobs在相同的stage時會parallel同時進行;
更多的用法請點選這裡;

tags
tags可以從允許執行此專案的所有Runners中選擇特定的Runners來執行jobs。
在註冊Runner的過程中,我們可以設定Runner的標籤,比如ruby,postgres,development。

tags可通過tags來指定特殊的Runners來執行jobs:

job:
  tags:
    - ruby
    - postgres
複製程式碼

上面這個示例中,需要確保構建此job的Runner必須定義了ruby和postgres這兩個tags。

allow_failure
allow_failure可以用於當你想設定一個job失敗的之後並不影響後續的CI元件的時候。
失敗的jobs不會影響到commit狀態。

下面的這個例子中,job1和job2將會並列進行,如果job1失敗了,它也不會影響進行中的下一個stage,因為這裡有設定了allow_failure: true。

job1:
  stage: test
  script:
  - execute_script_that_will_fail
  allow_failure: true

job2:
  stage: test
  script:
  - execute_script_that_will_succeed

job3:
  stage: deploy
  script:
  - deploy_to_staging
複製程式碼

when
when is used to implement jobs that are run in case of failure or despite the failure.
翻譯過來就是:用於實現在失敗或失敗時執行的作業。

可以設定以下值:

on_success - 只有前面stages的所有工作成功時才執行。 這是預設值。
on_failure - 當前面stages中任意一個jobs失敗後執行。
always - 無論前面stages中jobs狀態如何都執行。
`manual ` - 手動執行。
複製程式碼

舉個例子:

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。

coverage
允許你配置程式碼覆蓋率將會從該job中提取輸出。
在這裡正規表示式是唯一有效的值。
因此,字串的前後必須使用/包含來表明一個正確的正規表示式規則。特殊字串需要轉義。

舉個例子:

job1:
  coverage: '/Code coverage: \d+\.\d+/'
複製程式碼

Git Strategy

GitLab 8.9中以試驗性功能引入。將來的版本中可能改變或完全移除。GIT_STRATEGY要求GitLab Runner v1.7+。
複製程式碼

可以通過設定GIT_STRATEGY用於獲取最新的程式碼,可以再全域性variables或者是在單個job的variables模組中設定。
如果沒有設定,將從專案中使用預設值。

可以設定的值有:clone,fetch,和none。

clone是最慢的選項。它會從頭開始克隆整個倉庫,包含每一個job,以確保專案工作區是最原始的。

variables:
  GIT_STRATEGY: clone
複製程式碼

當它重新使用專案工作區是,fetch是更快(如果不存在則返回克隆)。
git clean用於撤銷上一個job做的任何改變,git fetch用於獲取上一個job到現在的的commit。

variables:
  GIT_STRATEGY: fetch
複製程式碼

none也是重新使用專案工作區,但是它會跳過所有的Git操作(包括GitLab Runner前的克隆指令碼,如果存在的話)。
它主要用在操作job的artifacts(例如:deploy)。

variables:
  GIT_STRATEGY: none
複製程式碼

Git Checout
GIT_STRATEGY設定為clonefetch時,可以使用GIT_CHECKOUT變數來指定是否應該執行git checkout
如果沒有指定,它預設為true。就像GIT_STRATEGY一樣,它可以設定在全域性variables或者是單個job的variables中設定。

如果設定為false,Runner就會:

  • fetch - 更新倉庫並在當前版本中保留工作副本,
  • clone - 克隆倉庫並在預設分支中保留工作副本。

如果設定這個為true將意味著clone和fetch策略都會讓Runner執行專案工作區更新到最新

variables:
  GIT_STRATEGY: clone
  GIT_CHECKOUT: false
script:
  - git checkout master
  - git merge $CI_BUILD_REF_NAME
複製程式碼

Git Submodule Strategy
GIT_SUBMODULE_STRATEGY變數用於在構建之前拉取程式碼時,Git子模組是否或者如何被引入。
它的可用值有:none,normal和recursive:
1)none意味著在拉取專案程式碼時,子模組將不會被引入。這個是預設值.
2)normal意味著在只有頂級子模組會被引入。它相當於

git submodule sync
git submodule update --init
複製程式碼

3)recursive意味著所有的子模組(包括子模組的子模組)都會被引入,他相當於:

git submodule sync --recursive
git submodule update --init --recursive
複製程式碼

注意:如果想要此功能正常工作,子模組必須配置(在.gitmodules)下面中任意一個:

可訪問的公共倉庫http(s)地址,
在同一個GitLab伺服器上有一個可訪問到另外的倉庫的真實地址。
複製程式碼

Job stages attempts
正在執行的job將會按照你設定嘗試次數依次執行下面的stages:

變數 描述
GET_SOURCES_ATTEMPTS 獲取job源的嘗試次數
ARTIFACT_DOWNLOAD_ATTEMPTS 下載artifacts的嘗試次數
RESTORE_CACHE_ATTEMPTS 重建快取的嘗試次數

預設是一次嘗試。

例子:

variables:
  GET_SOURCES_ATTEMPTS: 3
複製程式碼

pages
pages是一個特殊的job,用於將靜態的內容上傳到GitLab,可用於為您的網站提供服務。
它有特殊的語法,因此必須滿足以下兩個要求:

任何靜態內容必須放在public/目錄下
artifacts必須定義在public/目錄下
複製程式碼

下面的這個例子是將所有檔案從專案根目錄移動到public/目錄。
.public工作流是cp,並且它不會迴圈複製public/本身。

pages:
  stage: deploy
  script:
  - mkdir .public
  - cp -r * .public
  - mv .public public
  artifacts:
    paths:
    - public
  only:
  - master
複製程式碼

Runner 定義的變數

上面在介紹variable的時候,有提及到Runner也有自己定義的變數,如下:

變數 gitlab版本 runner 描述
CI all 0.4 標記這個 job 是在 CI 環境執行的
CI_COMMIT_REF_NAME 9.0 all 構建專案的 branch 或 tag 名稱
CI_COMMIT_REF_SLUG 9.0 all $CI_COMMIT_REF_NAME小寫,除了0-9和a-z,替換為-
CI_COMMIT_SHA 9.0 all 構建專案的 commit SHA 值
CI_COMMIT_TAG 9.0 0.5 構建專案的 commit 的 tag 名,只有在構建 tags 時才會使用。
CI_COMMIT_MESSAGE 10.8 all 完整的提交訊息。
CI_COMMIT_TITLE 10.8 all 提交的標題——訊息的完整第一行
CI_COMMIT_DESCRIPTION 10.8 all 對提交的描述
CI_CONFIG_PATH 9.4 0.5 CI 配置檔案路徑,預設值是 .gitlab-ci.yml
CI_DEBUG_TRACE all 1.7 是否啟用 debug tracing 跟蹤除錯功能
CI_DEPLOY_USER 10.8 all GitLab部署令牌的身份驗證使用者名稱
CI_DEPLOY_PASSWORD 10.8 all GitLab部署令牌的身份驗證密碼
CI_DISPOSABLE_ENVIRONMENT all 10.1 標記job 是否執行在一次性環境中
CI_ENVIRONMENT_NAME 8.15 all 執行 job 的環境名,如 produciton,dev,pre-production 等
CI_ENVIRONMENT_SLUG 8.15 all 環境名稱的簡化版本,適用於DNS、url、Kubernetes標籤等。
CI_ENVIRONMENT_URL 9.3 all 執行 job 的環境 URL
CI_JOB_ID 9.0 all 當前 job 在 GitLab CI 內部的唯一 ID
CI_JOB_MANUAL 8.12 all 標識該 job 是要手動開始的
CI_JOB_NAME 9.0 0.5 在 .gitlab-ci.yml 中定義的 job 名稱
CI_JOB_STAGE 9.0 0.5 在 .gitlab-ci.yml 中定義的 stage 名稱
CI_JOB_TOKEN 9.0 1.2 用於在GitLab容器登錄檔進行身份驗證的令牌
CI_JOB_URL 11.0 0.5 工作的URL
CI_REPOSITORY_URL 9.0 all 克隆 Git repository 的 URL
CI_RUNNER_DESCRIPTION 8.10 0.5 儲存在 GitLab 中的 runner 描述
CI_RUNNER_ID 8.10 0.5 正在執行的 runner 的唯一 ID
CI_RUNNER_TAGS 8.10 0.5 正在執行的 runner tags (標籤)
CI_RUNNER_VERSION all 10.6 正在執行當前 job 的 GitLab Runner 版本
CI_RUNNER_REVISION all 10.6 正在執行當前 job 的 GitLab Runner 修訂版本
CI_RUNNER_EXECUTABLE_ARCH all 10.6 GitLab GitLab Runner 可執行程式的 OS/架構
CI_PIPELINE_ID 8.10 0.5 當前 pipeline 在 GitLab CI 內部的唯一 ID
CI_PIPELINE_TRIGGERED all all 標記這個 job 是 triggered 由觸發器觸發的
CI_PIPELINE_SOURCE 10.0 all 標明如何觸發 pipeline 。 可用的選項有: push, web, trigger, schedule, api, and pipeline
CI_PROJECT_DIR all all 克隆下來的倉庫的完整路徑,以及 job 在哪個目錄執行
CI_PROJECT_ID all all 當前專案在 GitLab CI 內部的唯一 ID
CI_PROJECT_NAME 8.10 0.5 當前正在構建的專案名稱(實際上是專案資料夾名)
CI_PROJECT_NAMESPACE 8.10 0.5 當前正在構建的專案名稱空間 (使用者名稱或groupname)
CI_PROJECT_PATH 8.10 0.5 完整的專案路徑,即名稱空間+專案名
CI_PROJECT_PATH_SLUG 9.3 all $CI_PROJECT_PATH 小寫,除了0-9和a-z,替換為-
CI_PIPELINE_URL 11.0 0.5 Pipeline 詳細URL
CI_PROJECT_URL 8.10 0.5 訪問專案的HTTP地址
CI_PROJECT_VISIBILITY 10.3 all 專案可見性(內部、私人、公共)
CI_REGISTRY 8.10 0.5 如果啟用了註冊中心,它將返回GitLab的登錄檔的地址
CI_REGISTRY_IMAGE 8.10 0.5 如果為專案啟用了登錄檔,那麼它將返回與特定專案相關聯的登記處地址
CI_REGISTRY_PASSWORD 9.0 all 用來將容器推到GitLab容器登錄檔的密碼
CI_REGISTRY_USER 9.0 all 用來將容器推到GitLab容器登錄檔的使用者名稱
CI_SERVER all all 標記CI環境中執行
CI_SERVER_NAME all all 用於協調作業的CI伺服器的名稱
CI_SERVER_REVISION all all 用於安排工作的GitLab修訂
CI_SERVER_VERSION all all 用於安排工作的GitLab版本
CI_SHARED_ENVIRONMENT all 10.1 標記工作是在共享環境中執行的
GET_SOURCES_ATTEMPTS 8.15 1.9 試圖獲取執行作業的資源的次數
GITLAB_CI all all 在GitLab CI環境中執行該作業
GITLAB_USER_EMAIL 8.12 all 開始工作的使用者的電子郵件
GITLAB_USER_ID 8.12 all 開始工作的使用者的id
GITLAB_USER_LOGIN 10.0 all 啟動該工作的使用者的登入使用者名稱
GITLAB_USER_NAME 10.0 all 啟動工作的使用者的真實姓名
RESTORE_CACHE_ATTEMPTS 8.15 1.9 試圖休息的次數

因為沒有漢化版,因此都是拿到網上翻譯的,大致瞭解就行,詳細資訊,可以看官網的介紹:
https://docs.gitlab.com/ce/ci/variables/README.html

不過從上面runner自己定義的變數,是真的有很多很實用的變數,之前寫指令碼都是沒有用變數,自己造輪子的~

小結

本文主要介紹了.gitlab-ci.yml一些常用的指令,比較常用的就是jobs,stages跟runner自己定義的變數,其他的可以先了解;

就介紹到這裡吧,主要介紹常用的,剩下的,可以去官網瞭解下:
https://docs.gitlab.com/ce/ci/yaml/README.html

下篇文章會介紹,怎麼在gitlab ci上獲取每次提交的資訊,並且傳送到釘釘通知,這塊也不難,感興趣的同學可以想想怎麼做;

謝謝大家~

JB的git之旅--.gitlab-ci.yml介紹

相關文章