別怕!.gitlab-ci.yml 勇敢寫下去!
身為一個研發人,我有著閱讀官方文件的習慣,但當我打開了 GitLab CI/CD 的官方文件後...
好的,資訊量爆炸!!!
我始終堅信著,每個研發人都應該要有的信念:
科技應要讓使用者專注在心中想解決的問題,而不是在處理使用該科技所碰到的問題。
by Arren Ping
同樣地,我對 GitLab CI/CD 的期望亦是如此。不過,本來也清楚 CI/CD 不是件簡單的事情,文件數量多,反而是好事,不怕碰到困難解不了。
我這麼說服自己,研發人的心臟很強健,不屈不撓,勇敢向前,沒在怕的!
多看了幾份文件後,我理解到,GitLab CI/CD 是透過設定在專案根目錄底下的 .gitlab-ci.yml
這個檔案來驅動,而在經歷了多次的改版,已經有了很多方便使用的措施,其中一個就是 範本,對初學者來說真的是大大大大大......幫助!
找不到的捧油請在專案首頁尋找一個叫做 "Set up CI/CD" 的功能,勇敢地按下去,就會出現可以編輯 .gitlab-ci.yml
的界面,裡頭就有範本可以選。
我所需要的 maven
的範本自然也被包括在內,如下:
# This file is a template, and might need editing before it works on your project.
# Build JAVA applications using Apache Maven (http://maven.apache.org)
# For docker image tags see https://hub.docker.com/_/maven/
#
# For general lifecycle information see https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
# This template will build and test your projects
# * Caches downloaded dependencies and plugins between invocation.
# * Verify but don't deploy merge requests.
# * Deploy built artifacts from master branch only.
variables:
# This will suppress any download for dependencies and plugins or upload messages which would clutter the console log.
# `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work.
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
# As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used
# when running from the command line.
# `installAtEnd` and `deployAtEnd` are only effective with recent version of the corresponding plugins.
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
# This template uses jdk8 for verifying and deploying images
image: maven:3.3.9-jdk-8
# Cache downloaded dependencies and plugins between builds.
# To keep cache across branches add 'key: "$CI_JOB_NAME"'
cache:
paths:
- .m2/repository
# For merge requests do not `deploy` but only run `verify`.
# See https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
.verify: &verify
stage: test
script:
- 'mvn $MAVEN_CLI_OPTS verify'
except:
- master
# Verify merge requests using JDK8
verify:jdk8:
<<: *verify
# To deploy packages from CI, create a ci_settings.xml file
# For deploying packages to GitLab's Maven Repository: See https://docs.gitlab.com/ee/user/project/packages/maven_repository.html#creating-maven-packages-with-gitlab-cicd for more details.
# Please note: The GitLab Maven Repository is currently only available in GitLab Premium / Ultimate.
# For `master` branch run `mvn deploy` automatically.
deploy:jdk8:
stage: deploy
script:
- if [ ! -f ci_settings.xml ];
then echo "CI settings missing\! If deploying to GitLab Maven Repository, please see https://docs.gitlab.com/ee/user/project/packages/maven_repository.html#creating-maven-packages-with-gitlab-cicd for instructions.";
fi
- 'mvn $MAVEN_CLI_OPTS deploy -s ci_settings.xml'
only:
- master
我想,或許不少人跟我一樣看到範本後呈現呆滯狀(汗~
碰到困難就想辦法解決
面對這種狀況,我的做法是:
- 不要心生恐懼
- 思考自己期望達成的效果
- 勇敢再看一次
身為一個 CI/CD 的初心者,我想要的效果其實很簡單,在每次 merge 之後只要有人能幫我打包好,讓我能方便的下載包好的結果就好了!
這個幫忙打包的人,我希望是 GitLab CI/CD。(其實不要是我就可以,是誰做我都 OK!溜~
CI 就是持續地整合,打包就是其中一個過程;CD 就是持續地部署,打包的結果被放置到特定的位置,就是部署的一種形式。
先講個題外話,原本在我的想像裡,我以為 GitLab CI/CD 會嚴謹的定義 CI 與 CD 的每個步驟,以及在每個步驟中可以做的事情,最好是提供了種種的外掛可以讓使用者開心地挑選、使用,然後 Just Work!!!在我充分瞭解之後,以上純屬想像,不是 GitLab 的做法。
GitLab 提供的方案一樣是 Just Work,但有哪些步驟及步驟中該做哪些事情的決定權,完全交給了 Developer 本人,給了開發者最大的彈性可自由揮灑,擁有無限多種可能!是的,只要寫好自己想要的 .gitlab-ci.yml
就可以!
發揮研發人的想像力
回過頭來看範本的結構,可以發現 .gitlab-ci.yml
中有縮排,有些詞帶有 :
結尾,我們先從第一級(無縮排)的這些詞開始看:
- variables
- image
- cache
- .verify
- verify:jdk8
- deploy:jdk8
發揮想像力的時間到了,來猜猜這些詞的用途或目的是什麼:
- variables => 應該是宣告變數吧
- image => 感覺在 GitLab 這種純 command line 的執行環境裡一定不是影像,應該是指映像檔
- cache => 快取,跑不掉了
- .verify => 唔... 前面有個點,是什麼鬼,跳過
(逃~
- verify:jdk8 => 驗證 JDK 8??
- deploy:jdk8 => 部署 JDK 8??
接著,我們依照前面的做法補上第二級:
- variables => 應該是宣告變數吧
- MAVEN_OPTS:
- MAVEN_CLI_OPTS:
- image => 感覺在 GitLab 這種純 command line 的執行環境裡一定不是影像,應該是指映像檔
- cache => 快取,跑不掉了
- paths
- .verify => 唔... 前面有個點,是什麼鬼,跳過
(逃~
- stage
- script
- except
- verify:jdk8 => 驗證 JDK 8??
- <<
- deploy:jdk8 => 部署 JDK 8??
- stage
- script
- only
好的,一樣,有 耐心 地發揮想像力,但請將第一級的推測也加入一起考慮,來理解第二級可能的意思:
- variables => 應該是宣告變數吧
- MAVEN_OPTS => 這個名稱和 maven 定義的環境變數相同,應該就是給 maven 使用的設定值
- MAVEN_CLI_OPTS => 有個 CLI 感覺像是執行時期使用的
- image => 感覺在 GitLab 這種純 command line 的執行環境裡一定不是影像,應該是指映像檔
- cache => 快取,跑不掉了
- paths => 路徑,應該是快取資料的來源位置,或者是要把快取資料存放的位置
- .verify => 唔... 前面有個點,是什麼鬼,跳過
(逃~
- stage => 絕對不是舞台
(溜~
,應該是階段吧! - script => 要執行的 script
- except => 要排除什麼東西??
- stage => 絕對不是舞台
- verify:jdk8 => 驗證 JDK 8??
- << => 迷樣符號,跳過
(逃~
- << => 迷樣符號,跳過
- deploy:jdk8 => 部署 JDK 8??
- stage => 第二次出現,應該是階段!
- script => 要執行的 script
- only => 只能有什麼東西??
當這些推測都做完了之後,我們可以開始看解釋 .gitlab-ci.yml
的官方文件了,請參考這份 GitLab CI/CD Pipeline Configuration Reference。
有些人喜歡從上到下閱讀整份文件,而我的習慣是,部分理解後若有必要再補全整體知識,所以,我先從關鍵字下手!
確立正確的知識
關鍵字理解了之後,再重新更新一次:
- variables => 宣告變數
- MAVEN_OPTS => 給 maven 環境使用的設定值
- MAVEN_CLI_OPTS => 使用者定義的變數,在 script 期間可以選擇代入使用
- image => 指定要使用的 docker 映像檔,映像檔可以在 Dock Hub 上找
- cache => 設定要使用快取
- paths => 快取的路徑,要被快取的資料來源路徑
- .verify => 自訂的 anchors,在執行時期時,會將引用此 anchors 的位置替換為 anchors 宣告的內容
- stage => 執行階段
- script => 要執行的 script
- except => 在哪些情況下不執行
- verify:jdk8 => 不是保留字,是個使用者自訂的 job。配合註解來看,應該是想要採用 jdk8 執行 maven 的驗證工作
- << => 引用 anchors
- deploy:jdk8 => 不是保留字,是個使用者自訂的 job。配合註解來看,應該是想要採用 jdk8 執行 maven 的驗證工作
- stage => 執行階段
- script => 要執行的 script
- only => 只在哪些情況下執行
至此,整個輪廓變得清晰了許多,要特別提醒 務必理解 幾個我覺得最重要的問題:
- stage 是什麼?
- stage 是怎麼定義的?
- job 是做什麼用的?
- 為什麼需要 cache?
stage 是什麼?
- stage 是工作階段
- 一個 stage 中可以包含多個 job,job 的執行不保證順序
- stage 之間是有順序相依的,必須確保前一個 stage 完成後,才會執行下一個 stage
- 一般情況下 stage 中的 job 都必須正確無誤完成後,才能執行下一個 stage
stage 是怎麼定義的?
- 在使用者沒有定義的情況下,預設提供三個 stage => build、test 和 deploy
- 使用者可以透過
stages
定義自己想要的階段及順序
stages:
- build
- test
- deploy
job 是做什麼用的?
- job 定義了要完成的工作
- GitLab CI/CD 會安排 Runner 也就是派遣工來承接 job,依照 job 中的定義來執行工作
- GitLab CI/CD 的派遣工有個缺點 => 有失憶症,就算來幫忙執行 job 的是同一人,他也完全不記得之前做過些什麼
- 就算是被歸類為同一個 stage 的 job,也不保證誰先執行、誰後執行,彼此之間也互不認識
為什麼需要 cache?
- 其實沒有 cache 也可以,有了或許可以加速 job 的執行速度
- 有些工作需要一些資源才能執行,例如:相依的函式庫,但因為派遣工每次都會失憶症發作,在沒有設定 cache 的情況下,就會重新獲取所有需要的資源,這樣很慢且很貴(Runner 若非開放原始碼專案是有總執行時間上限的),設定了 cache 後,就可以避免這個問題,而是直接從 cache 中取得
回歸需求,大膽執行!
現階段我的需求是 => 在每次 merge 之後只要有人能幫我打包好,讓我能方便的下載包好的結果。
換言之,
- 不需要測試
- 因為我已經人工本地測完了
- 沒有特殊的部署
- 沒有要發佈到 production 環境的需求
- 也沒有要版本庫
- 只要能有個地方下載檔案就好
- 別忘了,是用 maven + JDK 11
基於以上,第一版 .gitlab-ci.yml
如下:
# 請上 Docker Hub 找適合自己的
image: maven:3.6.3-jdk-11
stages:
- build
# 完全引用 template 中的設定
variables:
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
build:
stage: build
only:
- master
script:
- mvn $MAVEN_CLI_OPTS package
# 產生出的成果會被保留供下載
artifacts:
# GitLab 提供的環境變數,意思是產生出的成果下載時的檔名將會是專案名稱
name: "$CI_PROJECT_TITLE"
# 要保留哪些成果的路徑
paths:
- target/*.jar
做到這只差最後一步 => 請勇敢的將 .gitlab-ci.yml
commit & push!
真的完全不需要擔心,GitLab CI/CD 會先驗證檔案的正確性,且 Runner 並不會因為這樣就壞掉。
頂多只是 job 有誤,流程沒有成功跑完而已。
所以,
恭喜跨出了 GitLab CI/CD 的第一步,請愉悅地享受 CI/CD 的效果及成就感吧!