CI(持續整合)指開發人員一天內進行多次合併和提交程式碼操作,並通過自動化測試,完成構建
CD(持續部署)指每次程式碼更改都會自動部署到對應環境
CI/CD 結合在一起,可以加快開發團隊交付成果的效率,減少時間成本
gitlab-ci 是 gitlab8.0 之後自帶的一個持續整合系統,中心思想是每一次 push 到 gitlab 就會觸發一次指令碼執行,指令碼內容包括測試、編譯、部署等一系列內容
gitlab-ci 的指令碼需要 gitlab-runner 來執行,程式碼 push 之後,webhook 檢查到程式碼變化,就會觸發 gitlab-ci,分配到各個 Runner 來執行相應的指令碼
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 操作這裡就不贅述了
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
下面以 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
首先獲取 gitlab-ci 的 token:專案主頁->Setting->CI/CD->Runners Expand
使用命令註冊 gitlab-runner
gitlab-runner register
按照步驟輸入:
完成以後,重新整理頁面,即可在 Runners Expand 看到新增了一個 Runner
下面我們簡單測試一下 Runner 是否能正常執行,隨意新建一個 SpringBoot 專案
在根目錄下建立一個 .gitlab-ci.yml 檔案,這裡只是簡單輸出一段語句
stages:
- deploy
deploy-job:
tags:
- prod
stage: deploy
script:
- echo "hello world!!!"
push 到 gitlab 後,會發現指令碼已經自動執行了,綠勾代表執行成功
點選綠勾,在下方 Pipeline 點選 deploy-job 可以檢視執行過程
.gitlab-ci.yml 檔案中可以定義一個或多個作業(job),每個作業獨立執行,必須有唯一的名稱(不能使用關鍵字)以及包含一個 script,這裡定義了三個作業 build、test、deploy,script 可以是 shell 命令
build:
script:
- echo "build"
test:
script:
- echo "test"
deploy:
script:
- echo "deploy"
- echo "finish"
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"
用於定義作業可以使用的階段,並且是全域性定義的,同一階段的作業並行執行,不同階段按順序執行
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"
.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"
定義變數,可以定義 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"
用於指定特定的 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"
allow_failure 表示是否允許作業失敗,預設值 false 不允許失敗,改為 true 後,如果該作業失敗也不會被阻塞
job1:
stage: test
script:
- "..."
allow_failure: true
when 用於控制作業執行:
job1:
stage: test
script:
- "..."
when: delayed # 表示延遲30s執行
start_in: "30"
設定作業失敗後重試作業的次數
job1:
stage: test
script:
- "..."
retry: 2
也可以精確匹配到某一錯誤,即出現某一錯誤時才重試
job1:
stage: test
script:
- "..."
retry:
max: 2
when:
- script_failure # 指令碼失敗時重試
作業級別的超時可以超過專案級別的超時,但不能超過 Runner 特定的超時
job1:
stage: test
script:
- "..."
timeout: 3h
設定要並行執行的作業的範例數,此值必須大於等於 2 並小於等於 50,這將建立 N 個並行執行的同一作業範例
job1:
stage: test
script:
- "..."
parallel: 5
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
workfolw 關鍵字適用於整個管道,並確定是否建立管道
variables:
DOMAIN: example.com
workflow:
rules:
- if: '$DOMAIN == "example.com"'
when: always # 預設always,可以設定never
- when: never
儲存編譯專案時所需的執行時依賴項,指定專案工作空間中需要在 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執行之前下載快取,並在結束之後上傳快取
用於指定作業成功或失敗時應附加到作業的檔案或目錄的列表,可在 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天
獲取當前階段之前的製品
build:
stage: build
script:
- mvn package
artifacts:
name "$ARTIFACTS_NAME"
paths:
- target/*.jar
deploy:
dependencies:
- build
stage: deploy
script:
- ... # 部署製品
可以讓作業無需按照階段順序執行,下述的例子表示: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"]
可以引入外部 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"
繼承作業設定,相同設定覆蓋,不同則繼承
.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
當 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
首先註冊一個工作型別為 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 # 區域性定義
工作期間執行的另一個 Docker 服務映象,將其 link 到 image 定義的 Docker 映象,這樣可以在構建期間存取該服務映象
...
services:
- name: mysql:latest
alias: mysql
build-job:
stage: build
tags:
- docker
script: ...
image: maven:3.6.3-jdk-8 # 區域性定義
可用於在 gitlab ui 追蹤作業執行情況,
deploy-job:
stage: deploy
tags:
- docker
script: ...
environment:
name: production # 應用名稱
url: http://www.baidu.com # 應用地址