GitLab CI/CD課程29

Configure Caching to speed up Pipeline execution

ZONGRU Li
9 min readAug 18, 2022

回顧一個概念,每一個Job的執行都是在各自的isolated環境

並且每個Job都是全新的環境

  • 所以不同Jobs間不會互相影響
  • 比較不會有無法預期的side-effects

但是我們往往在不同Jobs執行時需要相同的檔案

其中一個滿足上述需求的功能就是前面學的 — Artifact

Artifact

Artifact:

  • 保留Job執行後所得的artifact(成品)並在Pipeline結束後提供到GitLab UI
像是這邊也可以下載
  • 並且也可以在不同Jobs間傳遞artifact

但是考慮到目前有以下這段寫法:

每次執行到run_unit_tests這個Job都會跑一堆npm安裝

而這個安裝是會去網路上下載必要套件

就猶如Mavendependency一樣

考量到假若又有另一個Job比如名稱叫run_code_analysis

並假設裡面也要執行npm安裝後才能做一些測試

那麼這個Job內就又要真的重做下載安裝的動作

也就是都在做很重複的下載動作,並且載相同的東西,卻無法重複利用

尤其是這些第三方套件library

並且浪費大量的時間( →slow down CICD pipeline)

所以前面學到的 →Artifact則解決了不同Jobs間這類重複下載的問題

Artifact透過Runner把檔案交給GitLab Server在轉交給下一個Runner方式

但是若是不同次執行的Pipelines間也有這樣的需求!?

甚至現在像是dependency的檔案數量極為龐大

很難像Artifact轉傳方式處理

Cache

Pipeline#1執行已經下載的東西,在Pipeline#2希望就不用重複下載

這時候就要引入 →Cache

Caching re-use between in pipeline run:

  • 加速pipeline執行
  • 減少CI的花費

Artifacts VS Cache

Artifacts:

  • Job Artfact上傳保留在GitLab Server
  • 常用來在不同Stages間轉傳build過程中的結果

Cache:

  • 通常用於dependencies,像是打包時常常去網路上下載的套件
  • Cache的檔案是保留在GitLab Runner上面
  • 但有一個前提是剛好Job跑在同一台Runner,才有re-use
  • 因為這些Cache是保留在RunnerServer

Distributed Cache

Distributed Cache:

  • 好處:中心管理Cache storage
  • 壞處:但是會多出要向遠端storage下載的部分,但是還是比從網路上下載快得多
  • 好處:下載1zip還是比分別下載多個dependency

Configure a Cache

  • 用"cache" attribute.gitlab_ci.yml檔案內定義
  • 其中要給定"cache key"

cache key:

  • 每個cache的獨一無二的id key
  • 如果沒給,預設是會叫"default"
  • 所有Jobs透過相同的cache key來使用相同的cache

Common Naming of Cache Keys:

  • 依據環境Branch來分,像是(cache_main,cache_dev)
  • 也就是可能會需要動態地依據branch定義不同cache
  • 所以需要另外引用到以下GitLab自帶的變數:
LINK

並指定要保留為cache的方式是可以用paths,寫法如下:

上述app/node_modules就是npm install後會長出來的套件

以上寫法可以完成兩個目的:

  • 產生cache
  • 或下載cache

在第一次執行該Pipeline#1時經過這段流程,會產出cache

在到第二次執行Pipeline#2經過這段流程,會下載cache

這誕生一個名詞 →pull-push policy(一種Cache Policies)

pull-push policy:

  • Job開始的時候下載cache,並且在Job結束後上傳變更的cache

如上設定下

run_unit_tests這個Job載執行開始的時候會下載cache

run_unit_tests這個Job載執行結束的時候會上傳cache內容異動的部分

並且這個policydefault的,所以可以省略:

這邊課程講師為了demo用途,額外加入一個job →run_lint_checks

引用"Linting"這個靜態程式碼分析工具,查找程式中的錯誤:

並且跟run_unit_tests都在相同stage內,沒有needs來分順序

這時候會有一個嚴重問題:

也就是storage會同時被不同process更新

所以這時候我們會要求其中一個Job針對storageread only

這時候就要這樣改:

pull policy:

  • 只下載,不上傳
  • 特別適合在很多併發平行處理的Jobs上使用
  • 加速job執行的同時
  • 也減少Cache Serverloading

反過來說還有另一個policy就是push policy

這也是很多人會把這個獨立寫成單一個Job:

這個只是展示,這段等等會移除

push policy:

  • 專門用來建置cacheJob
  • 只上傳,不下載

另外要提醒,即便有獨立的push的Job或是其他別的Job建立了cache

需要相關套件的Job仍然需要執行"npm install"

Best Practice →保留如npm install:

  • 不應該依賴Cache!
  • Cache只是拿來優化,但無法保證都充足來執行Job內容
  • 也就是Pipeline設計要考慮當沒有cache時(甚至拿不到)
  • 也要仍可以正常運作(只是慢一點)

Configure Volume for Docker Executor

還有一個關於Cache使用上的問題是我們有用到:

也就是docker container的部分

當同時使用cache時,這些cache內容會建立在Container

想當然爾,隨著Container消失,而不像Shell Runner那樣保留在Server

其中設定要到該docker機台(Runner)上找到:

/etc/gitlab-runner/config.toml

root身分編輯其內容:

這邊只要新增一行實體路徑就好:

儲存!

當前的Pipeline內容為:

Commit後執行看看結果:

run_unit_tests部分:

run_unit_tests
run_unit_tests

接著看看另一個新增的Job run_lint_checks

接著仔細看看:

接著手動讓這個Pipeline重跑,看到:

變快了!

Clearing the Cache

這邊先移除上面demo用的run_lint_checks這個Job

若有需求要清空Cache則有兩種方式:

1.按按鈕:

但是上述這個紐按了以後,舊的Cache實體檔其實還會在

而實體的Cache名稱會變新的

真的要清除還是要手動進到Runner storage內移除

這邊試著按下去,然後把移除了run_lint_checks這個jobpipeline重新執行

所以舊的cache還在,新的cache名稱會有一個index方式變化

main-X-protected

講師畫面是:

main-X

Where the caches are stored

#查找docker綁定的volume:
docker volume ls
docker volume inspect {volume name}
#找到mount目錄後可以找到:
{mount目錄}/{帳號名}/{程式專案名}底下

其中一個裡面長這樣:

是個zip檔!

另外Shelldocker Executor綁的位置可能不一樣

可以去文件查看:

LINK

目前Pipeline內容為:

參考課程(reference)

--

--

ZONGRU Li
ZONGRU Li

Written by ZONGRU Li

2022/11/17 開源部分個人筆記給LINE "Java程式語言討論區"社群,希望能對社群的技術學習做一點點貢獻.(掩面....記得退訂閱!

No responses yet