自動構建系統是從美團的自動部署系統發展出來的一個新功能。每當開發人員提交代碼到倉庫后,系統會自動根據開發人員定制的構建配置,啟動新的Docker容器,在其中對源代碼進行構建(build),包括編譯(如Java、C++和Go)、預處理(如Javascript和CSS)、壓縮(如圖片)等操作,生成最終需要上線的程序包。
背景
美團的代碼發布系統有中央控制節點,負責代碼的拉取、應用的構建和上傳等任務。隨著業務的迅速增長,應用發布項的數目和單個發布項的服務器數量也隨之增長,中控節點的任務加重,幾個問題也變得亟待解決:
不同應用的構建環境在同一個虛擬機上,需要解決環境沖突和隔離的問題
多個應用同時構建會競爭發布機的CPU和IO資源,讓構建變慢
應用的構建腳本運行在公共發布機上,腳本的bug可能會影響到發布機的正常運行
例如某次主站(PHP)的發布速度非常慢,調查后發現當時某些Java應用正在編譯,占用了大量CPU資源,導致其它應用的發布變慢。
為解決上述問題,我們設計了把應用的構建過程從中央發布機分離出來的方案,并利用Docker作為構建的基礎環境。關于Docker的介紹,可以參考《Docker系列之一:入門介紹》這篇文章。
原理
首先,開發人員在Stash上配置自動構建,之后的代碼提交就會通知自動構建系統。自動構建系統收到通知,找到所有配置了該倉庫的發布項,生成構建任務,并把這些任務提交到Django-rq隊列。任務的主要配置是YAML格式的自動構建配置文件,該文件類似Dockerfile,但是為了使用方便,只支持少量的關鍵字,因此比Dockerfile使用更簡單。通過該配置文件可指定構建容器使用的鏡像,一些環境變量,以及構建命令等。系統從私有的 Docker registry獲取鏡像,并根據YAML配置生成Docker容器,在此容器中完成構建。
從Stash觸發自動構建的功能,是從這個項目修改實現的,只需簡單配置即可啟用自動構建。
構建成功的結果會自動上傳到美團存儲服務(Meituan Storage Service)。當發布人員發布時,就直接從MSS拉取構建好的應用包進行發布,省去了在發布時才進行的編譯環節。
為什么用Docker?
為了達到隔離構建環境的目的,應用的構建可以在分別的美團云虛擬機上實現。但是,應用構建有一些特點讓Docker在此場景更合適。首先,構建環境都是臨時的,每次構建結束后就銷毀(也可選擇保留)。而我們內部使用的美團云虛擬機是和運維用的配置管理數據庫(Configuration Management Database)關聯的,新虛擬機會自動部署一些基礎環境、監控報警項等,并注冊進CMDB,而這些東西對自動構建的系統是多余的。第二,自動構建的系統啟停頻繁,Docker這樣的輕量級容器可以更好地滿足快速生成和銷毀的需求。因此,自動構建系統是在美團云虛擬機里面運行的Docker容器中進行的。
收益
自動構建很好地解決了文章開頭提到的發布系統的三個問題:
自動隔離不同應用的構建環境,無需擔憂環境沖突的問題
不同應用的構建容器不必運行在同一臺虛擬機,可以分布在多虛擬機的集群上,避免了構建之間的資源競爭,讓構建過程更加迅速
任一應用構建的錯誤不會影響其它應用的構建或者中央發布機的運行
此外,自動構建還有如下兩個好處。
首先,預先的主動構建把冗長的構建時間從發布過程省去,讓發布人員在發布時耗時更短,既讓發布更敏捷迅速,又提升了用戶體驗。美團在工作日每天的代碼發布要上千次,快速的發布過程才能更好地保證業務的迭代過程。
其次,自動構建讓構建環境的定制更方便。原來在發布機上構建時,如果需要的依賴在發布機上還沒有,就需要給運維人員提需求來進行配置,這個過程不夠敏捷。使用自動構建后,開發人員可自行在YAML格式的配置文件指定構建環境。前端開發人員的構建環境往往比較新,需要頻繁改變環境,因此支持自定義依賴的自動構建系統受到了前端開發人員的歡迎。
總結和展望
自動構建目前是發布項配置里面的一個可選項,這保持了和原有系統的兼容。自動構建是美團在線上業務中首次使用Docker。我們會持續推進該特性在自動部署系統的使用,最終成為所有發布項的默認配置。
自動構建使用Docker的方式,為我們后續更廣泛地使用Docker提供了啟發。
第一,將Docker用于開發環境。通過Dockerfile描述測試環境,并維護起測試環境的Docker鏡像,可以讓開發人員快速搭起來一個統一的開發環境;再結合Vagrant,可以很好地解決研發團隊中普遍存在的測試環境搭建麻煩的問題。
第二,將Docker用于應用部署。完成自動構建后,容器中已經有了應用程序包,再加上運行時依賴,即可讓這個容器直接提供服務。
未來可以在應用的開發測試,編譯構建,和部署運行等三個環節,都使用Docker容器。關于Docker在上述場景的應用,請關注我們博客的后續更新。