GitLab CI 之 Runner 的 Executor 該如何選擇?

使用者在初次踏進 GitLab CI 的世界時,通常按著官方文件一步步照做,多半不會遇到什麼問題。唯獨有一項東西有可能讓新手產生較大的疑惑,那就是該如何選擇 Executor。

目前在官方文件上已經有提供了一份 Compatibility chart 幫助使用者選擇 Executor。本文就讓艦長也針對 Executor 表達一些看法吧!

(本文同步發表於 Medium。)

GitLab Runner 與 Executor 的關係

首先,讓我們先來解釋 GitLab、GitLab Runner 與 Executor 的關係。

讓我們拆開來說明,先從 GitLab 與 GitLab Runner 的關係開始。

如上圖,我們都知道 GitLab Runner 是用來幫助我們執行 CI Job 的工人,而 GitLab 就是這些工人的老闆。老闆(GitLab)會去查看需求單(.gitlab-ci.yml)建立一張又一張有先後順序的工單(CI Pipeline),而每一位工人(Runner)則是每隔固定的時間就去詢問老闆(GitLab)現在有分配給自己的工作(CI Job)嗎?現在自己應該做哪一項工作?工人拿到工作後開始執行,並且在執行過程中將處理進度即時填寫在工單上。

到這裡為止,大部分的人都不太會有什麼問題,讓我們接著說明 GitLab Runner 與 Executor 的關係。

前面我們將 GitLab 與 GitLab Runner 比喻為老闆與工人,那麼 Executor 是什麼?是工人的工具嗎?艦長覺得與其說是「工具」,Executor 反倒更像是工人的「完成工作的方式」或「工作的環境」。

舉例來說,就像我們都曾聽過的都市傳說,據說在國外有某知名企業的工程師,偷偷將自己的程式開發工作遠距外包給印度工程師完成,藉此實現上班摸魚打混還能取得高績效表揚的神奇故事。當然偷偷把正職工作私下外包是不正確的行為,但在這個故事中,這就是這位工程師「完成工作的方式」;同理用嘴巴命令別人做事、自己苦力的土法煉鋼、善用自動化工具或高科技工具輔助、遠距連線工作⋯⋯這些都是不同的「完成工作的方式」。

按著上面的比喻,依據你選擇的 Executor 決定了 Runner 將會採用何種「方式」及在哪個「工作環境」來完成 CI Job。

因此我們可以明白,這意味著身為老闆的我們,很可能需要聘雇多位不一樣的工人。舉例來說,炒菜煮飯這種工作,我們就會安排給在廚房工作的廚師、闖入民宅開寶箱這種工作,我們就會安排給 RPG 遊戲中的勇者。根據不同的 CI Job,我們有可能需要準備設置了不同 Executor 的 Runner 來因應。

目前可選用的 Executor

了解 Runner 與 Executor 的關係後,接著來認識目前 GitLab Runner 可選擇的 Executor 有哪些。

【小提醒】目前 GitLab 官方已表示不會再增加更多的 Executor,並且為了保留彈性與擴充性,改為提供 Custom 這項 Executor,如果現有的 Executor 不能滿足你的需求,那就自己客制處理吧!

目前可選用的 Executor 如下:

  • Shell:即是 Runner 直接在自己的 Local 環境執行 CI Job,因此如果你的 CI Job 要執行各種指令,例如 make、npm、composer⋯⋯,則需要事先確定在此 Runner 的 Local 環境是否已具備執行 CI Job 所需的一切相依程式與套件。
  • SSH:Runner 會透過 SSH 連上目標主機,並且在目標主機上執行 CI Job。因此你要提供 Runner 足以 SSH 連線目標主機的帳號密碼或 SSH Key,也要提供足夠的使用者權限。當然目標主機上也要事先處理好執行 CI Job 所需的一切相依程式與套件。
  • Parallels:每次要執行 CI Job 時,Runner 會先透過 Parallels 建立一個乾淨的 VM,然後透過 SSH 登入此 VM 並在其中執行 CI Job。所以同樣的用來建立 VM 的 Image 是先要預備好執行 CI Job 所需的一切相依程式與套件,這樣 Runner 建立好的環境才能正確地執行 CI Job。另外,當然架設 Runner 的主機上,記得要安裝好 Parallels。
  • VirtualBox:同上,只是改成用 VirtualBox 建立乾淨的 VM。同樣架設 Runner 的主機上,記得要安裝好 VirtualBox。
  • Docker:Runner 會透過 Docker 建立乾淨的 Container,並且在 Container 內執行 CI Job。因此架設 Runner 的主機上,記得要安裝好 Docker,另外在規劃 CI Pipeline 時也要記得先準備能順利執行 CI Job 的各種 Docker image。在 CI Pipeline 中採用 Container 已是十分普遍的作法,建議大家可以優先評估 Docker executor 是否適合你的工作場景。
  • Docker Machine:延續上一個 Executor,此種 Executor 一樣會透過 Container 來執行 CI Job,但差別在於這次你原本的 Runner 將不再是一般的工人了,它已經搖身一變成為工頭,每當有工作(CI Job)分派下來,工頭就會去自行招募工人(auto-scaling)來執行工作。因此倘若在短時間內有大量的工作需要執行,工頭就會去招募大量的工人迅速的將工作們全數搞定。需要注意的是因為招募工人需要一些時間,故有時此種 Executor 在啟動時會需要多花費一些時間。
  • Kubernetes:延續前兩個與 Container 相關的 Executor,這次直接進入超級工頭 K8s 的世界。與前兩種 Executor 類似,但這次 Runner 操控的不是小小的 Docker engine 了,而是改為操控 K8s。此種 Executor 讓 Runner 可以透過 K8s API 控制分配給 Runner 使用的 K8s Cluster 相關資源。每當有 CI Job 指派給 Runner 時,Runner 就會透過 K8s 先建立一個乾淨的 Pod,接著在其中執行 CI Job。當然使用此種 Executor 依然記得先準備好能順利執行 CI Job 的各種 Container image。
  • Custom:如果上面這七種 Executor 都不能讓你滿意,那就只好請客官您自行動手啦!Custom Executor 即是 GitLab 提供給使用者自行客制 Executor 的管道。

