1 前言nginx
當代信息技術飛速發展,軟件和系統的代碼規模都變得愈來愈大,並且組件衆多,依賴繁複,每次新版本的發佈都彷彿是乘坐一次無座的綠皮車長途夜行,疲憊不堪。軟件交付是一個複雜的工程,涉及到軟件開發的各個細節,其中任何一環出現問題,都會致使軟件不能及時交付,或者交付的質量堪憂。git
從企業的角度來說,如何利用更科學的工具、更科學的流程來提升產品質量,提高客戶滿意度,是剛需。從員工角度來說,生命裏值得追求的事情不少,不能把寶貴的時間浪費在一些機械的、重複的事情上面。數據庫
聯想企業網盤從2007開始面向企業客戶提供專業的雲存儲服務,10年來服務了250000+企業。軟件的更新迭代司空見慣,聯想企業網盤就是由成百上千臺服務器組成的,是一個很是複雜的互聯網應用,僅僅在服務端就有幾十個模塊協同工做,加上各類客戶端,須要使用不一樣的編譯發佈環境,有時候須要單獨模塊發佈,有時候須要多個模塊聯合發佈,使得每次的升級狀況都很是複雜。曾經經歷過一次大版本的升級迭代,運維和研發團隊不眠不休的工做了40多個小時,既影響了用戶的服務,也使得團隊疲憊不堪。相似的經歷,使得咱們思考如何經過技術革新來解決這一難題,可以把咱們的工程師們從簡單勞動中解放出來,這樣在將來面對更大規模的集羣的時候,纔可以遊刃有餘。服務器
縮短上線時間,提升上線準確度,是咱們建設這個系統的初衷。運維
2 問題分佈式
先讓咱們借用一張圖(來源於 thoughtworks 官方文檔)來回顧一下軟件發佈的一個完整的流程:模塊化
整個過程當中,代碼管理,集成和測試,發佈上線是3個主要的環節。咱們全部的問題都集中在這3個環節當中。工具
一、代碼管理post
代碼管理混亂是一個研發團隊的常見問題,研發的過程當中,代碼的分支設計不合理,分支過多或者過少,分支依賴混亂,權限控制缺失,徹底靠人治,沒有代碼審覈。單元測試
二、集成和測試
從研發環境到測試環境,都沒有統一規範的部署環境,研發團隊直接給測試出版本(野版本),由於編譯環境,人員水平的差別會致使各類莫名其妙(有時候很低級)的問題,極大的影響了測試的效率和準確度。
三、上線交付
代碼最終部署到生產環境的時候,須要運維人員和研發人員頻繁手工操做,費時費力,還容易出錯,整個過程不可重複且沒有記錄,回滾操做複雜,有時候甚至是沒法回滾的,一旦是上線出現錯誤,對咱們用戶的影響就是很是惡劣的。
3 實踐
多年來,咱們在研發過程當中不斷總結,想了不少的辦法,在服務客戶的同時積累了大量的生產環境運維經驗,開發了許多工具和流程,來解決升級和產品上線的問題。,下面基於聯想企業網盤的生產實踐,分享一些咱們在建設持續交付系統方面的方法。
以下圖所示,咱們主要討論這幾個方面:
3.1 代碼管理
代碼是軟件交付過程的源頭,因此合理的規劃與管理尤其重要。
3.1.1 代碼倉庫
早期,咱們全部研發人員的代碼都存放在一個 SVN 庫裏,分支和 Tag 散佈在各個模塊的子目錄裏。SVN 是很好的一個工具,可是太靈活了,要你們嚴格遵照紀律,可是更多時候要靠你們自覺,可是人老是會有鬆懈的時候。一旦有人不守紀律,對於後來者就是一個苦不堪言過程。
因此咱們的第一步,就是把 SVN 遷移至 Git。按照模塊拆分爲單獨的庫,每一個模塊單獨受權,統一分支模型。倉庫軟件用的 Gerrit,它本來是代碼審覈工具,擁有強大的權限管理系統,Git 倉庫只是附帶的功能。
其實在從SVN遷移到Git的時候,有不少工程師會有疑問,爲何遷移到 Git?不是 SVN 很差,也不是爲了追逐技術潮流,而是後面的自動化工做(包括代碼審覈工具)用 Git 更方便,固然 Git 強大的分支功能以及分佈式也是一個重要緣由。
3.1.2 分支設計
分支咱們參考比較常見的一個 Git 分支模型(參考連接),針對咱們本身的需求作了一些調整,以下圖:
一、 設計兩條主分支,dev 和 master,dev 是開發分支,master 是對外的穩定分支,持續交付系統會從master分支拉取代碼進行構建;
二、 輔助分支只使用 feature 分支和 hotfix 分支,feature 分支原則上是儘可能不建,只用於開發週期比較長的新功能開發,短平快的 feature 都直接提交至 dev。
3.1.3 審覈
代碼是產品質量的源頭,代碼質量不行,其餘再多輔助手段都沒用。代碼審覈是保證代碼質量相當重要的一環。只要團隊人員數大於一個就應該推行代碼審覈。
代碼審覈有兩種模式:
l 集成前審覈(pre review)
顧名思義,在代碼合併至目標分支前進行代碼審覈,有問題改,改完再繼續審覈,審覈經過則集成進目標分支,這一類審覈的表明工具軟件有:Github,Gerrit,其中 Github 是以分支爲單位進行審覈,Gerrit 以提交爲單位進行審覈。
l 集成後審覈(post review)
先合併代碼,而後進行審覈,有問題只能用新的提交來修復了,這一類審覈的表明工具軟件(其實這兩款軟件也支持 pre review):reviewboard,phabricator。此種方式容易致使目標分支不穩定,因此通常不建議。
咱們採用的是第一種集成前審覈的方式,工具軟件用的 Gerrit,以提交爲單位,強制審覈事後再合併至目標分支(固然這個過程是自動的)。
好了,話很少說,有圖有真相,下圖是咱們的代碼提交工做流:
圖中黃色的部分便是代碼審覈的部分,每一個提交須要通過其餘人審覈(Code Review +2)和持續集成系統驗證過(Verify +1)才能合併至目標分支。
代碼審覈頁面:
3.2 構建部署
在這裏我簡單的將構建部署分爲持續集成和部署流水線,實際上,這兩塊不少地方有重合,這裏的持續集成僅僅只討論構建驗證和自動集成,部署流水線包括從構建到部署至不一樣環境的整個過程。
3.2.1 持續集成
持續集成是一個大的議題,是敏捷開發的一項核心實踐。在持續交付過程中,持續集成將從開發到部署的各個環節組成一條流水線,是整個交付過程的核心。重點是要快速反饋,在集成代碼以前迅速發現問題並改正。
咱們把單元測試、編譯驗證、靜態掃描和覆蓋率檢測分離出來(這一步驟的時間控制在 5分鐘內,這也是前面爲何要把庫拆分的緣由之一),在研發人員提交代碼後當即觸發構建,在5分鐘內把結果反饋給研發人員,繼而快速修復錯誤,直至驗證經過。
咱們採用的工具軟件是 Jenkins,最流行的持續集成軟件,經過插件支持 Gerrit,功能很是強大。
在實際的實施過程中,要求每一個模塊都要提供在一個乾淨環境執行編譯、單元測試等等步驟的腳本或方法,構建環境能夠經過 Vagrant 或者 Docker 來自動配置,咱們內部採用了Docker 技術來隔離各個構建環境。
流水線
3.2.2 部署流水線
顧名思義,這一步驟就是把打包好的軟件部署到不一樣的運行環境,而且要自動處理各個環境的配置(例如域名、數據庫信息、登陸信息等等),此步驟嚴重依賴於前面步驟的實現,倉庫的規劃、分支的規劃、持續集成的流水線構建等等。
一個典型的部署流水線
在構建部署流水線的時候,咱們要遵循幾個原則:
一、 過程可重複;
二、 一次構建多地部署;
三、 模塊化部署;
四、 變動管理;
五、 審計功能;
六、 快速回滾。
在選擇部署工具方面,咱們考察過兩個:thoughtworks go 和 Jenkins(插件 Delivery Pipeline)。
Go 系統自帶管道,可是靈活性不如 Jenkins;Jenkins 的一個好處是咱們的持續集成都在 Jenkins 裏實現,不少腳本均可以複用,甚至不少任務都能直接複用,缺點是管道各任務之間數據共享比較繁瑣,須要額外的插件(例如 Copy Artifact),因此實現的不是很天然。
在實際的實施過程中,可以徹底實現自動化(無人值守發佈)是一種理想狀態,但實踐當中老是會受各類因素制約,因此必要時也必須向現實低頭。咱們最終實現了一鍵部署加關鍵環境(例如生產環境)手工觸發(下面圖中的播放小箭頭就是這樣的步驟)相結合的流程,參見下圖:
在實施過程中,配置文件的管理也是很重要的一個議題。配置文件主要分爲兩類:
一、 配置文件與運行程序不能分離,像J2EE這樣的應用,配置文件與編譯成果物打包成一個 war 文件,咱們的處理方法是把敏感信息(例如數據庫信息)存放在其餘的Git 庫,構建的時候針對不一樣環境分別構建,構建時由Jenkins 自動記錄代碼的版本和配置文件的版本;
二、 配置文件與運行程序能夠分離,相似於 nginx 這樣,咱們把程序打包成 rpm 或者 deb ,配置文件存放在 puppet 主服務器上,每次部署都觸發 puppet 的自動分發。
在持續交付流程中,咱們能夠清楚的知道當前每一個環節,每一個節點都處在一個什麼版本狀態,這對於清晰的瞭解,快速回滾很是有用。參見下圖,某項目部分模塊不一樣環境版本信息(請忽略頁面醜陋這個細節,紅色即表示某個模塊正在發佈,還沒最終上線):
@IT薄荷葉:4 尾聲 目前聯想企業網盤的服務已經全面採用流程化的上線交付體系,從研發環境到測試環境到生產環境,所有是流水線做業,保證了各個模塊間代碼和版本的一致性,表明的集成、發佈只須要咱們輕點一下鼠標,而後就能夠喝着茶耐心等待收到發佈成功的郵件了。 持續交付是一個長期的須要不斷完善的過程,公司的策略在變,產品需求在變,人在變,流程也在變,咱們所作的僅僅是開始,還須要繼續去摸索,磨合,打造出更爲完善的交付系統。這是一個任何軟件開發團隊都須要重點考慮的事情,創建規範,制定流程,利用科學的工具來實踐規範和流程,脫離小做坊式的交付模式,按時按質按量交付產品。 (1小時前)
http://www.oschina.net/question/2448759_2186294