GitLab CI-CD 學習筆記

2023-02-11 15:01:17

概述

1. CI/CD

CI(持續整合)指開發人員一天內進行多次合併和提交程式碼操作,並通過自動化測試,完成構建

CD(持續部署)指每次程式碼更改都會自動部署到對應環境

CI/CD 結合在一起,可以加快開發團隊交付成果的效率,減少時間成本

2. Gitlab-CI/CD

gitlab-ci 是 gitlab8.0 之後自帶的一個持續整合系統,中心思想是每一次 push 到 gitlab 就會觸發一次指令碼執行,指令碼內容包括測試、編譯、部署等一系列內容

gitlab-ci 的指令碼需要 gitlab-runner 來執行,程式碼 push 之後,webhook 檢查到程式碼變化,就會觸發 gitlab-ci,分配到各個 Runner 來執行相應的指令碼


gitlab-ce

1. 安裝 gitlab-ce

gitlab 有 ce 和 ee 兩個版本,ce 是社群版,開源免費,ee 是企業版,需要付費

下面以 Ubuntu18.04.6 為例,安裝 gitlab-ce

安裝依賴軟體

sudo apt-get update
sudo apt-get install -y curl openssh-server ca-certificates tzdata perl

新增 gitlab 軟體源映象

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash

安裝 gitlab-ce

sudo apt-get install gitlab-ce

如果命令列能看到 Gitlab 的 Logo 列印,就說明安裝成功了

開啟 gitlab 組態檔

vim /etc/gitlab/gitlab.rb

為了能在瀏覽器存取 gitlab,還需要設定 gitlab 的存取地址和埠

# ip:port 改成自己的,也可以用域名
external_url 'http://192.168.66.100:82'

過載設定並重啟

gitlab-ctl recofigure
gitlab-ctl restart

在瀏覽器輸入 http://192.168.66.100:82 即可存取 gitlab,當然了,前提是你的埠要放開

初始使用者名稱為 root,初始密碼記錄在 /etc/gitlab/initial_root_password 檔案,密碼有效期為 24 小時,建議登入後儘快修改密碼

登入以後,就可以建立專案了,其餘的基本的 git 操作這裡就不贅述了

2. 其他問題

gitlab-ctl recofigure 過程,有可能出現卡在 ruby_block[wait for logrotate service socket] action run 的情況,解決辦法如下:

  • ctrl + c 強行結束

  • 執行 systemctl restart gitlab-runsvdir

  • 再次執行 gitlab-ctl recofigure

安裝結束以後,存取 web 端報 502,最可能的原因是埠被佔用了,需要修改埠

vim /etc/gitlab/gitlab.rb
# 修改為沒有被使用的埠即可
puma['port'] = 9091

gitlab-runner

1. 安裝 gitlab-runner

下面以 Ubuntu18.04.6 為例,安裝 gitlab-runner

新增 gitlab 軟體源映象

curl https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash

安裝 gitlab-runner

sudo apt-get install gitlab-runner

2. gitlab-runner 註冊

首先獲取 gitlab-ci 的 token:專案主頁->Setting->CI/CD->Runners Expand

使用命令註冊 gitlab-runner

gitlab-runner register

按照步驟輸入:

  1. GitLab instance URL:如上圖所示 URL
  2. registration token:如上圖所示 Token
  3. description:關於該 Runner 的描述
  4. tags:用於標記該 Runner,後續需要使用這個 tag 來指定 gitlab-runner
  5. optional maintenance note:沒搞懂有啥用,隨意寫
  6. Enter an executor:選擇執行器,gitlab-runner 提供了許多執行器,可用在不同場景中執行構建,這裡選擇 shell

完成以後,重新整理頁面,即可在 Runners Expand 看到新增了一個 Runner

3. 簡單範例

下面我們簡單測試一下 Runner 是否能正常執行,隨意新建一個 SpringBoot 專案

在根目錄下建立一個 .gitlab-ci.yml 檔案,這裡只是簡單輸出一段語句

stages:
  - deploy

deploy-job:
  tags:
    - prod
  stage: deploy
  script:
    - echo "hello world!!!"

