GitLab CI/CD課程28
Dynamic Versioning:
在當前的基本Pipeline設計中,我們是hard code方式寫死版本號TAG:
如果沒有人去更改,最後打包的image就會不斷地覆寫上次打包的image
所以這邊就要避免hard code版本號TAG這部分
最後當然是每次新版本佈署都是使用可以區分的版本號
這樣哪一版有異常時
就能夠很快決定退版到哪一個TAG版本號的IMAGE重新佈署
而當然這部分版號隨打包佈署遞增最好是自動化
Application Versioning in General:
可能每家公司企業乃至團隊都有不同做法
常見的方式就是像Maven的三碼語意化版本(Semantic Version)
第一碼(Major):如不兼容的API變更(例如置換Framework,較大功能新增)
第二碼(Minor):較小功能新增或是嚴重Bug修正
第三碼(Patch):小的功能調整或小Bug修正
而這些版本號通常都是由打包管理工具設定檔來定義或提供:
npm← →package.json
Maven← →pom.xml
Gradle← →build.gradle
以目前例子來說就是:
所以版本變更就要來改這個版本號例如1.0.0 →1.0.1
Read version from package.json:
所以現在這邊要做的就是在打包image過程中
從package.json中提取版號來用於打包image的tag使用
首先
然後在build_image這個Job內從package.json提取版號來用
#透過以下shell語法與jq工具來取提版號欄位:
cat app/package.json | jq -r .version
但是透過jq工具來截取json欄位,首先要在Runner上安裝該工具
#在Runner機台上安裝jq工具:
sudo apt-get install jq -y
簡單測試一下,直接vi一個package.json檔案貼入既有內容:
#執行以下指令看到版號:
cat package.json | jq -r .version
其他也可以:
在Pipeline腳本內的build_image這個job內就要把拿到的版號提出為變數
該Job變為如下:
此時Pipeline就不用在煩惱TAG要用的號碼了
Generate Unique Version Tag:
現在的困境在於,要有人去維護package.json上面的版本號
如果有人忘了更改package.json上面的版本號
那麼image包出來都是同一個TAG
所以要進一步讓image的TAG都是獨一無二的,簡單透過結合以下兩者:
package.json的版號 + GitLab預設的變數如下
在上面的"CI_PIPELINE_ID"則是GitLab instance層級唯一,應該不需要
所以在此,我們要設計的就是先簡化package.json的語意化版本
並且串接上"CI_PIPELINE_IID",所以:
Pipeline的build_image這個Job改為:
即便有人忘了改package.json的版號,最後image組合的tag也會數字增加
Use artifacts in other jobs:
在上面完成的修改後,已在打包image階段,打好了可用的TAG
但是這邊會有一個問題
就是VERSION這個變數只會存在於build_image這個Job內
但是在push_image這個Job的階段也會需要用到這個VERSION變數
這就是前面學到的,每個Job的執行都是在一個全新的環境下!
自然拿不到前一個Job定義的環境變數
當然這邊也可以讓push_image這個Job用一樣方式取得
但是這樣有點重工
此時就要引用"Job Artifacts",也就是前面做過的輸出測試報告
最後傳回給GitLab,並提供於Web介面上下載該報告
而這也是拿來在Jobs間傳遞變數的可用方式
也就是說要在build_image這個Job產變數檔
然後在push_image這個Job內讀取上述變數檔
這邊要特別提醒一個過程:
當build_image這個Job完成時候
version-file.txt檔案會先上傳給Gitlab Server本身,接著才傳給後續Job使用
所以在push_image這個Job新增以下
但是這邊會有個問題產生
預設情況下,GitLab Job產出的artifact的檔案
會被下一個"Stage"的Jobs下載使用
也就是說現在build_image這個Job產出的version-file.txt檔案
只會被"deploy stage"的deploy_to_dev這個Job拿到!
也就是現在問題在於
build_image這個Job跟push_image這個Job都在同stage內
push_image這個Job會拿不到檔案
所以當同一個stage內的後一個Job要拿到前一個Job產出的檔案時
需要 →"dependencies",裡面可以定義一個Jobs集合拿取其artifacts
再次調整push_image這個Job為:
如上,就看到needs與dependencies兩兩成對
但是needs是為了stage內不同Jobs的順序性
前一個Job要結束才能執行該Job
另外還有一個重點要提及的是"dependencies"是相依於"needs"
例如:
這樣才可以:
另外可能是新版的關係,現在"needs",將自動包含"dependencies"功能
所以可以簡化:
接著還有效率上的疑慮是如果某個Job產出的artifact檔案超大或太多份
但是後續的Job可能根本不需要的情況!?
比如在deploy之後可能新增一個測試的Job
就可以用下面方式避免下載該artifact:
這樣也可以加速流程進行
當然這邊也可以拿取前面測試的報告:
不過上面只是演示,這段Code會移除不做
接著調整deploy_to_dev這個Job
如上面解釋,這個必然拿到剛剛版本的變數檔的artifact了!
所以現階段完整pipeline如下:
Commit上述Pipeline後看看結果:
來到以下位置看看image:
那個80對應到Pipeline的:
網站貓貓一樣還在:
另外在push_image這個Job的log可以看到下載artifact動作:
Pass Env Vars as Dotenv Artifact:
首先簡單解釋Dotenv檔案是輕量化的npm package
可以自動從.env檔案載入環境變數
但是每一行只能定義一個變數,並且格式是key=value形式
所以build_image這個Job可以調整為:
上面那個第二行echo給build.env只是示範打的,等等會拿掉
如上最後包成artifacts →reports →dotenv屬性
當build_image這個Job進行上述調整後
會多一個功能是
後面的Job會自動引入那些變數為環境變數!
也就是:
這時候還要重提一個部分就是前面提到的
"needs"與"dependencies"這兩個屬性也可以拿來控制dotenv內的環境變數!
此時完整的Pipeline為:
上述Pipeline Commit後等一陣子看到:
在push_image這個Job的log內看到: