有些時候在流水線上執行時間需要比較久的工作,如果可以分拆多個工作,讓他們同時進行,可以讓這系列的工作加速執行完成,但直接在 .gitlab-ci.yml
上分組為不同的工作,又可能在後期造成工作 script 維護上的困擾。那還有其他的參考方案嗎?
parallel
對 GitLab CI 工作進行分頁拆分在 GitLab CI 11.5 版後,推出了 parallel
參數,主要是協助建立參數,讓原本工作,可以拆為多個工作同時進行,那他是怎麼辦到的呢?在使用 parallel
的同時,當工作啟動的時候 GitLab CI 便會幫忙建立另外兩個環境變數,分別是 CI_NODE_INDEX
和 CI_NODE_TOTAL
這兩個預計給工作使用的環境變數 parallel
參數,便是透過這兩個環境變數與工作溝通,達到「分頁拆分」工作的效果。以底下簡單範例來說:
job:
image: ubuntu:20.04
parallel: 5
script:
- echo "parallel job ${CI_NODE_INDEX} And Total ${CI_NODE_TOTAL}"
上面的這個例子,設定了 parallel: 5
意思就是:「把這個工作拆分為五個子工作」同時進行,而透過 CI_NODE_TOTAL
環境變數當參數傳入到工作中,就像跟工作或執行的工具說:「幫我把工作拆成 5 份」,而 CI_NODE_INDEX
環境變數,當參數傳入到工作中,就類似跟執行的工具說:「這是這 5 份中的第幾份」。
其整體看起來,就像是把眼前的工作進行了「分頁拆分」作執行,例如單元測試,假設其中有 20 個測試案例,透過 CI_NODE_TOTAL
環境變數,決定將 20 個測試案例分頁拆分成 5 份,每一份執行 4 個測試案例,再透過 CI_NODE_INDEX
環境變數,來決定拆分後的工作是第幾份(第幾頁)工作。如上述範例的執行結果:
可以看到 GitLab CI 幫忙把原本的一個工作,拆解為 5 份,進入看其中的一份,可以看到畫面中顯示 parallel job 3 And Total 5
即代表著這是這五份中的第三份。
從上面的範例中得知,如果使用的工具或程式語言可以支援分頁拆分後平行化處理,那麼就可以透過 parallel
參數進行工作拆分,如官方手冊上 RoR 的例子 :
test:
parallel: 3
script:
- bundle
- bundle exec rspec_booster --job $CI_NODE_INDEX/$CI_NODE_TOTAL
就是透過CI_NODE_INDEX
和 CI_NODE_TOTAL
兩個環境變數,當參數傳入到 rspec_booster
之中,讓 RoR 的 RSpec 知道如何做工作分頁拆分。
透過 parallel
參數,可以幫助一個龐大的工作,如測試案例進行分頁拆分,讓可以拆分的工作們得以拆成多個工作而後並行處理,但必須要注意,拆分後的工作們,是否可以被同時進行?如果可以執行工作的 runner 數量不夠,則甚至可能造成執行速度比原本慢。
又,每個工作的「前置作業」準備時間,是否過長?如果原本一個工作的前置作業需要 50 秒,本體工作執行需要另外的 50 秒,總耗費可能是 100 秒,但將之拆解為 5 個工作平行執行後,每個工作本體工作執行時間可能只剩下 10 秒鐘,但因為前置作業一樣是各別花費 50 秒,單一個工作花費 60秒,整體也僅節省 40 秒。倘若這時候可同時執行的工作不到 5 個,分拆後的工作必須依序執行,那麼整體花費的時間就會比拆分之前還多,因此這部分也是不得不注意的地方。
接下來,將繼續討論更深入使用的工作平行處理,我是墨嗓(陳佑竹),期待這系列的文章能夠讓人有些幫助。