網易CI/CD實踐(上):CI系統的技術選型與部署流程

雲計算的普及,不僅改變了目前的IT基礎設施與企業系統架構,同時也改變了技術團隊的組織架構和企業內部的研發流程。而持續集成(CI)和持續交付(CD)就是企業內部研發流程提升交付效率的關鍵。

CI/CD的核心價值是效能與質量。效能提升的關鍵在於自動化,它包含了兩個方面:一是整個軟件研發流程自動化,降低人力成本;二是CI/CD平臺在業務接入、資源管理、線上支持、問題排查等諸多方面實現自動化,從而減少技術支撐方面的成本。而質量保障,一方面是研發質量,需要提供相應的質量檢查與測試工具;另一方面是過程質量,CI/CD平臺需要能夠持續採集研發流程中的指標數據(如交付頻率、交付週期、交付成功率),建立起一個完善的質量度量體系。

目前各大公司的CI/CD平臺,在工具選型、落地實現等方面各有不同,此次InfoQ採訪到了網易杭州研究院高級產品開發工程師汪燦豐和高級服務端開發工程師梅光輝,他們分享了網易輕舟在CI/CD方面的實踐。由於乾貨內容太多,我們將這次實踐分爲了上中下三篇內容,分別介紹網易的CI實踐、CD實踐、測試自動化及API版本管理。

網易CI/CD實踐的背景

據瞭解,網易的大部分互聯網產品業務團隊都是使用統一的平臺來進行CI/CD實踐,目前平臺上運行着數萬個倉庫,活躍倉庫近萬個,同時平臺內還有大量副本數超過數千個的服務,這些服務每天承載着業務方大量的訪問。

爲了適應業務發展的節奏,網易內部廣泛推行了敏捷開發,每天通過平臺發佈應用的次數達到數萬次,產品迭代節奏快,交付週期短。所有業務使用統一的平臺進行CI/CD,無需各自搭建,降低成本,使用統一的規範,避免了相同問題的多次採坑。

網易公司內部的CI/CD實踐主要是輕舟CI/CD平臺,該平臺提供了可視化的流水線編排界面,一次配置,多次運行,支持團隊成員共享配置。每次提交或者合併代碼都會自動觸發流水線的執行,自動將代碼發佈到環境上。數據顯示CI/CD流水線相比傳統的手工或腳本方式平均效率提升了5倍以上,發佈效率提升了8倍以上。另外通過整合多種自動化測試工具幫助業務方實現高質量的集成。通過可視化度量平臺從多個維度瞭解構建,部署的相關指標數據,幫助產品提高發布效率。

之前,網易內部有一套從主機部署時代發展過來的自動化部署平臺,但是其對容器部署的支持不友好,部署之前需要先在服務器上部署agent,註冊到內部CMDB,再下發指令執行。這樣的執行操作註定了這個平臺在大批量部署場景下會存在性能瓶頸。

基於原平臺存在的性能問題,以及對業務容器化、微服務化演進的判斷,網易研發了新的輕舟CI/CD平臺,成爲了網易雲原生技術棧的重要組成部分,滿足雲原生環境下企業在能效、團隊協作效率、產品迭代速度等多方面的需求。

在使用體驗上,輕舟CI/CD是一體的,但是在系統架構設計方面,其實是分開的。下面,我們就分別來講講CI和CD的系統設計。

網易CI實踐的整體架構及工具選型

與絕大多數互聯網公司一樣,網易內部各業務方的持續集成也大都是由研發團隊的QA負責的,CI工具選擇了比較常用的Jenkins,同時在流水線的上下游整合了其它的主流CI工具。 整個流水線平臺依託於Kubernetes,基於K8s的CRD(自定義資源)重新設計了流水線上層模型,並通過Operator驅動流水線執行過程。

當流水線觸發一次執行時,將會產生一個PipelineRun對象,Operator將會根據對應的流水線預先定義好的階段生成對應的Job,然後通過Jenkins的API觸發Job執行。Job執行完成後,將會通過Webhook回調上層服務接口,將狀態回寫到PipelineRun中,然後觸發下一個階段的執行。

網易CI系統整體架構

CI工具選型

傳統的持續集成實踐本身就很佔資源,編譯構建對磁盤、CPU,甚至是網絡都有一定的要求,如果在高峯期想要保證持續集成任務能夠及時運行,通常需要預留大量的構建機資源,這不僅會導致資源浪費,同時也需要更多人力來維護管理,成本會很高。

所以,網易技術團隊在進行CI工具選型時,就直接圈定了4個當前主流的工具,分別是Travis CI、Circle CI、GitLab CI 和 Jenkins,並詳細對比了4個工具。

