2015年前,豬八戒網80%的項目都是PHP語言開發的,剩餘少部分系統使用Node.js和Java。2015年一個關鍵的里程碑,開啓了豬八戒網SOA服務轉變,這就是騰雲7號行動。php
騰雲7號可謂意義深遠,它使用Java語言將核心業務代碼進行了重構,創建了以Dubbo爲核心的SOA服務框架,使用ZooKeeper + Swoole爲核心的業務調用提供機制。html
知足新業務使用Java語言編寫、老業務仍然使用PHP編寫,同時支持兩種語言調用Dubbo服務的能力。前端
在SOA架構的基礎上,2016年開始全面推行先後端分離,因而出現了三足鼎立的局面:node
剩餘部分小系統或者邊緣化的工具使用其餘語言開發,或者在此三種語言基礎上的一些變種:nginx
系統架構以及語言體系的變化,隨之而來的是項目工程的指數級增加:docker
項目工程的增加,給軟件研發過程管理帶來了較大壓力,這時候公司開始推行敏捷。shell
區別於業界流行的敏捷開發模式,豬八戒網根據公司實際狀況作了一點小小的變化,即增長了deploy的概念,整個層級變成:deploy->story→task。後端
deploy是story的集合,做爲一次上線發佈的內容彙總,它主要負責從開發到測試到運維的交付件說明,以及開發-測試-性能-預發佈-灰度-線上各環境代碼發佈的准入準出標準控制,deploy這部分將在後面DevOps中作詳細介紹。api
業務擴張對運維又帶來了壓力,大量的項目須要進行發佈,因此虛擬機的數量也不斷增加,管理難度隨之加大,運維人數最多增長到三十多人:瀏覽器
爲了下降維護難度,咱們開始作CMDB,指定各類規範,同時進行多數據中心建設,業務上作異地雙活。
Nginx加載Upstream進行灰度和生產環境流量控制,DNS負責數據中心切換,能達到在某個數據中心掛掉的狀況下快速切換到另一個數據中心。
敏捷開發、快速增加的項目工程、不一樣語言的編譯構建、不一樣數據中心的部署和代碼發佈、不一樣數據中心和不一樣環境之間的服務監控以及反饋鏈路,如何知足這些需求而且將它們連起來,這是豬八戒網須要解決的重點問題。
爲了知足業務快速擴張的需求,2016年底開始組建DevOps團隊,集合了運維、配置管理、Java技術人員等。團隊專門負責DevOps方法論以及技術的落地,全公司使用統一的標準進行軟件開發,並使用統一的工具進行項目管理。一張圖看豬八戒網的DevOps:
上圖中的DevOps是一個平臺,它集成了從開發到測試到上線的整個過程,基於這個圖重點介紹:
在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版本的穩定性。
Java的API接口實現,這裏有三個功能:發佈組件到Nexus倉庫、自動生成API接口文檔、將代碼轉換爲PHP和Node.js生成物(這裏沒有歷史,只有此生)。
這三個功能用戶能夠一鍵觸發,因此任何部門的API接口,只要一發布,必然有最新的接口文檔,避免了接口文檔認爲更新不及時的問題。
流水線的演變是基於測試環境的變化而變化的,曾經咱們的測試環境比較單一,流水線也相對簡單,但隨着業務的快速發展,單一的環境凸顯大量的問題,因此咱們開始在環境和流水線上進行優化改造。
曾經豬八戒網的測試環境都是由DevOps團隊統一管理和維護的,隨着環境和流水線的不斷優化,後來交接給運維團隊負責,目前已經在慢慢將測試環境交給開發和測試自行維護,但你們意識上仍是比較多的依賴於DevOps和運維幫忙解決環境上的問題,這裏先介紹流水線上發佈模式進化的三個階段:
第一階段:咱們叫它大鍋飯年代
這個時期的流水線很簡單,環境也很簡單,問題點主要也就是上圖中的狀況。
第二階段:又叫公交車模式
在這個階段,咱們的系統架構尚未Dubbo,此次調整隻是爲了解決環境共用致使的相互影響,因此搭建了t一、t二、等t系列測試環境。測試完成後將代碼合併到Trunk推送預發佈,在預發佈作回滾測試,上線時直接將預發佈的代碼同步到生產環境,保證預發佈的代碼和生產環境代碼一致。
公交車模式解決了第一個階段提到的1和2兩個問題,但項目仍然耦合。因此咱們以公交車模式經過下降線上變動頻率【每週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發佈是調用Kubernetes進行發佈,將事先生成好的yml文件傳遞給Kubernetes,而後在對應數據中心啓動容器,並經過zbjcheck服務校驗功能確保服務啓動正常後,再刪除老的容器,達到不停機升級的目的。
目前DevOps集成了單元測試(包括自動生成單元測試用例)、接口測試、性能測試的功能。單元測試大部分狀況下仍是須要開發人員寫用例,自動生成單元測試用例的功能並非那麼好用,因此用戶較少,但在流水線上會自動進行單元測試,並將結果反饋給用戶:
單測結果是基於Sonar的,在Jenkins上執行完單測後連同靜態檢測結果一塊兒發佈到Sonar,在Sonar上配置了通用的過濾條件,能夠過濾掉部分不須要統計單測的代碼(如框架自動生成的代碼不計入單測覆蓋率),用戶能夠在此基礎上配置其餘過濾條件。
接口測試和性能測試方面,咱們在DevOps平臺上作了一個關聯的功能,每個接口測試或者性能測試用例,都對應一個項目工程,關聯關係梳理好後能夠實如今發佈流水線的任意環節觸發接口測試或者性能測試。
和項目工程關聯:
發佈流水線觸發接口測試:
發佈流水線觸發性能測試:
自動化測試的結果展現方面目前作的不夠好,只是在日誌中提供連接,用戶點擊連接進去查看結果。
CMDB做爲底層的統一資源管理中心,負責跨數據中心的混合雲管理,提供統一的資源管理平臺,無論私有云仍是公有云,無論虛擬機仍是Docker都統一管理,同時提供對底層服務的訪問支持。提供機器與宿主機的拓補圖關係等,對基礎設施的管理提供了便利。
一套OpenStack表示一個虛擬化集羣,一套Kubernetes表示一個容器雲集羣,每一個數據中心有一套或多套OpenStack和Kubernetes。CMDB經過數據中心和可用區來標示不一樣的集羣。任何須要和虛擬機和容器對接的功能統一由CMDB提供接口管理。
DNS做爲附加的功能,可由用戶直接點擊一個按鈕實現域名解析:
域名解析是一個比較複雜的過程,它須要和後臺不少系統交互,還須要根據事先定義好的Nginx模版生成配置,Docker的服務還須要進行動態服務發現,最終將域名信息註冊到DNS中。
DevOps平臺同時支持對虛擬機和Docker的擴縮容功能,只要對應數據中心存在對應的服務,就能夠進行擴縮容,一次擴容節點不能超過10個,縮容節點數最少保留一個。
咱們能對不一樣數據中心的服務進行擴縮容,而且全部的操做都有事件機制,能將每一個服務所使用的資源進行歸檔管理,最終能夠對各個部門所使用的資源進行服務器成本費用結算。
從瀏覽器進入服務器,且經過權限控制,有權限人員才能進入,更加方便排查問題:
DevOps已經集成了監控的部分功能,包括接口調用狀況、全站可用性、監控數據排行榜、金絲雀分析等。
可用性監控
監控數據排行榜
接口調用狀況
金絲雀分析
金絲雀分析主要用於在代碼發佈到灰度環境時,分析灰度環境和線上環境的相關指標值對比,以確保新版本代碼質量沒必要老版本差。
目前只有如下幾個指標數據,後續將不斷完善指標內容:
灰度環境和線上環境都承擔用戶流量,經過Nginx的Upstream進行權重設置,咱們能夠根據金絲雀結果作一次上線發佈前的質量評估。
雖然咱們完成了DevOps的大部分功能,要講到技術細節,上面的每個小節都能用一篇文章來說解,因此之後咱們會不斷分享咱們在DevOps中的一些技術細節,固然咱們也還有不少須要優化和改進的。需求蒐集和規劃、項目管理和發佈關聯、自動化測試、金絲雀分析的改進、自助做業平臺、CMDB對混合雲的管理等都是後續須要改進的,總體的規劃圖以下:
DevOps平臺功能架構分佈中,還有不少工具以及功能未描述,上面講到的每個點均可以展開爲一篇文章作詳細介紹,這裏主要爲2017年作一個總結。
以上內容爲豬八戒網最近幾年來整個DevOps的發展演進史,公司的規模不一樣,總體架構以及方法可能不一樣,對於豬八戒來講,DevOps還在繼續演進,同時也會不斷學習業界優秀實踐,爲業務發展提供最基礎的保障。