前言
之前有專門寫過一篇文章,對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
複製程式碼
-
- 首先,所有
build
的job都是並行執行的
- 首先,所有
-
- 所有
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
設定為clone
或fetch
時,可以使用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上獲取每次提交的資訊,並且傳送到釘釘通知,這塊也不難,感興趣的同學可以想想怎麼做;
謝謝大家~