push 到 gitlab 後,會發現指令碼已經自動執行了,綠勾代表執行成功

點選綠勾,在下方 Pipeline 點選 deploy-job 可以檢視執行過程


pipeline 語法

1. job & script

.gitlab-ci.yml 檔案中可以定義一個或多個作業(job),每個作業獨立執行,必須有唯一的名稱(不能使用關鍵字)以及包含一個 script,這裡定義了三個作業 build、test、deploy,script 可以是 shell 命令

build:
	script: 
	  - echo "build"
test:
	script: 
	  - echo "test"
deploy:
	script: 
	  - echo "deploy"
	  - echo "finish"

2. before_script & after_script

before_script 用於定義一個命令,在每個作業執行之前執行,before_script 失敗將導致整個作業失敗,其他作業不再執行,如果在作業中定義了 before_script,則該作業不會執行全域性的 before_script

after_script 用於定義一個命令,在每個作業執行之後執行,作業失敗不影響 after_script 的執行,如果在作業中定義了 after_script,則該作業不會執行全域性的 after_script

before_script:
	- echo "before script"
build:
	before_script: 
		- echo "before script in buildjob"
	script: 
		- echo "build"
	after_script:
		- echo "before script in buildjob"
test:
	script: 
		- echo "test"
deploy:
	script: 
		- echo "deploy"
		- echo "finish"
		
after_script:
	- echo "after script"

3. stages & stage

用於定義作業可以使用的階段,並且是全域性定義的,同一階段的作業並行執行,不同階段按順序執行

before_script:
	- echo "before script"
	
stages:
	- build
	- test
	- deploy

build:
	before_script: 
		- echo "before script in buildjob"
	stage: build
	script: 
		- echo "build"
	after_script:
		- echo "before script in buildjob"
test:
	stage: test
	script: 
		- echo "test"
		
deploy:
	stage: deploy
	script: 
		- echo "deploy"
		- sleep 5
		
after_script:
	- echo "after script"

4. .pre & .post

.pre 始終是整個 pipeline 的第一個執行階段,.post 始終是整個 pipeline 的最後一個執行階段,無法修改,使用者自定義的 stage 則在這兩者之間,如果一個 pipeline 僅包含 .pre 和 .post,則不會建立 pipeline

before_script:
	- echo "before script"
	
stages:
	- build
	- test
	- deploy
	
codescan:
	stage: .pre
	script: 
		- echo "codescan"

build:
	before_script: 
		- echo "before script in buildjob"
	stage: build
	script: 
		- echo "build"
	after_script:
		- echo "before script in buildjob"
test:
	stage: test
	script: 
		- echo "test"
		
deploy:
	stage: deploy
	script: 
		- echo "deploy"
		- sleep 5
		
after_script:
	- echo "after script"

5. variables

定義變數,可以定義 pipeline 變數、job 變數,job 變數優先順序最高

before_script:
	- echo "before script"
	
variables:
	DOMAIN: example.com

stages:
	- build
	- test
	- deploy
	
codescan:
	stage: .pre
	script: 
		- echo "codescan"

build:
	before_script: 
		- echo "before script in buildjob"
	stage: build
	script: 
		- echo "build"
		- echo "$DOMAIN"
	after_script:
		- echo "before script in buildjob"
test:
	stage: test
	script: 
		- echo "test"
		
deploy:
	stage: deploy
	script: 
		- echo "deploy"
		- sleep 5
		
after_script:
	- echo "after script"

6. tags

用於指定特定的 job 在特定的 runner 執行,如果 job 不指定 tags,則預設在共用的 runner 執行

windows_job:
	stages: 
		- build
	tags:
		-windows
	script:
		- echo "windows job"

linux_job:
	stages: 
		- build
	tags:
		-linux
	script:
		- echo "linux job"

7. allow_failure

allow_failure 表示是否允許作業失敗,預設值 false 不允許失敗,改為 true 後,如果該作業失敗也不會被阻塞

job1:
	stage: test
	script: 
		- "..."
	allow_failure: true

8. when

when 用於控制作業執行:

  • on_success:前面階段的所有作業成功才執行該作業,預設 on_success
  • on_failure:前面階段出現失敗時執行
  • always:總是執行作業
  • manual:手動執行作業
  • delayed:延遲執行作業