該選擇哪一種 Executor?

簡單來說就是根據你的需要來選擇 Executor!(謎之音:艦長你這不是廢話嗎~)

如果你的團隊已經很熟悉 Container 技術,不論是開發、測試及 Production 環境都已全面擁抱 Container,那當然選擇 Docker executor 是再正常不過了。更不用說如果 Production 環境已經採用 K8s,那麼 CI/CD Pipeline 想必也離不開 K8s 的魔掌,Runner 勢必會選用 Kubernetes executor。(但還是別忘了凡事都有例外。)

假如只有開發環境擁抱 Container,但實際上測試機與 Production 環境還是採用實體伺服器或 VM,這時你可能就會準備多個 Runner 並搭配多種 Executor。例如 Build、Unit Testing 或某些自動化測試的 CI Job 讓 Docker executor 去處理;而像是 Performers testing 則用 VirtualBox executor 開一台乾淨的 VM 並部署程式來執行測試。

又或者,你的公司有非常多專案正在同步進行中,同時間需要執行的 CI Job 時多時少,那麼可以 auto-scaling 的 Docker Machine executor 也許會是一個可以考慮的選擇。事實上 gitlab.com 提供給大家免費使用的 Shared Runner,就有採用 Docker Machine executor。

再舉例,假如有某個 CI Job 只能在某台主機上執行,也許是為了搭配實體伺服器的某個硬體裝置、也許是基於安全性或憑證的緣故,在這種情況下很可能你會用到 SSH executor,或甚至是在該主機上安裝 Runner 並設定為 Shell executor,讓特定的 CI Job 只能在該 Runner 主機上執行。

最後,也有可能你因為剛好身處在一個完全沒有 Container 知識與技能的團隊,所以才只好選擇 Shell、SSH、VirtualBox 這些不需要碰到 Container 的 Executor。

【小提醒】由於 SSH、VirtualBox、Parallels 這三種 Executor,Runner 都是先連上別的主機或 VM 之後才執行 CI Job 的內容,因此都不能享受到 GitLab Runner 的 caching feature。

(官網文件也有特別提醒這件事。)

結語

GitLab Runner 及 Executor 與 CI/CD Pipeline 的規劃密切相關,在實務上我們經常會準備多種 Runner 因應不同的情境,也許是類似下面這樣常態準備 3 台 Runner。

  • Docker executor|供一般的 CI Job 使用。
  • Docker Machine executor|供 CI Job 大爆發塞車時使用。
  • SSH 或 Shell executor|供 Production Deploy 或某些有較高安全性考量的 CI Job 使用。

或者也有可能是 K8s + Kubernetes executor 打通關。

總之在規劃及處理 CI/CD Pipeline 時,我們無可避免的需要與整條軟體開發及軟體部署的流程打交道,並且深入其中處理各種相依關係。Runner 作為幫助我們自動執行 CI Job 的工人,我們理當要為它安排合適的工作方式與環境,讓它能順暢地完成交付給它的任務。

最後,如果你有興趣深入了解 GitLab Runner 到底是如何透過 Executor 完成工作,建議你可以嘗試客制自己的 Custom executor。客制 Executor 的過程,有助於你理解 Runner 在接手並執行 CI Job 時,會經歷哪些過程。

【補充】CI Job 會經歷 configprepareruncleanup 這四個階段,其實就是事前、事中、事後的概念,在 configprepare 準備好能夠執行 CI Job 的環境,run 實際執行 Job 內容,最後 cleanup 清除環境。

Executor 的介紹就到此告一個段落。文末艦長要再次工商呼籲一下,你也有負責規劃團隊的 CI Pipeline 嗎?你都是使用哪些 Executor?歡迎與我分享、或是來到 DevOps Taiwan Community 公開分享你的經驗喔。

如果你覺得艦長寫的文章對你有產生幫助,歡迎抖內(Donate)艦長,讓艦長可以將原本用來養家活口的餘力分一些投入在社群分享上。咦,你說網頁上沒看到任何類似 Buy Me a Coffee 的連結?那不妨買一本艦長的著作《和艦長一起 30 天玩轉 GitLab》,不只能抖內艦長,還可以一併支持出版社與圖書通路商,一次抖內一舉數得喔!

參考資料

更多文章