Jenkins 很酷,但是不完美,有歷史侷限性造成的問題。本文僅從「如何更好給研發團隊賦能的角度」,剖析Jenkins, 探討理想的持續交付平臺, 不帶貨無廣告~
- Jenkins的前身是Hudson, Hudson是SUN公司時期就有的CI工具,後來因為ORACLE收購SUN之後的商標之爭,創始人KK搞了新的分支叫Jenkins 。今天的Hudson還在由ORACLE持續維護,但風頭已經遠不如社群以及CloudBees驅動的Jenkins.
- Hudson 被 Jenkins 取代後,不再維護,並於 2017 年 2 月宣佈已過時。Hudson 網站 hudson-ci.org 於 2020 年 1 月 31 日關閉
- 關於Hudson 和Jenkins的恩怨,有興趣可查閱 https://www.oschina.net/news/63453/hudson-and-jenkins-grievances
提到DevOps/持續整合這些話題,由於開源免費,歷史悠久,外掛API豐富,群眾基礎好(可借鑑模仿案例實踐資料多)等原因,Jenkins永遠是那個最亮的「仔」,也是眾多相關領域廠商或者企業**繞不開的「工具」。
不過,依然有很多「不完美」,僅僅是個沒有「DevOps靈魂」的CI工具(理由如下),但不得不承認它又是「免費」又有「使用者量」的CI工具。下面我通過以下幾個方面詳細做些剖析**
首先 Jenkins 是一個巨石系統,它是一個單體的結構。為什麼到現在為止大家好像沒有看過特別成熟的 Jenkins 叢集級的方案,或者很少看到高可用的方案,大部分情況下大家看到的是給不同的團隊或者是不同的部門分配多個 Master ,而不是共用一個大的 Master ,其實這個主要取決於 Jenkins 內部的實現原理和機制。
傳統意義上來講一個服務會有兩層,一層是你的服務層,一層是你的資料層。但是 Jenkins 因為歷史的一些原因,導致所有的儲存都是以檔案的方式儲存在磁碟上,儲存在磁碟上就會一個比較大的效能問題。在 Jenkins home 裡有一個 jobs ,裡面儲存的就是大家構建的每一個任務,還會存構建任務的設定等等。一系列的東西都以檔案的方式,以特定的目錄結構儲存在磁碟上。
當 Jenkins 第一個步驟,比如你重啟 Jenkins 的時候,它會做什麼?先把磁碟上 jobs 目錄都掃一遍,載入到自己的記憶體裡裡,再去做後續的東西。比如剛才說的高可用的方案,假如用共用儲存,現在在一臺 Jenkins Master 上寫了一個job,其實另一臺 Jenkins 是沒有感知的,因為沒有載入這個job。
Jenkins 的外掛那麼多,到底該選哪一個?而且出現很多問題是1+1小於2,有時候必須安裝第二個外掛來滿足,兩個外掛組合的時候又可能達不到很好的合力,這導致很多業務場景不得不去裝很多額外的外掛來滿足自己的需求。開發者對 Jenkins 熟識的程度大部分在於自己外掛的使用經驗。
當jenkins支援的場景越複雜,你會發現你要管理很多外掛,這是你構建Jenkins和複製Jenkins面對最大的問題;同時,外掛由於是個人貢獻維護,很多外掛會有年久失修情況。
Jenkins的外掛包括Jenkins本身,它是有一些漏洞的,當你去用一些外掛的時候,你要不停的更新它。
不知道有沒有人在一個Jenkins中配200個人,你肯定碰到到第80個人的時候,整個使用者設定介面會卡。
要想 Jenkins 用得好,外掛不能少。但是 Jenkins 的外掛會帶來一些效能問題,每一個外掛都是在專案啟動的時候就會載入到記憶體裡,當外掛越大的時候,對效能的損耗越大。要選擇自己合適的外掛去構建自己的 Jenkins 。
拋開Jenkins上面的缺點不談,回到現實場景中,我們需要從更大的視角(即持續交付)來理解一個「持續交付平臺」需要扮演的角色。
從上圖中可以看出,從開發人員寫下程式碼到服務終端使用者是一個漫長過程,整體可以分成三個階段:
如果從持續交付角度看,其最核心訴求就是要讓上圖三個階段能夠無縫連線並自動化執行起來,從而達到持續交付的兩個核心目標:提高交付頻率(部署次數)和降低部署延時(從程式碼提交到上線的時間差)。
參照如上持續交付的流程,可以發現持續交付對於一個部署系統的要求絕對不僅僅是一個自動化的部署過程,這也是在有了Jenkins和其相關部署外掛後仍然需要搭建獨立部署系統的原因所在。具體來說,我們可以從下面幾點分析:
儘管持續交付希望自動化完成從程式碼到部署上線的整個流程。但是整個持續交付過程有多個不同角色的人蔘與其中(開發、測試、運維甚至還經理及市場人員)。其中有些角色(如開發/測試)需要關心構建過程,而更多的角色(如運維等)絕大時候都是從製品開始部署工作。這也就要求構建和部署過程相互解耦,能夠獨立操作。
構建和部署這兩個過程通過製品(Artifact,又稱為部署包)連線(製品是構建過程的產出,同時是部署過程的輸入)。如果它們相互解耦,自然就需要有統一的地方管理儲存和管理這些製品,即統一製品庫。
有了統一製品庫後,構建過程自動提交產生的製品到此,而部署過程則主動到製品庫拉取需要的製品進行部署,從而實現構建和部署的完整解耦。
服務上線需要涉及到很多不同目的環境(開發、測試、預發、生產、演示等)。在雲化基礎設施中,環境內部的資源會頻繁變化(例如,Auto-Scaling時刻都有可能新增或者減少你的雲主機)。
這時候需要對部署流程隔離部署環境差異以及環境內頻繁變化的基礎設施。當需要執行一個部署時,操作人員只需要指定部署到哪個環境(即環境名稱或者ID號),而不需要關心環境內部的任何資訊,只需把部署請求分發到指定環境內的每臺主機並自動執行。
如果基於Jenkins來直接部署,則必然把環境管理的很多複雜度引入到部署流程內部。
為保障服務的高可用,落實部署和釋出的解耦以及其他業務需要,使用者常需要支援如灰度釋出、A/B測試釋出等部署需求。一個獨立的部署系統在此可以提供多種部署策略,並結合環境管理等其他功能滿足業務上對部署和釋出的各種需求。同樣,Jenkins及其部署外掛並沒有提供這樣的能力。
在一個公司內部經常有不同的專案,使用不同的程式語言,而部署流程也五花八門。從控制風險,減少重複操作,降低部署自動化難度等多重考量,公司都傾向制定一套標準的部署流程。
這時候,獨立的部署系統就可以幫助用把這些規範落實下去並在日常的部署過程中時刻校驗(在軟體工程領域,幾乎所有的規範落實都得靠工具來助一臂之力,否則基本都會變成紙面上的規範而已)。
如果基於Jenkins來直接部署,如何落實這些部署規範仍然是一個很困難的事情,因為Jenkins及其部署外掛並未對此提供任何實質性的支援。
部署是一個團隊從程式碼到服務的關鍵路徑,這上面的所有運算元據都值得記錄並用於各種運營支援(包括安全審計、部署記錄查詢、部署頻率和失敗率分析等等)。基於Jenkins直接部署當然也可以獲取這些資料,但是把它做在獨立的系統內會更靈活和方便。
如之前提到,部署不僅僅開發和測試人員需要,要努力讓部署服務化,從而讓團隊內任何一個人都可以隨時觸發一次部署。Jenkins的操作介面對於開發或者測試人員可能還比較方便,但是對於其他人員來說則過於複雜。
當然,除了上面列出的這些原因外,你還要解決部署版本的管理等,這裡就不一一列舉。
如前所述,一個理想的持續交付系統需要包括的內容是非常豐富的,特別是要面臨各種複雜場景,不同技術棧的團隊,異構的各種內部系統(絕對不僅僅是Jenkins外掛要做的那些事情)。
如下圖所示,持續交付系統需要連線專案中涉及的人、程式碼,製品庫,以及環境等,Jenkins僅僅起到了簡單的連線作用。
所以,能夠給研發過程賦能的「持續交付平臺」需要具備如下特點
DevOps持續交付涉及的工具如同各類不同形狀的積木,你的目標是建造一個房子,可能你現在手中只有很少的積木,或者你有很多重複的積木,但是唯獨缺少三角形完成屋頂部分。
想清楚不迷路,不同的人搭建方法不同,只要最後搭建合理漂亮實用,恰到好處就可以,期待更好賦能研發過程的持續交付平臺~