job1:
	stage: test
	script: 
		- "..."
	when: delayed	# 表示延遲30s執行
	start_in: "30"

9. retry

設定作業失敗後重試作業的次數

job1:
	stage: test
	script: 
		- "..."
	retry: 2

也可以精確匹配到某一錯誤,即出現某一錯誤時才重試

job1:
	stage: test
	script: 
		- "..."
	retry: 
		max: 2
		when: 
			- script_failure	# 指令碼失敗時重試

10. timeout

作業級別的超時可以超過專案級別的超時,但不能超過 Runner 特定的超時

job1:
	stage: test
	script: 
		- "..."
	timeout: 3h

11. parallel

設定要並行執行的作業的範例數,此值必須大於等於 2 並小於等於 50,這將建立 N 個並行執行的同一作業範例

job1:
	stage: test
	script: 
		- "..."
	parallel: 5

12. rules

rules 允許按順序評估單個規則,直到匹配為止:

  • if:如果條件匹配,多條件匹配可以使用 && ||

    variables:
    	DOMAIN: example.com
    
    job1:
    	stage: test
    	script: 
    		- "..."
    	rules:	# DOMAIN值匹配,則手動執行,否則
    		- if: '$DOMAIN == "example.com"'
    		  when: manual
    		- if: '$DOMAIN == "example2.com"'
    		  when: delayed
    		  start_in: '5'
    		- when: on_success
    
  • changes:指定檔案發生變化

    job1:
    	stage: test
    	script: 
    		- "..."
    	rules:
    		- changes: 
    			- fimeName # 檔名
    		  when: manual
    		- when: on_success
    
  • exists:指定檔案存在

    job1:
    	stage: test
    	script: 
    		- "..."
    	rules:
    		- exists: 
    			- fimeName # 檔名
    		  when: manual
    		- when: on_success
    

13. workflow-rules

workfolw 關鍵字適用於整個管道,並確定是否建立管道

variables:
	DOMAIN: example.com

workflow:
	rules:
		- if: '$DOMAIN == "example.com"'
		  when: always	# 預設always,可以設定never
		- when: never

14. cache

儲存編譯專案時所需的執行時依賴項,指定專案工作空間中需要在 job 之間快取的檔案或目錄

全域性 cache 定義在 job 之外,針對所有 job 生效,job 中的 cache 優於全域性

cache:
	paths:	# 在全域性定義快取
		- my/files

