“微服務”這個概念近兩年非常熱,正在慢慢改變 DevOps 的思路。微服務架構把一個龐大的業務系統拆解開來,每一個組件變得更加獨立自治、松耦合。但是,同時也伴隨着部署單元粒度越來越小,對交付效率要求也越來越高。一套高效、靈活、高可用的 CI/CD 系統就很關鍵。所以說 CI/CD 是微服務架構下必不可少的一部分。
這方面有很多的開源項目和工具,比如 Jenkins、Github 默認支持的 Travis 以及本文主要介紹的GitLab CI。
那么“當談到 GitLab CI 的時候,我們都該聊些什么?”
什么是 GitLab WorkFlow
本章主要講了 GitLab WorkFlow 從研發到發布交付的一個流程,介紹 CI/CD 所做的事情。
圖1
圖 1 來自 GitLab 官方文檔,可以讓我們更加方便的了解 CI/CD 做了哪些事情。
從左往右看,首先研發人員完成需求提交代碼到 GitLab。GitLab 觸發一次 Build,構建好服務,然后開始跑單元測試、集成測試。等待測試結果通過后,再由負責該項目的同事進行 CodeReview,灰度發布,正式部署到線上。CI/CD 就是指測試和發布環節,如果能夠做到自動化,那么就可以大大加快開發迭代的速度。
如何配置 GitLab Runner 如何把項目接入 CI
GitLab CI 相關術語
在介紹 GitLab 之前,先介紹一下本文主要涉及到術語。
- Job/Build,它是最小的任務單元,只負責一件事情,要么編譯,要么測試等;
- Stage,階段,每一個 Job 都會有一個階段,一個階段可以包含多個 Job。階段是有先后順序的。通過 stage 可以間接的控制 Job 執行的先后順序;
- Pipeline,多個 Stage 有順序的排列就是 Pipeline,流水線;
- GitLab Runner,是實際處理 Job 的,每個 Runner 可以單獨配置,Runner 支持多種類型的 Job,同一時間單個 runner 只能處理一個 Job;
- GitLab Multi Runner,是一個 GitLab 的開源項目,用來統一管理 Runner;
- Executor,每個 Runner 都需要指定一個 Executor,來決定 runner 最終使用哪個執行器進行處理。
圖2
圖 2 是一個典型的 Pipeline,一共有 5 個階段,Build,Test,Release, Staging, Production,每個階段里都至少有一個 Job,Test 中有兩個 Job。GitLab 會從左往右依次把任務給到 Runner 處理,如果中途有一個任務沒有處理成功的話,整個 Pipeline 就會退出。這就是持續集成(CI)、持續發布(CD) 的一個流程。
如何使用 GitLab CI
注冊 Runner
圖3
GitLab 中提供了兩種 Runner 的類型,圖 3 這個界面可以在 GitLab 項目設置頁中找到的,一個是特定的 Specific Runner,另一個是共享的 Shared Runner 。特定的 Runner 只能供部分項目使用,而共享的 Runner 是所有 GitLab 中的項目都可以使用的。而這兩種類型的 Runner 的注冊方式都是一樣。
從注冊一個特定的 Runner 開始講,首先安裝一個 GitLab Mutli Runner,因為是 Go 語言實現的,所以安裝起來會比較簡單,直接采用二進制安裝即可。第二步正式開始注冊,輸入 Gitlab 地址、token、描述、標簽執行器等。輸入上述數據之后 Runner 就注冊好了,由於 Multi Runner 支持動態加載配置,所以 Runner 就立即生效了。可以在剛才的界面中看到新增了一個 Runner。有了 Runner,第二步就是如何在項目中增加 .gitlab-ci.yml 的 CI 配置文件。
在項目中增加 .gitlab-ci.yml 的 CI 配置文件
圖 4
上文所示是一個非常簡單的 CI 配置文件。定義了兩個階段,一個 test,一個 build,先執行 test 再執行 build,test 階段有一個 job 叫做 test,執行的指令是 echo skip,但是這個 job 需要跑在帶有 opentalk 的這個標簽的 runner 上。build 階段也有一個 job,叫做 build,它會執行 make docker,去構建 docker 鏡像並且推送到私有倉庫中,這個任務只有當分支中有 tag 提交才會觸發,並且需要跑在帶有 online docker builder 的 runner 上。寫好這樣一個 gitlab-ci.yml 后,commit 一下提交到 Gitlab,你就可以看到 CI/CD 頁面(圖4)中增加一條正在跑的任務。
圖 5
接下來看看 GitLab Runner 的內部實現是怎樣的?
GitLab Runner 的實現細節
本章主要分析了 GitLab CI 跟 Runner 信息交互的過程。
圖 6
從圖 6 可以看出 GitLab CI 是這樣一個結構,最上面 GitLab 服務,負責托管代碼,支配分解 Job。下面幾個是 GitLabMultiRunner,由於支持多操作系統環境,所以圖 6 中都加了標注,每一個 GitLabMultiRunner 可以配置多個 GitLab Runner,GitLab Runner 直接跟 GitLab 做交互,這一層通信是通過 HTTP 協議實現的,之后也會講到。另外有些同學可能已經注意到了,圖中 GitLab 是部署在公網上的,而 GitLab Runner 則是在 Nat 之下的,這個設計非常友好,不需要把 GitLab Runner 跟 GitLab 部署在一起,GitLab Runner 甚至可以在自己的筆記本上。
當我們看完了 GitLab CI 的整體結構后,再看看 Runner 跟 GitLab 之間的信息交互是怎樣的?
Runner 跟 GitLab 之間的信息交互是怎樣的?
信息交互分為幾個部分,第一個部分是 Runner 注冊。
圖 7
Runner 會向 GitLab 發送一個注冊請求,請求內容中包含 token、 tag 等重要信息,這些其實都是之前配置的時候需要填寫的, GitLab 接收一個注冊請求之后就會返回一個 token 給 Runner,Runner 之后的請求中都會帶上這個 token。
圖 8
在收到 GitLab 注冊成功的消息之后,Runner 就會不停的向 GitLab 請求 Job,時間間隔是 3s。可以看到請求中的 token 已經改成注冊時 GitLab 返回的 token 了。
這時會有兩種情況:
第一種是沒有任務,GitLab 返回 204 No Content;
圖 9
第二種情況是有任務,GitLab 會把任務信息返回回來,包括任務的 token,job_info,git_info,runner_info 等等。Runner 在接收到 Job 之后,就會向 GitLab 發送一個確認請求,同時更新任務的狀態。發送完這個請求,Runner 就開始正式跑任務了。Runner 會定時的發送輸出的中間數據,通過向 GitLab 發 Patch 請求的方式。
圖 10
等任務處理完后,Runner 會發送最終結果、狀態、日志等。
圖 11
最后總結下,第一個注冊 Runner,注冊成功后 3s 定時請求 Job,接收到 Job 之后發送確認請求,然后開始運行任務,定時把中間結果輸出給 GitLab,等任務處理完了,把結果發送給 GitLab。上述內容就是 Runner 跟 GitLab 之間的信息交互流程。
現在 Runner 已經從 GitLab 獲取到了任務,下一步 Runner 是怎么做的呢,Executor 又是怎么實現?下篇《當談到 GitLab CI 的時候,我們都在聊些什么》將會重點為大家介紹 Docker Executor 的實現細節。
更多閱讀: