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