job:
	script: "..."
	cache:
		key: job	# 為快取設定唯一key,會為該job分配一個獨立的cache
		paths:	# 在job中定義快取,快取target目錄下的所有.jar檔案,該快取將覆蓋全域性快取
			- target/*.jar
		# policy: pull # pull:不下載快取,push不上傳快取,預設會在job執行之前下載快取,並在結束之後上傳快取

15. artifacts

用於指定作業成功或失敗時應附加到作業的檔案或目錄的列表,可在 Gitlab UI 中下載

build:
	script:
		- mvn package
	artifacts:
		name: "$ARTIFACTS_NAME"	# 指定所建立的製品名稱,預設為artifacts,下載為artifacts.zip
		paths:
			- target/*.jar
		when: always	# 製品建立條件,on_success:作業成功時創造製品,on_failure:作業失敗時建立製品,always:總是建立製品
		expire_in: 1 week	# 製品有效期,從儲存到gitlab開始算起,預設30天

16. dependencies

獲取當前階段之前的製品

build:
	stage: build
	script:
		- mvn package
	artifacts:
		name "$ARTIFACTS_NAME"
		paths: 
			- target/*.jar

deploy:
	dependencies:
		- build
	stage: deploy
	script: 
		- ...	# 部署製品

17. needs

可以讓作業無需按照階段順序執行,下述的例子表示:deploy-a 在 build-a 完成之後就可以執行,deploy-b 在 build-b 完成之後就可以執行

stages:
	- build
	- deploy
	
build-a:
	stage: build
	script: 
		- ...

build-b:
	stage: build
	script: 
		- ...
		
deploy-a:
	stage: deploy
	script:
		- ...
	needs: ["build-a"]

deploy-b:
	stage: deploy
	script:
		- ...
	needs: ["build-b"]

18. include

可以引入外部 yaml 檔案,使用合併功能可以自定義和覆蓋本地定義的 CI/CD 設定

local

引入同一儲存庫的檔案,使用相對於根目錄的完整路徑進行參照,必須保證走到同一分支

假設有 ci/localci.yml 檔案

stages:
	- deploy
	
deploy-job:
	stage: deploy
	script: ...

在 .gitlab-ci.yml 引入 ci/localci.yml 檔案,如果存在相同名稱的作業,它們的設定會進行合併,並且原檔案 .gitlab-ci.yml 的設定優先生效

include:
	local: "ci/localci.yaml"
	
stages:
	- build
	- test
	- deploy
	
build-job:
	stage: build
	script: ...

test-job:
	stage: test
	script: ...

file

引入其他專案的 yaml 設定

include:
	project: demo/demo-java-service
	ref: master
	file: .gitlab-ci.yml

template

引入官方提供的模板,可以存取 https://gitlab.com/gitlab-org/gitlab/tree/master/lib/gitlab/ci/templates 檢視有哪些模板

include:
	template: Auto-DevOps.gitlab-ci.yml

remote

引入遠端檔案

include:
	remote: "https://gitlab.com/awesome-project/raw/master/.gitlab-ci-template.yml"

19. extends

繼承作業設定,相同設定覆蓋,不同則繼承

.tests:
	script: mvn test
	stage: test
	only:
		refs:
			- tags

test-job:
	extends: .tests
	script: mvn clean test
	only:
		variables:
			- $RSPEC

最終得到的作業設定如下

test-job:
	stage: test
	script: mvn clean test
	only:
		variables:
			- $RSPEC
		refs:
			- tags

20. trigger

當 gitlab 從 trigger 定義建立的作業啟動時,將建立一個下游管道,允許建立多專案管道和子管道:

  • 多專案管道:跨多個專案設定流水線,以便一個專案的管道可以觸發另一個專案的管道

    stagging:
    	variables:
    		ENVIROMENT: stagging	# 該變數會傳遞給下游管道,如果上下游定義了相同名稱的變數,上游變數將優先
    	stage: deploy
    	trigger:
    		project: demo/demo-java-service	# 指定下游專案的完整路徑
    		branch: master	# 指定專案的分支名稱
    		strategy: depend	# 將自身狀態從觸發的管道合併到源作業
    
  • 父子管道:同一專案的管道可以觸發一組同時執行的子管道

    子管道 ci/child.yml

    stages:
    	- build
    
    child-build-job:
    	stage: build
    	script: ...
    

    父管道

    stages:
    	- deploy
    	
    stagging:
    	stage: deploy
    	trigger:
    		include: ci/child.yml
    		strategy: depend21
    

21. image

首先註冊一個工作型別為 docker 的 runner,只要使用該型別的 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 "docker" \
	--run-untagged="true" \
	--locked="false" \
	--access-level="not_protected"

預設註冊 runner 會指定一個基礎映象,如果全域性指定 image 則所有作業使用該映象建立容器並執行,如果全域性未指定 image,則檢視 job 中是否有指定,有則按照 job 指定的映象建立容器並執行,否則使用預設映象

image: maven:3.6.3-jdk-8	# 全域性定義

...

deploy-job:
	stage: deploy
	tags:
		- docker
	script: ...
	image: maven:3.6.3-jdk-8	# 區域性定義

22. services

工作期間執行的另一個 Docker 服務映象,將其 link 到 image 定義的 Docker 映象,這樣可以在構建期間存取該服務映象

...

services:
	- name: mysql:latest
	  alias: mysql

build-job:
	stage: build
	tags:
		- docker
	script: ...
	image: maven:3.6.3-jdk-8	# 區域性定義

23. environment

可用於在 gitlab ui 追蹤作業執行情況,

deploy-job:
	stage: deploy
	tags:
		- docker
	script: ...
	environment:
		name: production	# 應用名稱
		url: http://www.baidu.com	# 應用地址