流水線語法檢測
GitLab CI的每個實例都有一個稱為Lint的嵌入式調試工具,該工具可以驗證.gitlab-ci.yml文件的內容.
流水線參數列表
Keyword | Description |
---|---|
script |
運行的Shell命令或腳本。 |
image |
使用docker映像. |
services |
使用docker服務映像. |
before_script |
在作業運行前運行腳本。 |
after_script |
在作業運行后運行腳本。 |
stages |
定義管道中的階段,運行順序。 |
stage |
為工作定義一個階段,可選,未指定默認為test階段。 |
only |
限制創建作業的時間. |
except |
限制未創建作業的時間. |
rules |
條件列表,用於評估和確定作業的選定屬性,以及是否創建該作業. |
allow_failure |
允許作業失敗. 失敗的工作不會影響提交狀態. |
when |
什么時候開始工作. |
environment |
作業部署到的環境的名稱. |
cache |
在后續運行之間應緩存的文件列表. |
artifacts |
成功時附加到作業的文件和目錄列表. |
dependencies |
通過提供要從中獲取工件的作業列表,限制將哪些工件傳遞給特定作業. |
coverage |
給定作業的代碼覆蓋率設置. |
retry |
發生故障時可以自動重試作業的時間和次數。 |
timeout |
定義自定義作業級別的超時,該超時優先於項目范圍的設置。 |
parallel |
多少個作業實例應並行運行. |
trigger |
定義下游管道觸發器. |
include |
允許此作業包括外部YAML文件. |
extends |
該作業將要繼承的配置條目. |
pages |
上載作業結果以用於GitLab頁面. |
variables |
在作業級別上定義作業變量. |
interruptible |
定義在通過新的運行使其冗余時是否可以取消作業. |
resource_group |
限制作業並發. |
job/script/before_script/after_script/stages/stage/variables
job
在每個項目中,我們使用名為.gitlab-ci.yml
的YAML文件配置GitLab CI / CD 管道。
這里在pipeline中定義了兩個作業,每個作業運行不同的命令。命令可以是shell或腳本。
job1:
script: "execute-script-for-job1"
job2:
script: "execute-script-for-job2"
- 可以定義一個或多個作業(job)。
- 每個作業必須具有唯一的名稱(不能使用關鍵字)。
- 每個作業是獨立執行的。
- 每個作業至少要包含一個script。
script
job:
script:
- uname -a
- bundle exec rspec
注意:有時, script
命令將需要用單引號或雙引號引起來. 例如,包含冒號命令( :
)需要加引號,以便被包裹的YAML解析器知道來解釋整個事情作為一個字符串,而不是一個”鍵:值”對. 使用特殊字符時要小心: :
, {
, }
, [
, ]
, ,
, &
, *
, #
, ?
, |
, -
, <
, >
, =
!
, %
, @
.
before_script
用於定義一個命令,該命令在每個作業之前運行。必須是一個數組。指定的script
與主腳本中指定的任何腳本串聯在一起,並在單個shell中一起執行。
after_script
用於定義將在每個作業(包括失敗的作業)之后運行的命令。這必須是一個數組。指定的腳本在新的shell中執行,與任何before_script
或script
腳本分開。
可以在全局定義,也可以在job中定義。在job中定義會覆蓋全局。
before_script:
- echo "before-script!!"
variables:
DOMAIN: example.com
stages:
- build
- deploy
build:
before_script:
- echo "before-script in job"
stage: build
script:
- echo "mvn clean "
- echo "mvn install"
after_script:
- echo "after script in job"
deploy:
stage: deploy
script:
- echo "hello deploy"
after_script:
- echo "after-script"
after_script失敗不會影響作業失敗。
before_script失敗導致整個作業失敗,其他作業將不再執行。作業失敗不會影響after_script運行。
stages
用於定義作業可以使用的階段,並且是全局定義的。同一階段的作業並行運行,不同階段按順序執行。
stages:
- build
- test
- deploy
這里定義了三個階段,首先build階段並行運行,然后test階段並行運行,最后deploy階段並行運行。deploy階段運行成功后將提交狀態標記為passed狀態。如果任何一個階段運行失敗,最后提交狀態為failed。
未定義stages
全局定義的stages是來自於每個job。如果job沒有定義stage則默認是test階段。如果全局未定義stages,則按順序運行 build,test,deploy。
如果作業中定義了其他階段,例如”codescan”則會出現錯誤。原因是因為除了build test deploy階段外的其他階段作為.pre運行(也就是作為第一個階段運行,需要將此作業的stage指定為.pre)。
codescan:
stage: .pre
script:
- echo "codescan"
定義stages控制stage運行順序
一個標准的yaml文件中是需要定義stages,可以幫助我們對每個stage進行排序。
stages:
- build
- test
- codescan
- deploy
.pre & .post
.pre始終是整個管道的第一個運行階段,.post始終是整個管道的最后一個運行階段。 用戶定義的階段都在兩者之間運行。.pre
和.post
的順序無法更改。如果管道僅包含.pre
或.post
階段的作業,則不會創建管道。
stage
是按JOB定義的,並且依賴於全局定義的stages
。 它允許將作業分為不同的階段,並且同一stage
作業可以並行執行(取決於特定條件 )。
unittest:
stage: test
script:
- echo "run test"
interfacetest:
stage: test
script:
- echo "run test"
可能遇到的問題: 階段並沒有並行運行。
在這里我把這兩個階段在同一個runner運行了,所以需要修改runner每次運行的作業數量。默認是1,改為10.
vim /etc/gitlab-runner/config.toml 更改后自動加載無需重啟。
concurrent = 10
variables
定義變量,pipeline變量、job變量、Runner變量。job變量優先級最大。
變量具體用法示例:
.gitlab-ci.yml文件中設置的變量會覆蓋下面設置的變量
綜合實例
綜合實例:
before_script:
- echo "before-script!!"
variables:
DOMAIN: example.com
stages:
- build
- test
- codescan
- deploy
build:
before_script:
- echo "before-script in job"
stage: build
script:
- echo "mvn clean "
- echo "mvn install"
- echo "$DOMAIN"
after_script:
- echo "after script in buildjob"
unittest:
stage: test
script:
- echo "run test"
deploy:
stage: deploy
script:
- echo "hello deploy"
- sleep 2;
codescan:
stage: codescan
script:
- echo "codescan"
- sleep 5;
after_script:
- echo "after-script"
- ech
實驗效果
可能遇到的問題: pipeline卡主,為降低復雜性目前沒有學習tags,所以流水線是在共享的runner中運行的。需要設置共享的runner運行沒有tag的作業。
tags/allow_failure/when/retry/timeout/parallel
tags
用於從允許運行該項目的所有Runner列表中選擇特定的Runner,在Runner注冊期間,您可以指定Runner的標簽。
tags
可讓您使用指定了標簽的runner來運行作業,此runner具有ruby和postgres標簽。
job:
tags:
- ruby
- postgres
給定帶有osx
標簽的OS X Runner和帶有windows
標簽的Windows Runner,以下作業將在各自的平台上運行。
windows job:
stage:
- build
tags:
- windows
script:
- echo Hello, %USERNAME%!
osx job:
stage:
- build
tags:
- osx
script:
- echo "Hello, $USER!"
allow_failure
allow_failure
允許作業失敗,默認值為false
。啟用后,如果作業失敗,該作業將在用戶界面中顯示橙色警告. 但是,管道的邏輯流程將認為作業成功/通過,並且不會被阻塞。 假設所有其他作業均成功,則該作業的階段及其管道將顯示相同的橙色警告。但是,關聯的提交將被標記為”通過”,而不會發出警告。
job1:
stage: test
script:
- execute_script_that_will_fail
allow_failure: true
when
on_success
前面階段中的所有作業都成功(或由於標記為allow_failure
而被視為成功)時才執行作業。 這是默認值。
on_failure
當前面階段出現失敗則執行。
always
-執行作業,而不管先前階段的作業狀態如何,放到最后執行。總是執行。
manual 手動
manual
-手動執行作業,不會自動執行,需要由用戶顯式啟動. 手動操作的示例用法是部署到生產環境. 可以從管道,作業,環境和部署視圖開始手動操作。
此時在deploy階段添加manual,則流水線運行到deploy階段為鎖定狀態,需要手動點擊按鈕才能運行deploy階段。
delayed 延遲
delayed
延遲一定時間后執行作業(在GitLab 11.14中已添加)。
有效值'5',10 seconds,30 minutes, 1 day, 1 week
。
實驗demo
before_script:
- echo "before-script!!"
variables:
DOMAIN: example.com
stages:
- build
- test
- codescan
- deploy
build:
before_script:
- echo "before-script in job"
stage: build
script:
- echo "mvn clean "
- echo "mvn install"
- echo "$DOMAIN"
after_script:
- echo "after script in buildjob"
unittest:
stage: test
script:
- ech "run test"
when: delayed
start_in: '30'
allow_failure: true
deploy:
stage: deploy
script:
- echo "hello deploy"
- sleep 2;
when: manual
codescan:
stage: codescan
script:
- echo "codescan"
- sleep 5;
when: on_success
after_script:
- echo "after-script"
- ech
retry
配置在失敗的情況下重試作業的次數。
當作業失敗並配置了retry
,將再次處理該作業,直到達到retry
關鍵字指定的次數。如果retry
設置為2,並且作業在第二次運行成功(第一次重試),則不會再次重試. retry
值必須是一個正整數,等於或大於0,但小於或等於2(最多兩次重試,總共運行3次).
unittest:
stage: test
retry: 2
script:
- ech "run test"
默認情況下,將在所有失敗情況下重試作業。為了更好地控制retry
哪些失敗,可以是具有以下鍵的哈希值:
max
:最大重試次數.when
:重試失敗的案例.
根據錯誤原因設置重試的次數。
always :在發生任何故障時重試(默認).
unknown_failure :當失敗原因未知時。
script_failure :腳本失敗時重試。
api_failure :API失敗重試。
stuck_or_timeout_failure :作業卡住或超時時。
runner_system_failure :運行系統發生故障。
missing_dependency_failure: 如果依賴丟失。
runner_unsupported :Runner不受支持。
stale_schedule :無法執行延遲的作業。
job_execution_timeout :腳本超出了為作業設置的最大執行時間。
archived_failure :作業已存檔且無法運行。
unmet_prerequisites :作業未能完成先決條件任務。
scheduler_failure :調度程序未能將作業分配給運行scheduler_failure。
data_integrity_failure :檢測到結構完整性問題。
實驗
定義當出現腳本錯誤重試兩次,也就是會運行三次。
unittest:
stage: test
tags:
- build
only:
- master
script:
- ech "run test"
retry:
max: 2
when:
- script_failure
效果
timeout 超時
特定作業配置超時,作業級別的超時可以超過項目級別的超時,但不能超過Runner特定的超時。
build:
script: build.sh
timeout: 3 hours 30 minutes
test:
script: rspec
timeout: 3h 30m
項目設置流水線超時時間
超時定義了作業可以運行的最長時間(以分鍾為單位)。 這可以在項目的“設置”>” CI / CD”>“常規管道”設置下進行配置 。 默認值為60分鍾。
runner超時時間
此類超時(如果小於項目定義的超時 )將具有優先權。此功能可用於通過設置大超時(例如一個星期)來防止Shared Runner被項目占用。未配置時,Runner將不會覆蓋項目超時。
此功能如何工作:
示例1-運行程序超時大於項目超時
runner超時設置為24小時,項目的CI / CD超時設置為2小時。該工作將在2小時后超時。
示例2-未配置運行程序超時
runner不設置超時時間,項目的CI / CD超時設置為2小時。該工作將在2小時后超時。
示例3-運行程序超時小於項目超時
runner超時設置為30分鍾,項目的CI / CD超時設置為2小時。工作在30分鍾后將超時
parallel
配置要並行運行的作業實例數,此值必須大於或等於2並且小於或等於50。
這將創建N個並行運行的同一作業實例. 它們從job_name 1/N
到job_name N/N
依次命名。
codescan:
stage: codescan
tags:
- build
only:
- master
script:
- echo "codescan"
- sleep 5;
parallel: 5
綜合實例
before_script:
- echo "before-script!!"
variables:
DOMAIN: example.com
stages:
- build
- test
- codescan
- deploy
build:
before_script:
- echo "before-script in job"
stage: build
script:
- echo "mvn clean "
- echo "mvn install"
- echo "$DOMAIN"
after_script:
- echo "after script in buildjob"
unittest:
stage: test
script:
- ech "run test"
when: delayed
start_in: '5'
allow_failure: true
retry:
max: 1
when:
- script_failure
timeout: 1 hours 10 minutes
deploy:
stage: deploy
script:
- echo "hello deploy"
- sleep 2;
when: manual
codescan:
stage: codescan
script:
- echo "codescan"
- sleep 5;
when: on_success
parallel: 5
after_script:
- echo "after-script"
- ech
only/except/rules/workflow
only & except
only和except是兩個參數用分支策略來限制jobs構建:
-
only
定義哪些分支和標簽的git項目將會被job執行。 -
except
定義哪些分支和標簽的git項目將不會被job執行。job: # use regexp only: - /^issue-.*$/ # use special keyword except: - branches
rules
rules
允許按順序評估單個規則對象的列表,直到一個匹配並為作業動態提供屬性. 請注意, rules
不能only/except
與only/except
組合使用。
可用的規則條款包括:
if
(類似於only:variables
)changes
(only:changes
相同)exists
rules:if
如果DOMAIN
的值匹配,則需要手動運行。不匹配on_success
。 條件判斷從上到下,匹配即停止。多條件匹配可以使用&& ||
variables:
DOMAIN: example.com
codescan:
stage: codescan
tags:
- build
script:
- echo "codescan"
- sleep 5;
#parallel: 5
rules:
- if: '$DOMAIN == "example.com"'
when: manual
- when: on_success
rules:changes
接受文件路徑數組。 如果提交中Jenkinsfile
文件發生的變化則為true。
codescan:
stage: codescan
tags:
- build
script:
- echo "codescan"
- sleep 5;
#parallel: 5
rules:
- changes:
- Jenkinsfile
when: manual
- if: '$DOMAIN == "example.com"'
when: on_success
- when: on_success
rules:exists
接受文件路徑數組。當倉庫中存在指定的文件時操作。
codescan:
stage: codescan
tags:
- build
script:
- echo "codescan"
- sleep 5;
#parallel: 5
rules:
- exists:
- Jenkinsfile
when: manual
- changes:
- Jenkinsfile
when: on_success
- if: '$DOMAIN == "example.com"'
when: on_success
- when: on_success
rules:allow_failure
使用allow_failure: true
rules:
在不停止管道本身的情況下允許作業失敗或手動作業等待操作.
job:
script: "echo Hello, Rules!"
rules:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
when: manual
allow_failure: true
在此示例中,如果第一個規則匹配,則作業將具有以下when: manual
和allow_failure: true
。
workflow:rules
頂級workflow:
關鍵字適用於整個管道,並將確定是否創建管道。when
:可以設置為always
或never
. 如果未提供,則默認值always
。
variables:
DOMAIN: example.com
workflow:
rules:
- if: '$DOMAIN == "example.com"'
- when: always
綜合實例
before_script:
- echo "before-script!!"
variables:
DOMAIN: example.com
workflow:
rules:
- if: '$DOMAIN == "example.com"'
when: always
- when: never
stages:
- build
- test
- codescan
- deploy
build:
before_script:
- echo "before-script in job"
stage: build
script:
- echo "mvn clean "
- echo "mvn install"
- ech "$DOMAIN"
after_script:
- echo "after script in buildjob"
rules:
- exists:
- Dockerfile
when: on_success
allow_failure: true
- changes:
- Dockerfile
when: manual
- when: on_failure
unittest:
stage: test
script:
- ech "run test"
when: delayed
start_in: '5'
allow_failure: true
retry:
max: 1
when:
- script_failure
timeout: 1 hours 10 minutes
deploy:
stage: deploy
script:
- echo "hello deploy"
- sleep 2;
rules:
- if: '$DOMAIN == "example.com"'
when: manual
- if: '$DOMAIN == "aexample.com"'
when: delayed
start_in: '5'
- when: on_failure
codescan:
stage: codescan
script:
- echo "codescan"
- sleep 5;
when: on_success
parallel: 5
after_script:
- echo "after-script"
- ech
cache
cache 緩存
用來指定需要在job之間緩存的文件或目錄。只能使用該項目工作空間內的路徑。不要使用緩存在階段之間傳遞工件,因為緩存旨在存儲編譯項目所需的運行時依賴項。
如果在job范圍之外定義了cache
,則意味着它是全局設置,所有job都將使用該定義。如果未全局定義或未按job定義則禁用該功能。
cache:paths
使用paths
指令選擇要緩存的文件或目錄,路徑是相對於項目目錄,不能直接鏈接到項目目錄之外。
$CI_PROJECT_DIR
項目目錄
在job build中定義緩存,將會緩存target目錄下的所有.jar文件。
build:
script: test
cache:
paths:
- target/*.jar
當在全局定義了cache:paths會被job中覆蓋。以下實例將緩存binaries目錄。
cache:
paths:
- my/files
build:
script: echo "hello"
cache:
key: build
paths:
- target/
由於緩存是在job之間共享的,如果不同的job使用不同的路徑就出現了緩存覆蓋的問題。如何讓不同的job緩存不同的cache呢?設置不同的cache:key
。
cache:key 緩存標記
為緩存做個標記,可以配置job、分支為key來實現分支、作業特定的緩存。為不同 job 定義了不同的 cache:key
時, 會為每個 job 分配一個獨立的 cache。cache:key變量可以使用任何預定義變量,默認
default ,從GitLab 9.0開始,默認情況下所有內容都在管道和作業之間共享。
按照分支設置緩存
cache:
key: ${CI_COMMIT_REF_SLUG}
files: 文件發生變化自動重新生成緩存(files最多指定兩個文件),提交的時候檢查指定的文件。
根據指定的文件生成密鑰計算SHA校驗和,如果文件未改變值為default。
cache:
key:
files:
- Gemfile.lock
- package.json
paths:
- vendor/ruby
- node_modules
prefix: 允許給定prefix的值與指定文件生成的秘鑰組合。
在這里定義了全局的cache,如果文件發生變化則值為 rspec-xxx111111111222222 ,未發生變化為rspec-default。
cache:
key:
files:
- Gemfile.lock
prefix: ${CI_JOB_NAME}
paths:
- vendor/ruby
rspec:
script:
- bundle exec rspec
例如,添加$CI_JOB_NAME
prefix
將使密鑰看起來像: rspec-feef9576d21ee9b6a32e30c5c79d0a0ceb68d1e5
,並且作業緩存在不同分支之間共享,如果分支更改了Gemfile.lock
,則該分支將為cache:key:files
具有新的SHA校驗和. 將生成一個新的緩存密鑰,並為該密鑰創建一個新的緩存. 如果Gemfile.lock
未發生變化 ,則將前綴添加default
,因此示例中的鍵為rspec-default
。
cache:policy 策略
默認:在執行開始時下載文件,並在結束時重新上傳文件。稱為” pull-push
緩存策略.
policy: pull
跳過下載步驟
policy: push
跳過上傳步驟
stages:
- setup
- test
prepare:
stage: setup
cache:
key: gems
paths:
- vendor/bundle
script:
- bundle install --deployment
rspec:
stage: test
cache:
key: gems
paths:
- vendor/bundle
policy: pull
script:
- bundle exec rspec ...
綜合實例(一) 全局緩存
before_script:
- echo "before-script!!"
variables:
DOMAIN: example.com
cache:
paths:
- target/
stages:
- build
- test
- deploy
build:
before_script:
- echo "before-script in job"
stage: build
tags:
- build
only:
- master
script:
- ls
- id
- mvn clean package -DskipTests
- ls target
- echo "$DOMAIN"
- false && true ; exit_code=$?
- if [ $exit_code -ne 0 ]; then echo "Previous command failed"; fi;
- sleep 2;
after_script:
- echo "after script in job"
unittest:
stage: test
tags:
- build
only:
- master
script:
- echo "run test"
- echo 'test' >> target/a.txt
- ls target
retry:
max: 2
when:
- script_failure
deploy:
stage: deploy
tags:
- build
only:
- master
script:
- echo "run deploy"
- ls target
retry:
max: 2
when:
- script_failure
after_script:
- echo "after-script"
Pipeline日志分析
build作業運行時會對項目代碼打包,然后生成target目錄。作業結束創建緩存。
開始第二個作業test,此時會把當前目錄中的target目錄刪除掉(因為做了git 對比)。
獲取到第一個作業生成的緩存target目錄。
開始第三個作業,同樣先刪除了target目錄,然后獲取了第二個作業的緩存。最后生成了當前的緩存。
Runner緩存
在做本次實驗的時候我現在本地runner清除了項目的工作目錄和歷史緩存。
[root@zeyang-nuc-service ~]# cd /home/gitlab-runner/builds/1Cxihk7-/0/demo/demo-maven-service/
[root@zeyang-nuc-service demo-maven-service]# ls
Jenkinsfile README.md aaaaa jenkins pom.xml src target
[root@zeyang-nuc-service demo-maven-service]# cd ..
[root@zeyang-nuc-service demo]# ls
demo-maven-service demo-maven-service.tmp
[root@zeyang-nuc-service demo]# rm -fr demo-maven-service
[root@zeyang-nuc-service demo]# rm -fr demo-maven-service.tmp/
[root@zeyang-nuc-service demo]# cd
[root@zeyang-nuc-service ~]# cd /home/gitlab-runner/cache/
[root@zeyang-nuc-service cache]# ls
demo
[root@zeyang-nuc-service cache]# rm -rf *
項目代碼默認不會刪除,可以發現是第二次作業的緩存。(因為上面的例子中第三次作業並沒有修改緩存內容)
[root@zeyang-nuc-service cache]# cd /home/gitlab-runner/builds/1Cxihk7-/0/demo/demo-maven-service/
[root@zeyang-nuc-service demo-maven-service]# ls
Jenkinsfile README.md aaaaa jenkins pom.xml src target
[root@zeyang-nuc-service demo-maven-service]# cd ..
[root@zeyang-nuc-service demo]# ls
demo-maven-service demo-maven-service.tmp
[root@zeyang-nuc-service demo]# rm -fr *
[root@zeyang-nuc-service demo]# ls
[root@zeyang-nuc-service demo]# ls
demo-maven-service demo-maven-service.tmp
[root@zeyang-nuc-service demo]# cd demo-maven-service
[root@zeyang-nuc-service demo-maven-service]# ls
Jenkinsfile README.md aaaaa jenkins pom.xml src target
[root@zeyang-nuc-service demo-maven-service]# cat target/a.txt
test
進入runner緩存目錄中查看緩存。
[root@zeyang-nuc-service ~]# cd /home/gitlab-runner/cache/demo/demo-maven-service/default/
[root@zeyang-nuc-service default]# ls
cache.zip
[root@zeyang-nuc-service default]# unzip cache.zip
Archive: cache.zip
creating: target/
inflating: target/a.txt
creating: target/classes/
creating: target/classes/com/
creating: target/classes/com/mycompany/
creating: target/classes/com/mycompany/app/
inflating: target/classes/com/mycompany/app/App.class
creating: target/maven-archiver/
inflating: target/maven-archiver/pom.properties
creating: target/maven-status/
creating: target/maven-status/maven-compiler-plugin/
creating: target/maven-status/maven-compiler-plugin/compile/
creating: target/maven-status/maven-compiler-plugin/compile/default-compile/
inflating: target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
inflating: target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
creating: target/maven-status/maven-compiler-plugin/testCompile/
creating: target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/
inflating: target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
inflating: target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
inflating: target/my-app-1.1-SNAPSHOT.jar
creating: target/test-classes/
creating: target/test-classes/com/
creating: target/test-classes/com/mycompany/
creating: target/test-classes/com/mycompany/app/
inflating: target/test-classes/com/mycompany/app/AppTest.class
[root@zeyang-nuc-service default]# ls
cache.zip target
[root@zeyang-nuc-service default]# cd target/
[root@zeyang-nuc-service target]# ls
a.txt classes maven-archiver maven-status my-app-1.1-SNAPSHOT.jar test-classes
[root@zeyang-nuc-service target]# cat a.txt
test
此時此刻再次運行流水線作業,第一個作業用的是上個作業最后生成的緩存。
進入runner緩存目錄查看,cache.zip時間已經發生的變化。
[root@zeyang-nuc-service default]# ll
total 12
-rw------- 1 gitlab-runner gitlab-runner 9172 Apr 29 10:27 cache.zip
drwxrwxr-x 6 root root 127 Apr 29 10:05 target
結論: 全局緩存生效於未在作業中定義緩存的所有作業,這種情況如果每個作業都對緩存目錄做了更改,會出現緩存被覆蓋的場景。
綜合實例(二)
控制緩存策略
例如build階段我們需要生成新的target目錄內容,可以優化設置job運行時不下載緩存。
before_script:
- echo "before-script!!"
variables:
DOMAIN: example.com
cache:
paths:
- target/
stages:
- build
- test
- deploy
build:
before_script:
- echo "before-script in job"
stage: build
tags:
- build
only:
- master
script:
- ls
- id
- cat target/a.txt
- mvn clean package -DskipTests
- ls target
- echo "$DOMAIN"
- false && true ; exit_code=$?
- if [ $exit_code -ne 0 ]; then echo "Previous command failed"; fi;
- sleep 2;
after_script:
- echo "after script in job"
cache:
policy: pull #不下載緩存
unittest:
stage: test
tags:
- build
only:
- master
script:
- echo "run test"
- echo 'test' >> target/a.txt
- ls target
- cat target/a.txt
retry:
max: 2
when:
- script_failure
deploy:
stage: deploy
tags:
- build
only:
- master
script:
- cat target/a.txt
- echo "run deploy"
- ls target
- echo "deploy" >> target/a.txt
retry:
max: 2
when:
- script_failure
after_script:
- echo "after-script"
artifacts/dependencies
artifacts
用於指定在作業成功或者失敗時應附加到作業的文件或目錄的列表。作業完成后,工件將被發送到GitLab,並可在GitLab UI中下載。
artifacts:paths
路徑是相對於項目目錄的,不能直接鏈接到項目目錄之外。
將制品設置為target目錄
artifacts:
paths:
- target/
禁用工件傳遞
job:
stage: build
script: make build
dependencies: []
您可能只想為標記的發行版創建構件,以避免用臨時構建構件填充構建服務器存儲。僅為標簽創建工件( default-job
不會創建工件):
default-job:
script:
- mvn test -U
except:
- tags
release-job:
script:
- mvn package -U
artifacts:
paths:
- target/*.war
only:
- tags
artifacts:expose_as
關鍵字expose_as
可用於在合並請求 UI中公開作業工件。
例如,要匹配單個文件:
test:
script:
- echo 1
artifacts:
expose_as: 'artifact 1'
paths:
- path/to/file.txt
使用此配置,GitLab將在指向的相關合並請求中添加鏈接file1.txt
。
制品瀏覽
請注意以下幾點:
- 每個合並請求最多可以公開10個作業工件。
- 如果指定了目錄,那么如果目錄中有多個文件,則該鏈接將指向指向作業工件瀏覽器。
- 如果開啟GitlabPages可以對.html .htm .txt .json .log擴展名單個文件工件渲染工件。
artifacts:name
通過name
指令定義所創建的工件存檔的名稱。可以為每個檔案使用唯一的名稱。 artifacts:name
變量可以使用任何預定義變量。默認名稱是artifacts
,下載artifacts
改為artifacts.zip
。
使用當前作業的名稱創建檔案
job:
artifacts:
name: "$CI_JOB_NAME"
paths:
- binaries/
使用內部分支或標記的名稱(僅包括binaries目錄)創建檔案,
job:
artifacts:
name: "$CI_COMMIT_REF_NAME"
paths:
- binaries/
使用當前作業的名稱和當前分支或標記(僅包括二進制文件目錄)創建檔案
job:
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
paths:
- binaries/
要創建一個具有當前階段名稱和分支名稱的檔案
job:
artifacts:
name: "$CI_JOB_STAGE-$CI_COMMIT_REF_NAME"
paths:
- binaries/
artifacts:when
用於在作業失敗時或盡管失敗而上傳工件。on_success僅在作業成功時上載工件。這是默認值。on_failure僅在作業失敗時上載工件。always 上載工件,無論作業狀態如何。
要僅在作業失敗時上傳工件:
job:
artifacts:
when: on_failure
artifacts:expire_in
制品的有效期,從上傳和存儲到GitLab的時間開始算起。如果未定義過期時間,則默認為30天。
expire_in
的值以秒為單位的經過時間,除非提供了單位。可解析值的示例:
‘42’
‘3 mins 4 sec’
‘2 hrs 20 min’
‘2h20min’
‘6 mos 1 day’
‘47 yrs 6 mos and 4d’
‘3 weeks and 2 days’
一周后過期
job:
artifacts:
expire_in: 1 week
artifacts:reports
用於從作業中收集測試報告,代碼質量報告和安全報告. 在GitLab的UI中顯示這些報告。
注意:無論作業結果(成功或失敗),都將收集測試報告。
artifacts:reports:junit
收集junit單元測試報告,收集的JUnit報告將作為工件上傳到GitLab,並將自動顯示在合並請求中。
build:
stage: build
tags:
- build
only:
- master
script:
- mvn test
- mvn cobertura:cobertura
- ls target
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
when: on_success
expose_as: 'artifact 1'
paths:
- target/*.jar
reports:
junit: target/surefire-reports/TEST-*.xml
注意:如果您使用的JUnit工具導出到多個XML文件,則可以在一個作業中指定多個測試報告路徑,它們將被自動串聯到一個文件中. 使用文件名模式( junit: rspec-*.xml
),文件名數組( junit: [rspec-1.xml, rspec-2.xml, rspec-3.xml]
)或其組合( junit: [rspec.xml, test-results/TEST-*.xml]
)。
如果無法顯示此頁面,需要更改系統設置。此選項可能會加大資源占用,默認禁用了需要啟用。
登錄gitlab
su - git
$ gitlab-rails console
--------------------------------------------------------------------------------
GitLab: 12.9.0 (9a382ff2c82) FOSS
GitLab Shell: 12.0.0
PostgreSQL: 10.12
--------------------------------------------------------------------------------
Feature.enable(:junit_pipeline_view)Loading production environment (Rails 6.0.2)
irb(main):001:0>
irb(main):002:0>
irb(main):003:0> Feature.enable(:junit_pipeline_view)
=> true
irb(main):004:0>
參考鏈接:https://docs.gitlab.com/ee/ci/junit_test_reports.html
artifacts:reports:cobertura
收集的Cobertura覆蓋率報告將作為工件上傳到GitLab,並在合並請求中自動顯示。
build:
stage: build
tags:
- build
only:
- master
script:
- mvn test
- mvn cobertura:cobertura
- ls target
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
when: on_success
expose_as: 'artifact 1'
paths:
- target/*.jar
reports:
junit: target/surefire-reports/TEST-*.xml
cobertura: target/site/cobertura/coverage.xml
$ gitlab-rails console
--------------------------------------------------------------------------------
GitLab: 12.9.0 (9a382ff2c82) FOSS
GitLab Shell: 12.0.0
PostgreSQL: 10.12
--------------------------------------------------------------------------------
Loading production environment (Rails 6.0.2)
irb(main):001:0>
irb(main):002:0>
irb(main):003:0> Feature.enable(:coverage_report_view)
=> true
maven集成cobertura插件
<plugins>
<!-- cobertura plugin start -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<formats>
<format>html</format>
<format>xml</format>
</formats>
</configuration>
</plugin>
<!-- cobertura plugin end -->
</plugins>
執行 mvn cobertura:cobertura 運行測試並產生 Cobertura 覆蓋率報告。
參考鏈接:https://docs.gitlab.com/12.9/ee/user/project/merge_requests/test_coverage_visualization.html
備注實驗未做出效果,具體問題待排查。
dependencies
定義要獲取工件的作業列表,只能從當前階段之前執行的階段定義作業。定義一個空數組將跳過下載該作業的任何工件不會考慮先前作業的狀態,因此,如果它失敗或是未運行的手動作業,則不會發生錯誤。
如果設置為依賴項的作業的工件已過期或刪除,那么依賴項作業將失敗。
綜合實例
before_script:
- echo "before-script!!"
variables:
DOMAIN: example.com
cache:
paths:
- target/
stages:
- build
- test
- deploy
build:
before_script:
- echo "before-script in job"
stage: build
tags:
- build
only:
- master
script:
- ls
- id
- mvn test
- mvn cobertura:cobertura
- ls target
- echo "$DOMAIN"
- false && true ; exit_code=$?
- if [ $exit_code -ne 0 ]; then echo "Previous command failed"; fi;
- sleep 2;
after_script:
- echo "after script in job"
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
when: on_success
#expose_as: 'artifact 1'
paths:
- target/*.jar
#- target/surefire-reports/TEST*.xml
reports:
junit: target/surefire-reports/TEST-*.xml
cobertura: target/site/cobertura/coverage.xml
coverage: '/Code coverage: \d+\.\d+/'
unittest:
dependencies:
- build
stage: test
tags:
- build
only:
- master
script:
- echo "run test"
- echo 'test' >> target/a.txt
- ls target
retry:
max: 2
when:
- script_failure
deploy:
stage: deploy
tags:
- build
only:
- master
script:
- echo "run deploy"
- ls target
retry:
max: 2
when:
- script_failure
after_script:
- echo "after-script"
needs/include/extends/trigger
needs 並行階段
可無序執行作業,無需按照階段順序運行某些作業,可以讓多個階段同時運行。
stages:
- build
- test
- deploy
module-a-build:
stage: build
script:
- echo "hello3a"
- sleep 10
module-b-build:
stage: build
script:
- echo "hello3b"
- sleep 10
module-a-test:
stage: test
script:
- echo "hello3a"
- sleep 10
needs: ["module-a-build"]
module-b-test:
stage: test
script:
- echo "hello3b"
- sleep 10
needs: ["module-b-build"]
如果needs:
設置為指向因only/except
規則而未實例化的作業,或者不存在,則創建管道時會出現YAML錯誤。
暫時限制了作業在needs:
可能需要的最大作業數分配,ci_dag_limit_needs
功能標志已啟用(默認)分配10個,如果功能被禁用為50。
Feature::disable(:ci_dag_limit_needs) # 50
Feature::enable(:ci_dag_limit_needs) #10
制品下載
在使用needs
,可通過artifacts: true
或artifacts: false
來控制工件下載。 默認不指定為true。
module-a-test:
stage: test
script:
- echo "hello3a"
- sleep 10
needs:
- job: "module-a-build"
artifacts: true
相同項目中的管道制品下載,通過將project
關鍵字設置為當前項目的名稱,並指定引用,可以使用needs
從當前項目的不同管道中下載工件。在下面的示例中,build_job
將使用other-ref
ref下載最新成功的build-1
作業的工件:
build_job:
stage: build
script:
- ls -lhR
needs:
- project: group/same-project-name
job: build-1
ref: other-ref
artifacts: true
不支持從parallel:
運行的作業中下載工件。
include
https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates
可以允許引入外部YAML文件,文件具有擴展名.yml
或.yaml
。使用合並功能可以自定義和覆蓋包含本地定義的CI / CD配置。相同的job會合並,參數值以源文件為准。
local
引入同一存儲庫中的文件,使用相對於根目錄的完整路徑進行引用,與配置文件在同一分支上使用。
ci/localci.yml: 定義一個作業用於發布。
stages:
- deploy
deployjob:
stage: deploy
script:
- echo 'deploy'
.gitlab-ci.yml 引入本地的CI文件’ci/localci.yml’。
include:
local: 'ci/localci.yml'
stages:
- build
- test
- deploy
buildjob:
stage: build
script: ls
testjob:
stage: test
script: ls
效果
file
包含來自另一個項目的文件
include:
- project: demo/demo-java-service
ref: master
file: '.gitlab-ci.yml'
實際使用效果演示:
在同一個用戶目錄下的不同倉庫,項目是一個私有倉庫,yml文件所在是一個公開倉庫
注意引用的yml文件的路徑寫法 前面的是用戶名,后面的是倉庫名
template
只能使用官方提供的模板 https://gitlab.com/gitlab-org/gitlab/tree/master/lib/gitlab/ci/templates
include:
- template: Auto-DevOps.gitlab-ci.yml
remote
用於通過HTTP / HTTPS包含來自其他位置的文件,並使用完整URL進行引用. 遠程文件必須可以通過簡單的GET請求公開訪問,因為不支持遠程URL中的身份驗證架構。
include:
- remote: 'https://gitlab.com/awesome-project/raw/master/.gitlab-ci-template.yml'
extends
繼承模板作業
stages:
- test
variables:
RSPEC: 'test'
.tests:
script: echo "mvn test"
stage: test
only:
refs:
- branches
testjob:
extends: .tests
script: echo "mvn clean test"
only:
variables:
- $RSPEC
合並后
testjob:
stage: test
script: mvn clean test
only:
variables:
- $RSPEC
refs:
- branches
extends & include
aa.yml
#stages:
# - deploy
deployjob:
stage: deploy
script:
- echo 'deploy'
only:
- dev
.template:
stage: build
script:
- echo "build"
only:
- master
include:
local: 'ci/localci.yml'
stages:
- test
- build
- deploy
variables:
RSPEC: 'test'
.tests:
script: echo "mvn test"
stage: test
only:
refs:
- branches
testjob:
extends: .tests
script: echo "mvn clean test"
only:
variables:
- $RSPEC
newbuildjob:
script:
- echo "123"
extends: .template
這將運行名為useTemplate
的作業,該作業運行echo Hello!
如.template
作業中所定義,並使用本地作業中所定義的alpine
Docker映像.
trigger 管道觸發
當GitLab從trigger
定義創建的作業啟動時,將創建一個下游管道。允許創建多項目管道和子管道。將trigger
與when:manual
一起使用會導致錯誤。
多項目管道: 跨多個項目設置流水線,以便一個項目中的管道可以觸發另一個項目中的管道。[微服務架構]
父子管道: 在同一項目中管道可以觸發一組同時運行的子管道,子管道仍然按照階段順序執行其每個作業,但是可以自由地繼續執行各個階段,而不必等待父管道中無關的作業完成。
多項目管道
當前面階段運行完成后,觸發demo/demo-java-service項目master流水線。創建上游管道的用戶需要具有對下游項目的訪問權限。如果發現下游項目用戶沒有訪問權限以在其中創建管道,則staging
作業將被標記為失敗。
staging:
variables:
ENVIRONMENT: staging
stage: deploy
trigger:
project: demo/demo-java-service
branch: master
strategy: depend
project
關鍵字,用於指定下游項目的完整路徑。該branch
關鍵字指定由指定的項目分支的名稱。使用variables
關鍵字將變量傳遞到下游管道。 全局變量也會傳遞給下游項目。上游管道優先於下游管道。如果在上游和下游項目中定義了兩個具有相同名稱的變量,則在上游項目中定義的變量將優先。默認情況下,一旦創建下游管道,trigger
作業就會以success
狀態完成。strategy: depend
將自身狀態從觸發的管道合並到源作業。
在下游項目中查看管道信息
在此示例中,一旦創建了下游管道,該staging
將被標記為成功。
父子管道
創建子管道ci/child01.yml
stages:
- build
child-a-build:
stage: build
script:
- echo "hello3a"
- sleep 10
在父管道觸發子管道
staging2:
variables:
ENVIRONMENT: staging
stage: deploy
trigger:
include: ci/child01.yml
strategy: depend
image/services/environment/inherit
准備工作注冊docker類型的runner
gitlab-runner register \
--non-interactive \
--executor "docker" \
--docker-image alpine:latest \
--url "http://192.168.1.200:30088/" \
--registration-token "JRzzw2j1Ji6aBjwvkxAv" \
--description "docker-runner" \
--tag-list "newdocker" \
--run-untagged="true" \
--locked="false" \
--docker-privileged \
--access-level="not_protected"
[[runners]]
name = "docker-runner"
url = "http://192.168.1.200:30088/"
token = "xuaLZD7xUVviTsyeJAWh"
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.docker]
pull_policy = "if-not-present"
tls_verify = false
image = "alpine:latest"
privileged = true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0
image
默認在注冊runner的時候需要填寫一個基礎的鏡像,請記住一點只要使用執行器為docker類型的runner所有的操作運行都會在容器中運行。 如果全局指定了images則所有作業使用此image創建容器並在其中運行。 全局未指定image,再次查看job中是否有指定,如果有此job按照指定鏡像創建容器並運行,沒有則使用注冊runner時指定的默認鏡像。
#image: maven:3.6.3-jdk-8
before_script:
- ls
build:
image: maven:3.6.3-jdk-8
stage: build
tags:
- newdocker
script:
- ls
- sleep 2
- echo "mvn clean "
- sleep 10
deploy:
stage: deploy
tags:
- newdocker
script:
- echo "deploy"
services
工作期間運行的另一個Docker映像,並link到image
關鍵字定義的Docker映像。這樣,您就可以在構建期間訪問服務映像.
服務映像可以運行任何應用程序,但是最常見的用例是運行數據庫容器,例如mysql
。與每次安裝項目時都安裝mysql
相比,使用現有映像並將其作為附加容器運行更容易,更快捷。
services:
- name: mysql:latest
alias: mysql-1
environment
deploy to production:
stage: deploy
script: git push production HEAD:master
environment:
name: production
url: https://prod.example.com
inherit
使用或禁用全局定義的環境變量(variables)或默認值(default)。
使用true、false決定是否使用,默認為true
inherit:
default: false
variables: false
繼承其中的一部分變量或默認值使用list
inherit:
default:
- parameter1
- parameter2
variables:
- VARIABLE1
- VARIABLE2