寫在前面
豬八戒網的系統架構演變史
2015年前,豬八戒網80%的專案都是PHP語言開發的,剩餘少部分系統使用Node.js和Java。2015年一個關鍵的里程碑,開啟了豬八戒網SOA服務轉變,這就是騰雲7號行動。
騰雲7號可謂意義深遠,它使用Java語言將核心業務程式碼進行了重構,建立了以Dubbo為核心的SOA服務框架,使用ZooKeeper + Swoole為核心的業務呼叫提供機制。
滿足新業務使用Java語言編寫、老業務仍然使用PHP編寫,同時支援兩種語言呼叫Dubbo服務的能力。
開發語言變遷
在SOA架構的基礎上,2016年開始全面推行前後端分離,於是出現了三足鼎立的局面:
- Node.js:負責前端
- Java:負責後端及老PHP專案遷移
- PHP:負責老專案維護
剩餘部分小系統或者邊緣化的工具使用其他語言開發,或者在此三種語言基礎上的一些變種:
瘋狂增長的背後
系統架構以及語言體系的變化,隨之而來的是專案工程的指數級增長:
專案工程的增長,給軟體研發過程管理帶來了較大壓力,這時候公司開始推行敏捷。
區別於業界流行的敏捷開發模式,豬八戒網根據公司實際情況做了一點小小的變化,即增加了deploy的概念,整個層級變成:deploy->story→task。
deploy是story的集合,作為一次上線釋出的內容彙總,它主要負責從開發到測試到運維的交付件說明,以及開發-測試-效能-預釋出-灰度-線上各環境程式碼釋出的准入準出標準控制,deploy這部分將在後面DevOps中做詳細介紹。
業務擴張對運維又帶來了壓力,大量的專案需要進行釋出,所以虛擬機器的數量也不斷增長,管理難度隨之加大,運維人數最多增加到三十多人:
為了降低維護難度,我們開始做CMDB,指定各種規範,同時進行多資料中心建設,業務上做異地雙活。
Nginx載入Upstream進行灰度和生產環境流量控制,DNS負責資料中心切換,能達到在某個資料中心掛掉的情況下快速切換到另外一個資料中心。
敏捷開發、快速增長的專案工程、不同語言的編譯構建、不同資料中心的部署和程式碼釋出、不同資料中心和不同環境之間的服務監控以及反饋鏈路,如何滿足這些需求並且將它們連起來,這是豬八戒網需要解決的重點問題。
DevOps進化論
為了滿足業務快速擴張的需求,2016年末開始組建DevOps團隊,集合了運維、配置管理、Java技術人員等。團隊專門負責DevOps方法論以及技術的落地,全公司使用統一的標準進行軟體開發,並使用統一的工具進行專案管理。一張圖看豬八戒網的DevOps:
上圖中的DevOps是一個平臺,它整合了從開發到測試到上線的整個過程,基於這個圖重點介紹:
新建Git工程
在2016年開始,公司搭建了GitLab,後來發現GitLab和SVN大家都在用,那麼整個釋出系統需要支援兩種版本庫(那個時候的釋出系統並不是Jenkins,而是公司自己開發的syn2,基於Django框架的Python前端,呼叫後端shell實現編譯構建和釋出),雖然當時都支援了,但為了統一版本庫,降低維護成本,我們關閉了SVN,將所有SVN專案遷移到GitLab中。
同時我們提供了Java的Dubbo和API工程模版,Node.js的兩個框架工程模版,使用者在DevOps平臺可以直接選擇工程模版,然後自動建立一個Git工程並返回給使用者Git地址。
構建
針對開發語言的不同,我們提供了12種編譯方式,分別為:Java、PHP、Node.js、Utopia、Scala、GNode、Jello、FIS、HTML、TPL、Thrift、BLG。
針對不同的編譯方式,我們提供了不同的Jenkins構建環境,當然,我們把它整合在了一起,Jenkins採用Master/Slave的架構,支援任何語言的編譯,Jenkins將在後續介紹。
釋出元件
Java的元件,構建後釋出到Nexus元件倉庫,原來我們的Nexus元件倉庫不受控制,開發人員可以隨意上傳元件,不管是snapshots還是release,所以導致很多release版本問題,後來我們做了許可權控制,釋出也統一起來,開發人員可以在本地將snapshots上傳到Nexus倉庫,但是release的必須使用DevOps提供的能力上傳,這極大的保護了release版本的穩定性。
釋出API
Java的API介面實現,這裡有三個功能:釋出元件到Nexus倉庫、自動生成API介面文件、將程式碼轉換為PHP和Node.js生成物(這裡沒有歷史,只有今生)。
這三個功能使用者可以一鍵觸發,所以任何部門的API介面,只要一發布,必然有最新的介面文件,避免了介面文件認為更新不及時的問題。
釋出流水線
流水線的演變是基於測試環境的變化而變化的,曾經我們的測試環境比較單一,流水線也相對簡單,但隨著業務的快速發展,單一的環境凸顯大量的問題,所以我們開始在環境和流水線上進行優化改造。
曾經豬八戒網的測試環境都是由DevOps團隊統一管理和維護的,隨著環境和流水線的不斷優化,後來交接給運維團隊負責,目前已經在慢慢將測試環境交給開發和測試自行維護,但大家意識上還是比較多的依賴於DevOps和運維幫忙解決環境上的問題,這裡先介紹流水線上釋出模式進化的三個階段:
第一階段:我們叫它大鍋飯年代
這個時期的流水線很簡單,環境也很簡單,問題點主要也就是上圖中的情況。
第二階段:又叫公交車模式
在這個階段,我們的系統架構還沒有Dubbo,這次調整隻是為了解決環境共用導致的相互影響,所以搭建了t1、t2、等t系列測試環境。測試完成後將程式碼合併到Trunk推送預釋出,在預釋出做回滾測試,上線時直接將預釋出的程式碼同步到生產環境,保證預釋出的程式碼和生產環境程式碼一致。
公交車模式解決了第一個階段提到的1和2兩個問題,但專案仍然耦合。所以我們以公交車模式通過降低線上變更頻率【每週二、四15點,公交車司機準點發車,將預釋出上的程式碼同步到線上(並不是將Trunk程式碼釋出到線上)】來達到耦合帶來的問題;雖然解決了一部分問題,但隨之而來的需要大量人工勞動力去維護這大量的測試環境,環境一致性問題隨之突出。
第三階段:也叫計程車模式
為了解決專案的耦合問題,以及環境一致性問題,我們開始給每個專案指定開發負責人,這種責任人制度,很大程度上解決了耦合的問題,大家都開始將各自負責的專案許可權收起來了,業務範圍和邊界更清晰。同時引入Docker技術,實現構建一次處處執行,解決了環境一致性問題。分支策略也變得非常簡單:branches開發,master釋出,tags存檔。大家可以在此分支策略基礎上做任意變種,滿足各個事業部不同開發人員的工作習慣。
在計程車模式釋出的各個環境裡,使用了在敏捷階段介紹的deploy,每個環境推送,都必須指定一個deploy,這個deploy必須和你推送的專案工程有關:
deploy必須到了某個階段,才能推送對應環境,而deploy的每個階段都有準出檢查。
這就像一條河,河上有幾個壩,每一個壩都會攔截一部分河裡的垃圾,那這條河的下游相對上游肯定是更清澈乾淨一些,最終匯入大海的水才會清澈,海水就是我們的生產環境。
每一個節點(環境)又有各自的流水線,各節點下的流水線:
所以我們的流水線是二級流水線:第一級流水線對應我們的五大環境(測試環境使用者可以自定義環境名稱,所以又有子環境的概念);第二級流水線對應各環境所需要的原子任務組合。
所有功能我們做成原子任務,包括校驗類和執行類。每個節點(環境)可以自由組合需要的原子任務(必須的原子任務由後臺控制,非必須的原子任務由使用者自行選擇是否新增)。
校驗類:我們在執行任務之前,有很多校驗(此類任務一般使用Java實現),包括前面提到的和敏捷關聯的deploy的流程校驗,以及安全掃描是否通過,配置中心是否配置,告警中心是否有對應告警等多達十幾個校驗項;
執行類:各種校驗內容通過後,才進入到執行類任務,包括從GitLab拉程式碼,編譯構建,上傳製品庫,釋出到程式碼源伺服器,Docker映象製作,上傳Harbor倉庫,啟動容器等,其中大部分功能是Jenkins來完成的。
為了保證流水線的高可用,設計了Jenkins的多Master + 多 Slave的架構,具體架構情況如下:
因為Jenkins的許可權機制無法滿足公司業務需求,所以我們將Jenkins放在了後臺,使用者不能直接接觸到Jenkins,而是使用DevOps作為使用者入口進行排程。
DevOps叢集隨機排程到對應的Master上,當DevOps在建立Jenkins的Job的時候會在所有Master上面建立;當DevOps在觸發Jenkins構建的時候會隨機選擇一個Master執行(當某個Master異常,DevOps不會排程到該Master,當Master恢復正常後,後臺任務會自動將多個Master間的任務置為一致),Slave放在Kubernetes叢集中,當Slave佇列滿的情況下可自動增加Slave節點(構建Docker映象的節點仍然在虛擬機器中)。
Jenkins上的任務首先以專案工程為單位建立folder,再在folder下建立對應的執行類任務。我們沒有使用Jenkins的Pipeline的原因,就是因為Pipeline統一維護困難,且沒有層級劃分。Jenkins在面向企業級方面還需要提供更豐富的功能。
每日構建次數:每日構建次數包括所有環境的釋出次數,平均每日大概在1500次左右。
每日上線次數:每次上線次數為專案釋出到生產環境的次數,平均每日大概100次左右,同時支援hotfix釋出,隨時回滾等。
元件庫
因為我們開發語言的原因,所以不同開發語言有對應的元件倉庫,這在前面的釋出API裡面已經講過,主要是Java的Nexus倉庫、PHP的PPKG倉庫、Node.js的NPM倉庫,這裡就不重複了
製品庫
製品庫分兩種,虛擬機器和Docker釋出,其中虛擬機器發布的我們直接將編譯構建好的內容儲存起來,供推送其他環境時可直接使用,達到一次構建,處處執行的目的(和環境有關的配置統一放在配置中心,每次釋出前通過校驗類流水線任務,校驗完成配置後方可釋出)。
Docker的是直接構建成映象,上傳到Harbor映象倉庫,在觸發Kubernetes容器叢集啟動容器時從映象倉庫獲取映象啟動。
虛擬機器發布
虛擬機器發布是使用Rsync服務進行檔案同步,將程式碼從製品庫同步到對應伺服器,然後伺服器上有一個守護程式,會實時監測檔案是否更新,若有程式碼更新則進行重啟操作。
Docker釋出
Docker釋出是呼叫Kubernetes進行釋出,將事先生成好的yml檔案傳遞給Kubernetes,然後在對應資料中心啟動容器,並通過zbjcheck服務校驗功能確保服務啟動正常後,再刪除老的容器,達到不停機升級的目的。
自動化測試
目前DevOps整合了單元測試(包括自動生成單元測試用例)、介面測試、效能測試的功能。單元測試大部分情況下還是需要開發人員寫用例,自動生成單元測試用例的功能並不是那麼好用,所以使用者較少,但在流水線上會自動進行單元測試,並將結果反饋給使用者:
單測結果是基於Sonar的,在Jenkins上執行完單測後連同靜態檢測結果一起釋出到Sonar,在Sonar上配置了通用的過濾條件,可以過濾掉部分不需要統計單測的程式碼(如框架自動生成的程式碼不計入單測覆蓋率),使用者可以在此基礎上配置其他過濾條件。
介面測試和效能測試方面,我們在DevOps平臺上做了一個關聯的功能,每一個介面測試或者效能測試用例,都對應一個專案工程,關聯關係梳理好後可以實現在釋出流水線的任意環節觸發介面測試或者效能測試。
和專案工程關聯:
釋出流水線觸發介面測試:
釋出流水線觸發效能測試:
自動化測試的結果展示方面目前做的不夠好,只是在日誌中提供連結,使用者點選連結進去檢視結果。
CMDB
CMDB作為底層的統一資源管理中心,負責跨資料中心的混合雲管理,提供統一的資源管理平臺,不管私有云還是公有云,不管虛擬機器還是Docker都統一管理,同時提供對底層服務的訪問支援。提供機器與宿主機的拓補圖關係等,對基礎設施的管理提供了便利。
一套OpenStack表示一個虛擬化叢集,一套Kubernetes表示一個容器雲叢集,每個資料中心有一套或多套OpenStack和Kubernetes。CMDB通過資料中心和可用區來標示不同的叢集。任何需要和虛擬機器和容器對接的功能統一由CMDB提供介面管理。
DNS解析
DNS作為附加的功能,可由使用者直接點選一個按鈕實現域名解析:
域名解析是一個比較複雜的過程,它需要和後臺很多系統互動,還需要根據事先定義好的Nginx模版生成配置,Docker的服務還需要進行動態服務發現,最終將域名資訊註冊到DNS中。
擴縮容
DevOps平臺同時支援對虛擬機器和Docker的擴縮容功能,只要對應資料中心存在對應的服務,就可以進行擴縮容,一次擴容節點不能超過10個,縮容節點數最少保留一個。
我們能對不同資料中心的服務進行擴縮容,並且所有的操作都有事件機制,能將每個服務所使用的資源進行歸檔管理,最終可以對各個部門所使用的資源進行伺服器成本費用結算。
控制檯
從瀏覽器進入伺服器,且通過許可權控制,有許可權人員才能進入,更加方便排查問題:
監控
DevOps已經整合了監控的部分功能,包括介面呼叫情況、全站可用性、監控資料排行榜、金絲雀分析等。
可用性監控
監控資料排行榜
介面呼叫情況
金絲雀分析
金絲雀分析主要用於在程式碼釋出到灰度環境時,分析灰度環境和線上環境的相關指標值對比,以確保新版本程式碼質量不必老版本差。
目前只有以下幾個指標資料,後續將不斷完善指標內容:
灰度環境和線上環境都承擔使用者流量,通過Nginx的Upstream進行權重設定,我們可以根據金絲雀結果做一次上線釋出前的質量評估。
未完待續
雖然我們完成了DevOps的大部分功能,要講到技術細節,上面的每一個小節都能用一篇文章來講解,所以以後我們會不斷分享我們在DevOps中的一些技術細節,當然我們也還有很多需要優化和改進的。需求蒐集和規劃、專案管理和釋出關聯、自動化測試、金絲雀分析的改進、自助作業平臺、CMDB對混合雲的管理等都是後續需要改進的,整體的規劃圖如下:
DevOps平臺功能架構分佈中,還有很多工具以及功能未描述,上面講到的每一個點都可以展開為一篇文章做詳細介紹,這裡主要為2017年做一個總結。
以上內容為豬八戒網最近幾年來整個DevOps的發展演進史,公司的規模不同,整體架構以及方法可能不同,對於豬八戒來說,DevOps還在繼續演進,同時也會不斷學習業界優秀實踐,為業務發展提供最基礎的保障。