阿里超大規(guī)模Docker化之路
12月6-7日,由阿里巴巴集團、阿里巴巴技術(shù)發(fā)展部、阿里云云棲社區(qū)聯(lián)合主辦,以“2016雙11技術(shù)創(chuàng)新”為主題的阿里巴巴技術(shù)論壇上,阿里巴巴研究員林昊分享了阿里超大規(guī)模Docker化之路。阿里在Docker化這條路上,碰到了規(guī)模、多元化場景所帶來的各種挑戰(zhàn),這次分享中將給大家介紹阿里為什么要引入Docker,以及如何完成這次超大規(guī)模的Docker化。
Docker化之前
Docker化之前,阿里主要交易業(yè)務(wù)已經(jīng)容器化。采用T4做容器化,T4是2011年開發(fā)的一套系統(tǒng),基于LXC開發(fā),在開發(fā)T4的過程中,跟業(yè)界很大的不同在于,T4更像VM的容器。當(dāng)用戶登進(jìn)T4后,看起來與標(biāo)準(zhǔn)的KVM等幾乎完全一樣,對用戶來講是非常透明化的。所以,容器化不是我們推進(jìn)Docker的原因。
a)觸發(fā)我們Docker化的主要原因一:Docker最重要的一點是鏡像化,可以做到拿著鏡像就可以從一臺完全空的機器的應(yīng)用環(huán)境搭建起來,可以把單機環(huán)境完全從零搭好。Docker化之前,阿里巴巴的應(yīng)用部署方式主要由Java、C來編寫的,不同的業(yè)務(wù)BU可能采用完全不同的部署方式,沒有統(tǒng)一標(biāo)準(zhǔn)。內(nèi)部嘗試通過基線來建立部署標(biāo)準(zhǔn),定義的基線包括應(yīng)用依賴的基礎(chǔ)環(huán)境(OS、JDK版本等)、應(yīng)用依賴的腳本,基礎(chǔ)環(huán)境的配置(啟動腳本、Nginx配置等)、應(yīng)用目錄結(jié)構(gòu)、應(yīng)用包、應(yīng)用依賴的DNS、VIP、ACI等,但不成功。部署標(biāo)準(zhǔn)做不了,直接導(dǎo)致自動化很難做到。
b)觸發(fā)我們Docker化的主要原因二:DevOps是一個更好的方向,阿里巴巴做了很多運維和研發(fā)融合的調(diào)整。Docker是幫助DevOps思想真正落地的一種手段,所有的思想最終都體現(xiàn)在工具或框架上,變成一個強制性的手段,Docker會通過Dockerfile的描述,來聲明應(yīng)用的整個運行環(huán)境是怎樣的,也就意味著在編寫Dockerfile過程中,就已經(jīng)清楚在不同環(huán)境中的依賴狀況到底是怎樣的,而且,這個環(huán)境是通過一個團隊來維護的。
Docker化目標(biāo)
2016年7月,阿里巴巴制定了兩個Docker化目標(biāo):
- 交易核心應(yīng)用100%Docker化;
- DB其中一個交易單元全部Docker化。
Docker化之路
推進(jìn)Dcoker之前,我們有一個準(zhǔn)備的過程。在準(zhǔn)備階段,我們需要Docker更像VM和更貼合阿里運維體系的Docker,我們將改造過的Docker稱為AliDocker;除了AliDocker以外,我們需要支持AliDocker的工具體系,比如編譯、鏡像庫、鏡像分發(fā)機制,在完成這些準(zhǔn)備工作后,我們認(rèn)為可以一帆風(fēng)順地開始大規(guī)模的AliDocker上線。但事實并非如此。
***輪Docker化
我們碰到了很多問題:
- 工具不完善,阿里很多應(yīng)用之前都是在T4容器中,怎樣將T4容器轉(zhuǎn)換成AliDocker是首要面臨的問題;
- 鏡像Build后上傳,以前阿里一個應(yīng)用轉(zhuǎn)成多個,很多時候需要在自己的機器上做Build,然后自己上傳,導(dǎo)致做應(yīng)用時很痛苦;
- 應(yīng)用從T4切換成走Docker的鏈路,鏈路沒有完全準(zhǔn)備好,從資源創(chuàng)建到發(fā)布,很多需要手工去做,大規(guī)模去做效率非常低。
第二輪Docker化
在推進(jìn)的過程中,我們又遭遇了新的問題。Docker的發(fā)布模式是典型的通過鏡像,拉到鏡像后將原來的容器銷毀,重新創(chuàng)建一個容器,把鏡像放進(jìn)去,拉起來。Docker單一化的發(fā)布方式支持不了多種發(fā)布模式,更改velocity模板發(fā)布效率低;有本地內(nèi)存cache的發(fā)布,重啟本地內(nèi)存cache就會消失。怎樣在基于鏡像模式情況下又能支持多種發(fā)布模式呢?
我們在Docker的鏡像模式基礎(chǔ)上做出一個crofix的模式,這個模式不是繞開鏡像,而是從鏡像中拉起我們需要的文件,去做覆蓋等動作,這樣就可以完成整個發(fā)布。Docker化鏡像模式是必須堅持的,否則失去了Docker化的意義。
第三輪Docker化
繼續(xù)推進(jìn)到很多應(yīng)用切換到Docker的時候,我們又遇到了更大的問題:
首先,很多研發(fā)人員都有明顯的感受,切換到Docker后變慢。***,編譯打包鏡像慢,編譯打包完應(yīng)用的壓縮包后,還需要把整個環(huán)境打包成鏡像,這是在原有基礎(chǔ)上增加的過程,如果編譯時每次都是新機器,以前依賴的所有環(huán)境都要重新拉,一個應(yīng)用Docker的完整鏡像通常會很大,因為它包括依賴的所有環(huán)境。
對此,我們在編譯層做了很多優(yōu)化,盡可能讓你每次都在之前編譯的基礎(chǔ)上進(jìn)行編譯。第二,鏡像壓縮問題,Go在1.6以前的版本壓縮是單線程,意味著壓縮整個鏡像時效率會非常低,所以我們選擇暫時把鏡像壓縮關(guān)閉掉。
其次是發(fā)布問題,Docker的鏡像化模式?jīng)Q定了分發(fā)一定是鏡像分發(fā),使用Docker時不能完全把它當(dāng)作透明化東西去用,對所有研發(fā)人員來說,要非常清楚依賴的環(huán)境、Dockerfile中鏡像的分層改怎么做,將頻繁變化部分與不頻繁變化部分做好分層,鏡像分層是改變Docker慢的重要方案;
阿里制定了鏡像分發(fā)多機房優(yōu)化,比如打包后將所有鏡像同步到所有機房;阿里也做了發(fā)布優(yōu)化(P2P、鏡像預(yù)分發(fā)、流式發(fā)布),還通過Docker Volume將目錄綁定到Dockerfile中,可以保證鏡像文件每次拉起時不會被刪掉。
在整個Docker化的過程中,我們在“慢”這個問題上遇到了***的挑戰(zhàn),不管是編譯慢還是發(fā)布慢,都做了很多突擊的改造項目,***才讓整個編譯過程、發(fā)布過程在可控的響應(yīng)速度內(nèi)。
第四輪Docker化
在推進(jìn)過程中,我們還遇到規(guī)模問題:
由于規(guī)模比較大,開源軟件很容易碰到支撐規(guī)模不夠,穩(wěn)定性差的問題。目前我們使用Swarm來管理,Swarm的規(guī)模能力大概可以支撐1000個節(jié)點、50000個容器,而我們需要單Swarm實例健康節(jié)點數(shù)在3W+,對此,我們對Swarm進(jìn)行了優(yōu)化。
規(guī)模我們做到從支撐1000到3W+,壓力減小了很多。而Swarm的穩(wěn)定性對我們來講,***的問題在HA上,一個Swarm實例如果掛掉,重新拉起需要時間,所以我們在用Swarm時進(jìn)行了改造。在前面加了一層Proxy,不同業(yè)務(wù)、不同場景都可以通過Proxy轉(zhuǎn)換到自己不同的Swarm實例上。另外,所有的Swarm節(jié)點我們都會用一個備方案在旁邊,而且都是不同機房去備。
通過改造增強HA機制后,可以做到每次切換、簡單發(fā)布。
Bugfix和功能增強
除了上面四輪次比較明顯的問題,在整個Docker化過程中,還做了很多的Bugfix和功能增強,具體有以下幾方面:
- Daemon升級或crash后,所有容器被自動銷毀的問題;
- Cpuset、cpuacct和CPU子系統(tǒng)mount到一起時CGroup操作錯誤的bug;
- 支持基于目錄的磁盤配額功能(依賴內(nèi)核patch);
- 支持制定IP啟動容器,支持通過DHCP獲取IP;
- 支持啟動容器前后執(zhí)行特定腳本;
- 支持鏡像下載接入各種鏈?zhǔn)椒职l(fā)和內(nèi)部mirror的機制;
- 增加Docker Build時的各種參數(shù)優(yōu)化效率和適應(yīng)內(nèi)部運維環(huán)境;
- 優(yōu)化Engine和Registry的交互。
經(jīng)歷了這么多坎坷,我們終于完成了全部目標(biāo),實現(xiàn)雙11時交易所有核心應(yīng)用都AliDocker化,DB其中一個交易單元全部AliDocker化,生產(chǎn)環(huán)境共幾十萬的AliDocker。
未來
容器化的好處是可以把很多對物理機型的強制要求虛擬化,可能也需要Docker在內(nèi)核層面的改造,對于未來,我們已經(jīng)做好了準(zhǔn)備,希望:
- 所有軟件AliDocker化;
- 和Docker公司緊密合作回饋社區(qū);
- AliDocker生態(tài)體系逐漸輸出到阿里云。