基于docker的私有構建實踐
來自: http://dockone.io/article/1017
docker技術的應用談的比較多的是改變服務器管理和運維模式,在日常開發工作中如何使用docker看到的實踐比較少。最近在團隊中嘗試著基于docker改進開發團隊的私有構建設置,取得了不錯的效率改進。這也證明了同樣的工具能有不同的玩法,記錄一下希望能夠對同業有一些啟發作用。
首先介紹一下項目背景。我們的系統,是一個另類投資的會計和凈值計算系統。它基于Client/ Server的架構,基礎開發語言是Java,前臺使用了AWT/ Swing的框架。這個應用有超過20年的歷史,目前整個代碼庫中JAVA代碼有超過140萬行,SQL代碼接近120萬行。
當前有將近100名開發人員在全球超過3個時區工作,日均代碼提交次數在400次左右。
盡管開發時間很長,代碼規模也很大,但通過良好的編碼規范,嚴謹的開發過程約束,以及自動化程度很高的持續集成體系,代碼得到了妥善的維護,技術債很輕。超過140萬行的JAVA代碼,單元測試覆蓋率超過60%,總技術債在600+人天左右,這個對于百人規模的開發團隊來說,是一件非常了不起的事情。
交付質量的另一個重要保障因素,就是大規模的持續自動化回歸測試(acceptance test,縮寫AT)。我們使用了jemmy的測試框架,整個測試倉庫包括8000+測試用例,有十幾臺PC作為Jenkins slave,按照測試套件的組織,在每天晚上全量運行所有8000+測試用例,這樣開發團隊每天得到一份基于最新代碼的回歸測試報告和相應的代碼覆蓋率報告,為及時發現和解決質量問題提供了可靠的幫助。最長的測試套件單次運行時間超過12小時。
這些運行AT的PC,他們的環境setup和開發人員的機器設置是一樣的,換句話說,當有實際需要的時候,任何一個開發的機器都能夠被用作獨立完整的AT環境運行回歸測試,或者對整個系統進行集成測試。這種應用的設置和部署方式我們叫做Private Build,中文叫做 “私有構建”。我嘗試過搜索private build的定義但是并沒有找到任何相似的實踐方法,所以我這里嘗試著給一個定義:
所謂私有構建,是指開發者不依賴外部共享資源(數據庫、MQ、文件服務器等等),在本地環境以統一、簡便的方式完成軟件應用的構建、運行和測試的全部工作。
在一個涉及大規模團隊開發協作的項目中,經常碰到的問題就是“環境永遠少一套”。拋開從無到有構建一個完整可工作應用的代價不談,當代碼庫還在很活躍地進化的時候,維護一套可以平滑集成代碼變更保持穩定工作的獨立環境是一件非常困難的事情。當項目團隊需要一個獨立的環境與他人進行集成或者執行某種特殊測試(比如說性能、安全等)的時候,他們通常會發現需要花費很大的代價去“更新”這套環境,這種代價可能大到讓人望而生畏。如果擁有一種“統一、簡便的方式(甚至簡單到一鍵式)完成軟件應用的構建、運行和測試的全部工作”,會讓這種畏懼消失無蹤。
私有構建能夠有效減少新成員在工作環境構建的學習成本,減少團隊內部由于各自工作環境設置不一樣帶來的對交付質量的影響。標準化的私有構建設置意味著能夠以很低的代價快速建立一套獨立的測試環境,當系統隨時間演化積累了越來越多的回歸測試用例的時候,擁有這樣快速擴展測試環境能力的重要性是不言而喻的。
當然,私有構建需要被包含在完整的持續集成體系里面才能發揮更好的作用,我們持續集成的概念圖如下:
中間把“本地開發環境”和“回歸測試環境”兩個方框聯系在一起的部分,就是我們的私有構建環境。開發人員的本地環境既有IDE,也能夠快速啟動包括了服務器、客戶端和一個oracle express數據庫的完整的AT環境。
要能真正實現“一鍵式”建立私有構建環境,對應用架構、配置和變更管理以及本地環境資源利用的有效性都有很高的要求。這件事情能夠當作一個完全獨立的話題來討論,這里就不展開了。這套體系穩定運行了很多年,為項目的發展立下了汗馬功勞。但是在最近的幾年里面,我們遇到了一些新的挑戰。
- 為了保持持續交付能力(代碼的健康程度),AT運行必須在第二天工作開始之前完成,這個時間窗口在4到8小時左右。
- 隨著業務的發展,開發團隊的規模也在不斷擴大,同時每日提交的代碼變更數量也在不斷地提升。這也意味著更多的AT測試用例,更長的總運行時間。為了保證在固定的時間窗口完成這些測試,需要更多的測試機器。之前的AT環境,需要專門的PC桌面運行,但能夠提供出來運行AT的資源是有限的,并且我們也希望控制需要“專門”用來運行AT的PC機器,因為專門的環境意味著需要有專門的人去維護。
為了解決這個矛盾,我們首先的嘗試是把服務端和數據庫打包進一個Ubuntu的VirtualBox鏡像(因為AT運行需要AWT/ Swing環境,保留在windows比較方便)。改動前的私有構建拓撲結構如下:
改動以后變成了這樣:
新的工作方式以VirtualBox虛擬機鏡像的方式統一了AT環境主要模塊(服務端和數據庫)的設置,簡化了AT環境搭建的代價。但是從實戰的效果來說,一臺PC機上啟動一個VirtualBox鏡像加上Client端運行AT,CPU和內存的使用就已經超過70%(16G內存,雙核四線程CPU)。這樣從本質上說仍然是一臺機器上運行一套AT環境,并且有一部分模塊(client端)的構建和PC的設置是直接相關的。盡管后期我們通過標準化的構建命令以及VAGRANT的引入進一步簡化了構建環境設置和AT啟動的工作,但是仍然覺得有些缺憾。尤其是當需要同時啟動AT測試和運行自己的IDE的時候,這種模式有點捉襟見肘的感覺。這時候,docker進入了我們的視野。
由于docker的輕量化特性,能夠以更少的資源運行所需要的進程。如果能夠將AT環境的所有模塊都通過docker運行在同一臺PC上,并且使得一臺PC能夠支持多套AT同時運行,理論上每個開發人員的PC都可以成為一套單獨的環境,并且不影響日常的開發工作。要達到這個目標,我們也面臨著一些實際的挑戰:
? 公司內部認證的Linux版本是3.0,我們重新基于Linux 3.1制作了一個VirtualBox鏡像。
? 由于公司網絡安全的限制,Boot2docker沒法在PC上面安裝,我們必須通過比較重的VirtualBox來裝載docker engine。最終拓撲結構變成了以composite的方式將oracle express,服務端和客戶端分別包裝進三個不同的docker image,在同一個docker engine上啟動。
? 當所有模塊都通過docker啟動的時候,client端AT需要在Linux環境下驅動。一方面需要基于Linux的AWT/ Swing重新編譯客戶端,另一方面在客戶端的docker環境里面安裝tightVNC來支持用戶界面的渲染從而讓AT能夠被驅動。
解決這些問題之后,新的拓撲結構如下:
在一個VirtualBox的鏡像里,包括oracle、服務端和客戶端三個docker鏡像。不同docker鏡像通過docker compose被組合起來構建和啟動。客戶端通過tightvnc進行swing UI的渲染,從而實現在Linux環境下也能運行AT測試。關于docker compose,可以參考docker blog:
http://blog.docker.com/2014/12 ... apps/
或者 https://docs.docker.com/compose/
簡單的說,docker compose是官方提供的容器業務流程框架,只需要通過簡單的yml配置,就能按照指定的依賴關系完成多個容器服務的構建和運行。它提供了一些必要的命令和參數像links、ports、volumes。我們只使用了最基本的來指定三個鏡像的啟動順序。
oracle:image: $machine_name:$port/oracle
server:
image: $machine_name:$port/server
client:
image: $machine_name:$port/client
links:
oracle
server
env_file:
./$app.env</pre>
這里的啟動順序是先oracle,再server,最后client。在實踐中,基于docker的私有構建環境,一臺PC運行一套AT環境,CPU和memory的利用水平大概在40%不到;同時運行兩套AT環境,CPU和memory的利用水平也就80%左右。開發人員完全可以做到在一臺機器上既做開發也運行AT互不干擾。更重要的是,所有的AT模塊都被封裝到一個虛擬機環境中,成為一個完全標準化的“私有構建”環境,我們的期望也比較完整地被滿足了。
最后整理一下我們基于docker的私有構建環境建立過程:
1. 制作三個docker鏡像,分別對應Oracle、客戶端和服務端。客戶端鏡像中一并包括tightVNC server提供linux環境中的桌面行為能力;
2. 在VirtualBox虛擬機里面安裝docker鏡像;
3. 將VirtualBox鏡像分發給開發團隊;
4. 將VirtualBox虛擬機注冊成一個Jenkins Slave;
5. 每個虛擬機鏡像上啟動兩套AT環境;
拓撲示意圖如下:
這樣每個開發人員的PC,在工作的時候可以提供一個獨立的測試環境供開發人員調試和測試。在空閑的時候,可以作為回歸測試環境運行兩套AT。并且每次啟動AT的時候,私有構建環境都是非常干凈的,避免了環境差異帶來的AT運行不穩定問題。
下一步我們的計劃是構建自己的docker registry,并且通過docker swarm實現docker進程的管理和水平擴展。心目中的目標架構是這樣:
回顧整個實驗的經歷,坦白說我覺得技術上遇見的挑戰并沒有想象的那么大。反而是打破在大公司工作的舒適區或者說無形的束縛,尋找解決問題新思路的第一步比較難跨越。呼應一下開頭的話,這個例子只是一個普通的工程問題,很可能許多人在日常工作中也能遇見類似的問題。我們的實踐說明了有了合適的切入角度,docker在這樣巨細而微的場景下也成為一個很接地氣的解決方案。
</div>