項目名稱 開發語言 配置語言 公有云服務 私有部署
Travis CI Ruby YAML 不支持
CircleCI Clojure YAML 不支持
Gitlab CI Ruby YAML 支持
Jenkins Java Groovy 支持

其中,Travis CI、CircleCI在Github開源項目中使用較多,但不支持私有化部署,不適合公司實踐;GitLab CI可以與代碼倉庫無縫集成,且天然支持GitOps,但整體生態目前並不成熟,需要自己製作builder的鏡像,並與Gitlab深度綁定;Jenkins作爲傳統的CI工具,社區和生態都比較完善,Jenkins 2.0版本提供了Pipeline as code的特性,可以將CI過程納入版本管理,支持GitOps。此外,Jenkins社區也誕生了kubernetes-plugin這樣的插件,可以將流水線的執行從傳統的物理機轉移到容器中,再依託Kubernetes強大的調度能力,就可以實現資源的動態調度和編排。

基於以上原因,網易輕舟最終選擇了Jenkins,但是傳統的Jenkins在系統運維、資源管理、使用方式等方面,存在很多問題。例如,Jenkins的master-slave架構比較經典,但由於誕生時間較早,所有配置和數據都是基於文件存儲的(存儲在Jenkins master節點home目錄下),修改時,會先更新內存,然後異步寫入磁盤,而當底層文件被更新時,Jenkins並不會自動reload更新後的數據,因此,很難做到高可用;Jenkins master實例對文件目錄是獨佔的,不同Jenkins實例也無法共享底層存儲…因此,網易技術團隊希望能夠在傳統Jenkins版本中做出以下改進:

  • 結合Docker/Kubernetes雲原生技術棧,解決傳統Jenkins使用中的痛點;
  • 通過將業內最佳實踐固化到產品中,解決易用性的問題,降低用戶使用門檻,提高接入效率;
  • 重新設計上層流水線模型,提供更加強大的流水線編排調度能力;
  • 自研流水線底層組件,替代Jenkins插件,提供更加靈活的擴展能力,方便與公司內部系統進行集成;
  • 提供豐富的企業級特性(如認證、鑑權、審計、告警、通知等),滿足企業客戶需求;

除了Jenkins,網易輕舟在整個流水線的上下游也整合了其它的主流CI工具,例如:

  • 代碼倉庫:支持Git/SVN,可以適配絕大多數代碼託管平臺,並且對Gitlab做了深度適配,例如,支持從Gitlab Webhookpayload中提取各類參數;
  • 代碼掃描:集成了SonarQube,支持了所有主流的編程語言;
  • 單元測試:整合了Java中常用的Jacoco工具,方便用戶在運行單元測試時,生成對應的UT和覆蓋率報告;
  • 代碼編譯:Java支持了Maven/Gradle,並且內置了Nexus私服,方便做內網代理;Node.js支持了Npm;Golang支持了go mod緩存加速;
  • 鏡像構建:支持Docker out of Docker、Kaniko兩種構建方式,用戶可以根據自身需求選擇使用;
  • 鏡像倉庫:整合了Harbor,支持Harbor webhook,並且集成了Harbor的鏡像掃描和鏡像複製功能;
  • 容器部署:支持kubectl原生部署、升級,以及輕舟CI/CD應用部署等多種部署方式;
  • 自動化測試:支持Java語言常用的TestNG,同時整合了網易內部的GoAPI測試平臺,支持在流水線中運行指定的接口測試集,並在執行時輸出測試報告;
  • 告警通知:集成了郵件發送、短信告警、網易POPO等多種通知方式;

據瞭解,目前國內大部分公司對Jenkins的使用方式依然停留在1.0的時代,很多人都還在使用Jenkins的UI配置方式,並沒有使用到Jenkins 2.0提供的Pipeline as code功能,並且在使用場景上,大量依賴一些自定義腳本,這些腳本通常由QA同學事先預置在機器上,一旦機器出現宕機或故障,遷移起來成本也很高。相較之下,選擇更新版本的Jenkins,使用更前沿的功能,並適時輔以其它CI工具,往往會有更好的效果。

網易CI實踐的分支管理與協作流程

所有CI實踐的源頭一定是代碼變更,好的代碼分支管理和版本變更規範是做好CI實踐的前提。網易輕舟是基於GitFlow進行代碼管理和協作流程的,主要的階段包括預發驗證、測試驗證和代碼審查、集成、驗證。

網易輕舟CI實踐中的主要分支有devlop和master,輔助分支包括feature/*、release/v1.x.0、hotfix/v1.x.1。

  • develop: 集成分支, 不允許commit/push, 僅允許來自  feature/* 或 hotfix/v* 分支的合併
  • master: 版本分支, 不允許commit/push, 僅允許來自 release/v* 或 hotfix/v* 分支的合併, 每次接受合併後必須在其上創建 TAG
  • feature/*: 功能分支, 從 develop 派生, 不允許來自 develop 的合併, 合併到 develop 後刪除
  • release/v1.x.0: 發版更新驗證分支, 從 master 派生, 派生時根據 master分支TAG標記並遞第二位版本號命名。不允許commit/push, 只允許來自 develop 的合併, 合併到 master 之後刪除。
  • hotfix/v1.x.1: 補丁更新驗證分支, 從  master 派生, 派生時根據 master 分支TAG標記並遞增第三位版本號命名。允許commit/push, 不允許 來自 develop 的合併, 合併到 master 後必須再合併到 develop , 合併後刪除。

除此之外,關於TAG,網易輕舟也有一些特定要求:

  • v1.x.0: 發版更新, release/v* 分支合入 master 後, 在 master 分支上創建。
  • v1.x.1: 補丁更新, hotfix/v* 分支合入  master 後, 在 master 分支上創建。
  • 此外,爲了保證代碼合入的質量,我們也制定了對應的代碼review原則:
  • 任何代碼變更都必須提mr,不允許直接push到dev/master等保護分支;
  • 任何變更至少必須有兩名團隊其他成員review過,才能合入develop、hotfix分支,只有被團隊接受的代碼纔是團隊的代碼;

網易CI流程的具體步驟

通常,一個持續集成流程會包括以下步驟:代碼檢出、單元測試、靜態掃描、編譯、構建、鏡像掃描和測試部署。好的持續集成流程一定是面向質量的,所以,在實踐過程中除了工具和流程,還需要做好代碼質量相關的工作。

對於大部分團隊來說,CI可能是由QA維護的,因此在實際使用過程中,會將線下環境的CI和線上分離開,線上通常更加註重持續部署,主要由QA、PE等角色負責,流程上會簡化一些,更加註重運維規範、上線審覈。

代碼檢出:通常需要在流水線中配置代碼源、ssh祕鑰以及代碼分支等信息,爲了優化代碼檢出性能,CI/CD流水線會採用的git淺拷貝的方式來加速整個過程。

靜態掃描:這是流水線至關重要的一環,運行時會將掃描的數據上傳至用戶預先配置好的SonarQube平臺,並且通過SonarQube的QualityGate進行質量卡點,除了QualityGate,用戶還可以自定義一些流水線特有的卡點規則,並且配置通過郵件、網易popo等通知執行結果。

單元測試:這是CI過程中必不可少的一環,CI/CD流水線整合了常用的Jacoco工具,方便用戶在運行單元測試時生成對應的UT和覆蓋率報告,報告的內容可以在流水線執行詳情頁查看,同時支持用戶設置單元測試通過率、UT覆蓋率卡點,併發送相應的郵件通知。

代碼編譯:支持大部分主流的編程語言,比如Java、Node.js、C++、Golang等,並且針對各類語言做了相應的編譯加速方案,支持Maven、Gradle、C++、Go mod構建緩存。

鏡像構建:支持Docker out of Docker、Kaniko等多種構建方式,同時整合了網易輕舟Harbor,集成了Harbor的鏡像掃描功能,支持在流水線運行過程中執行鏡像掃描、查看鏡像安全報告,同時支持安全項卡點以及郵件通知等功能。

集成測試:CI/CD流水線與網易內部自動化測試平臺GoAPI做了集成,用戶可以預先在平臺側配置好相應的接口執行集,然後在流水線中選擇對應的執行集執行,並在流水線詳情頁中查看執行集的通過率,同時支持卡點以及郵件通知。

流水線觸發器:多種觸發器,比如定時觸發、PollSCM、Webhook以及流水線串聯觸發,其中Webhook還額外提供了對Gitlab、Harbor的支持,支持從Gtilab、Harbor的payload中提取相關參數,並在流水線階段中使用。

採訪嘉賓簡介:

汪燦豐,網易杭州研究院高級產品開發工程師,專注於雲原生以及DevOps領域,目前主要負責網易輕舟CICD的研發工作。

梅光輝,網易杭研究院高級服務端開發工程師,目前主要負責網易輕舟CICD研發工作,在雲原生以及容器DevOps領域有過深入的研究和實踐。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章