天天看點

阿裡如何實作100%容器化鏡像化?八年技術演進之路回顧

八年時間,阿裡集團實作了 100%内部容器化鏡像化,經曆了幾代演進。本文将從最初的架構開始,向大家介紹下阿裡内部的容器化演化過程。

PouchContainer 現在服務于阿裡巴巴集團和螞蟻金服集團的絕大部分 BU, 包括交易&中間件,B2B/CBU/ICBU,搜尋廣告資料庫,還有收購或入股的一些公司,比如優酷高德、UC等。其中體量最大的是交易和電商平台,在 2017 年雙 11 的時候我們支撐了破紀錄的峰值,背後的應用都是跑在 PouchContainer 裡面,整體容器執行個體已經到了百萬級規模。使用了 PouchContainer 的應用涵蓋了各種各樣的場景。這些場景從運作模式來看,有标準的線上 App,還有像購物車、廣告、測試環境等比較特殊的場景。不同的場景對 PouchContainer 有不同的使用方式和需求。

從程式設計語言看,實際運作着 JAVA、C/C++,Nodejs,GoLang 等語言編寫的應用。從技術棧的角度看,包含了電商、DB、流計算、大資料、專有雲等場景,每個場景對于容器各方面要求,所用到的特性都不太一樣,PouchContainer 針對每個場景的需求都在産品上都做了支援。

PouchContainer 容器技術在阿裡的演進過程伴随着阿裡技術架構本身的演進。阿裡内部技術架構經曆了一個從集中式單體應用到分布式微服務化的演進。

淘寶最開始是一個巨石型的應用,一個應用裡包含了商品、使用者、下單等等所有交易鍊路的功能。随着功能越來越完善,維護起來也越來越困難。為了提高研發效率,從 2008 年開始我們逐漸把這個應用拆分成了多個分布式應用,商品的,交易的,使用者的,前台的,後端的;通過 HSF 遠端調用架構,TDDL 分布式資料層和 Notify 分布式消息中間件串聯起來。其中每個服務都有多個執行個體,都可以獨立研發演進,并可以進一步繼續拆分。于是就逐漸形成了一個龐大的分布式服務叢集。

從巨石型應用到多個單一功能的輕量級服務型應用,總的應用執行個體數變多了,每個執行個體需要的系統資源變少了。于是從最初的每個執行個體直接使用實體機自然過渡到使用 xen,kvm 等虛拟化技術。VM 使用了一段時間之後,發現整體實體機的使用率還是很低。當時一個 24 核的實體機隻能虛出 4 台 4 核的 VM,除了當時虛拟化本身的開銷不小外,每個應用執行個體在 VM 裡仍然用不完分到的資源。于是就想能不能不用虛拟機,用更輕量的基于程序級别的資源切分使用方式。

這個時候阿裡内部的運維體系已經比較龐大了,從應用的建構部署到分發,到一些運作期的監控告警等管控系統,都依賴于一個應用執行個體跑在一個獨立機器裡的假定。這個假定已經不經意間貫穿到了研發運維的各個環節裡面,包括系統的設計,運維習慣等都嚴重依賴這個假定。我們不可能重新搭建叢集,把存量的業務停掉再到新的叢集裡面用新的運維模式去跑起來,這個業務和運維上都是沒法接受的,不可能電商交易的研發停幾個月,系統停幾天來搞這個事情。是以我們首先要做到相容,新的資源使用方式必須相容原先的假定。我們經過仔細分析了這個假定的内涵,發現每個應用執行個體歸納下來無非有如下 4 點要求:

 ●  有獨立IP

 ●  能夠ssh登陸

 ●  有獨立的,隔離的檔案系統

 ●  資源隔離,并且使用量和可見性隔離

首先是有獨立 IP,能夠 SSH 登入。其次有獨立的檔案系統,應用程式跑起來,希望程式看到的整個檔案系統都是給他專用的,因為現有的代碼和配置中必然有很多路徑的寫死,需要滿足這個潛在要求。還有不管通過工具還是代碼,他隻能看到配置設定給他自己的資源。比如 4 個 CPU,8G 的記憶體,他能夠根據這些資源的用量做一些監控,做一些對自己資源使用量的采集和告警。這四個特點總結下來就是新的資源使用方式要做到和實體機或者 VM 的使用體驗一緻。能夠做到這樣的話原先跑在 VM 裡的應用就可以很平滑的遷移過來,現有的應用系統和運維系統不需要做很大的改動。

我們為了能達到這四點,最開始是多隆大神手工 Hack 系統調用,glibc 基礎庫等,實作了一些資源上的隔離。像有獨立的 IP 可登入 ,就用虛拟網卡,在每個容器裡面起一個 sshd 程序;資源的隔離和可見性上,就用 Cgroup 和 Namespace 等核心特性;後來發現開源的 LXC 項目也在做同樣的事情,并且比手工 Hack 更通用化,更優雅一些。于是我們內建 LXC,并且在核心上加了定制的資源可見性隔離的 patch,讓使用者的執行個體隻能看到配置設定給他的 CPU和記憶體,另外還增加了基于目錄的磁盤空間隔離的 patch,這樣就形成了我們第一代的容器産品。這個産品當時代号是 T4,寓意是第四代淘寶技術,淘寶 4.0;在 2011 年的時候 T4 容器技術灰階上線。

T4 相比 VM,完全沒有虛拟化 Hypervisor 層的開銷,資源切分和配置設定上更加靈活,可以支援不同程度的資源超賣。這樣就很好的支援了業務爆發增長的需求,控制了實體機按業務增長比例膨脹的勢頭。另外因為 T4 完全相容了之前研發和運維對實體機和 VM 的使用習慣,絕大多數應用都能夠做到透明的切換,應用無感覺。因為有這些特性,在接下來的短短幾年時間裡,T4 逐漸接管了交易和電商主體的線上應用。

到 2015 年的時候 Docker 技術火起來了。我們寫程式的都知道有個著名的公式,程式=資料結構+算法。從程式傳遞使用變成一個軟體産品的角度來看,我們可以套用這個公式:

 ●  軟體= 檔案(集)+ 程序(組);

從靜态來看,軟體從建構分發到部署,最終形式是一個有依賴層次的檔案集。從動态來看,這些檔案集,包括二進制和配置,由作業系統加載到記憶體後執行,就是一個有互動關系的程序組。我們之前的 T4 容器在程序(組),或者說運作時上做的事情和 Docker 基本類似,比如說都使用了 Cgroup、Namespace、linux bridge 等技術。還有些是 T4 特有的,比如基于目錄的磁盤空間的隔離,資源可見性隔離,對老版本核心的相容等。

我們從最早實體機演化到 VM,再到現在的容器,核心的更新周期比較漫長,疊代很慢,15年的時候存量的機器上全部都是 2.6.32 核心,T4是相容 2.6.32 核心的。 但是另一方面在檔案(集)的處理上 Docker 做得更好,更加系統化。 T4 隻做了很薄的一層鏡像,給相同的業務域做了一個基礎的運作和配置環境,這個鏡像沒有深入到每一個特定的應用。 而 Docker 是将每個應用的整個依賴棧打包到了鏡像中。是以在 2015 年我們引入了 Docker 的鏡像機制來完善自己的容器。

阿裡如何實作100%容器化鏡像化?八年技術演進之路回顧

在将 Docker 鏡像整合進來之後,原來基于 T4 的研發運維體系受到了很大的沖擊。 首先傳遞方式變了,之前是 build 一個應用的代碼包,把代碼包交給我們的部署釋出系統,後者建立一個空的容器,根據這個業務所在的很薄的模闆把一個空的容器跑起來,再到容器裡面安裝依賴的一些 IPM 包,設定一些配置,按每個應用定好的一個清單一個一個的安裝好,然後把應用包解壓啟動起來。這個應用依賴的軟體和配置清單我們内部叫做應用的基線。

引入鏡像之後,在将 Docker 鏡像整合進來之後,原有的傳遞方式發生了變化。之前是 build 一個應用的代碼包,把代碼包交給我們的部署釋出系統,後者建立一個空的容器,根據這個業務對應的很薄的一個模闆,把一個空的容器跑起來,再到容器裡面安裝依賴的一些 RPM 包,設定一些配置,按每個應用定好的一個清單一個一個的安裝好,然後把應用包解壓到主目錄啟動起來。這個應用依賴的軟體和配置清單我們内部叫做應用的基線。引入鏡像之後,我們應用的代碼包和依賴的所有的這些三方軟體、二方軟體都會打成一個鏡像。之前通過基線維護應用依賴環境,現在都放到每個應用自己的 Dockerfile 中了,整個研發建構和分發運維的過程大大簡化了。

做了這個事情之後,研發和運維之間的職責和邊界就發生了變化。之前研發隻需要關注功能,性能,穩定性,可擴充性,可測試性等等。引入了鏡像之後,因為要自己去寫 Dockerfile,要了解這個技術依賴和運作的環境倒底是什麼,應用才能跑起來,原來這些都是相應運維人員負責的。研發人員自己梳理維護起來後,就會知道這些依賴是否合理,是否可以優化等等。

研發還需要額外關注應用的可運維性和運維成本,關注自己的應用是有狀态的還是無狀态的,有狀态的運維成本就比較高。這個職責的轉換,可以更好的讓研發具備全棧的能力,思考問題涵蓋運維領域後,對如何設計更好的系統會帶來更深刻的了解。是以引入 Docker 之後對研發也提出了新的要求。我們總結新的時期,新的運維模式下對研發能力要求的幾個要素,總結起來就是幾個原則:

阿裡如何實作100%容器化鏡像化?八年技術演進之路回顧

為了更好的把自己的系統建設好,我們要倡導研發從第一天建立系統的時候,就要考量最終的可運維性,比如參數是否可配置,是否可以随時重新開機。機器每天都有硬體故障産生,這些硬故障不可能每天都人工處理,必須要盡可能自動化處理,自動化處理時,雖然有些故障隻影響了一部分執行個體,另一部分是好的,但是也可能需要一起處理,比如需要實體機上的業務全部遷移走來維修實體機的時候。是以不管當時容器裡的業務是好的還是不好的,都要滿足随時可重新開機,可遷移的要求。原來是部分傳遞,現在要考慮你到底運作環境是什麼樣的,什麼樣的運作環境才能跑起來,盡量做标準化的操作。

比如說啟動,Dockerfile 裡面寫好啟動的路徑,不要再搞一些特殊的處理,如果有任何特殊的處理都沒法做統一的排程和運維。統一的業務遷移,機器騰挪也沒法做。我們的目标其實就是從一開始的比較粗放的運維,到不斷的開發自動化的工具和系統,形成一個體系,通過前期人工運維的過程把一些固定的故障處理的流程模式化,最後提取出來一些可以自動處理故障,自動恢複的機制。我們的最終目标是無人職守。所有這些加起來其實就是我們引入鏡像化之後,并且要朝着無人值守的方向演進時,對研發和運維的新的要求。

阿裡如何實作100%容器化鏡像化?八年技術演進之路回顧

上面是 PouchContainer 容器的 Roadmap, 2011 年的時候 T4上線 ,到 2015 年 3 月的T4 覆寫了交易的大部分應用。這個時候開始引入了 Docker 鏡像機制,這裡面做了很多相容性的工作。

比如說原來 T4 輕量化的模闆轉化成對應的基礎鏡像,裡面相容了很多之前運維的習慣和運維的工具,如賬号推送,安全政策,系統檢測。我們在 2016 年初上線了第一個鏡像化應用,到 5 月份的時候集團決定主站全部應用容器化。在做鏡像之前阿裡是有一兩百人的團隊做每個應用的部署,運維,穩定性控制,後來這個團隊都沒有了,全部轉成了 DevOps,轉向開發工具和運維平台,通過代碼的方式,工具的方式解決運維的問題。之前專職做運維的同學最大的負擔就是線上環境的變更,研發送出變更申請給運維同學,運維同學做線上操作,研發不知道代碼運作環境具體依賴了哪些基礎軟體。

做了鏡像化的事情後,研發自己負責編寫 Dockerfile,運維就把環境變更的事情通過 Dockerfile 的機制移交給了研發。運維和研發之間的邊界就非常清楚了,這個邊界就是由 Dockerfile 來定義的。研發負責把他代碼依賴的環境在 Dockerfile 定義好,運維保證其建構分發時沒有問題。我們在 2016 年雙11的時候完成了交易核心應用的鏡像化 PouchContainer 化改造。在 2017 年雙11的時候交易全部應用完成了鏡像化改造。然後我們在 2017 年 11 月 19 日的時候宣布了 PouchContainer 的正式開源。

我們的内部 PouchContainer 經過大規模的運作,支援了各種各樣的業務場景,各種不同的技術棧,不同的運作形态,積累了非常多的經驗。這些經驗之前跟阿裡内部的環境耦合性比較大。比如說我們的網絡模型,我們其實是嵌入到了阿裡内部的網絡管控平台,包括IP配置設定在内部都有獨立的系統去完成。比如什麼時候啟用 IP,什麼時候下發路由等等,這些是有一個統一的 SDN 網絡管理系統來管理的。還有類似的内部存儲系統,還有運維的一些指令推送系統。内部系統耦合性比較大,沒法直接開源。

是以我們最後選擇的政策是先在外部孵化一個從零開始全新的項目,把内部的特性一點點搬上去。這個過程中我們内部的版本也會做重構,把内部的依賴做一些插件化解耦合的方式,這樣最後全新的項目在外部可以跑得很好;在内部用一些耦合内部環境的插件也可以跑起來,最終的目标是内外用一套開源版本。

那麼我們的 PouchContainer 容器相對于其他容器有什麼差異呢?主要展現在隔離性、鏡像分發優化、富容器模式、規模化應用和核心相容性幾個方面。傳統的容器隔離次元就是 namespace、cgroup;在資源可見性方面,我們前幾年是通過在核心上打 patch,在容器内看記憶體和 CPU 使用率等資料時,把統計數值和目前容器的 Cgroup 和 Namespace 關聯起來,使容器能使用的資源和已使用的資源都是容器自己的。

18年的時候我們引入了社群的lxcfs,這樣就不需要對特定核心 patch 的依賴了。磁盤空間的限制也是在低版本核心上加了更新檔,支援了基于檔案目錄的磁盤空間隔離,能夠把每個容器的 rootfs 限制住。在 4.9 以上的核心上,我們是用 overlay2 檔案系統來完成同樣功能的。我們也在做基于 hypervisor 的容器方案,提升容器的隔離性和安全性,我們在 PouchContainer 裡面內建了 RunV,用于一些多租戶的場景

阿裡如何實作100%容器化鏡像化?八年技術演進之路回顧

阿裡内部的離線上混部之是以能推進,在同一個機器上既能跑線上的業務又能跑離線的一些任務,互相之間不會出現太大的幹擾,其核心的技術就是 PouchContaienr 容器可以根據優先級,把不同業務的資源使用隔離開來,保證線上業務優先使用資源。這個資源包括很多的次元,比如 CPU、記憶體,CPU cache、磁盤、網絡等等。

阿裡如何實作100%容器化鏡像化?八年技術演進之路回顧

這是 PouchContainer 的鏡像分發設計。我們内部有很多比較核心的應用,體量比較大,執行個體會分布在上萬台實體機上。釋出新版本的時候上萬台機器同時拉鏡像,任何中心的鏡像倉庫都扛不住。是以我們設計了一套鏡像分發的二級架構,在每個地域建一個 mirror,在同一個地域内拉鏡像的時候用 P2P 分發技術---我們内部的産品名叫蜻蜓,已經開源;需要拉鏡像的伺服器之間可以分散互相拉檔案片段,這樣就直接化解了中心鏡像倉庫的服務壓力和網絡壓力。

後面其實還有更好的解決鏡像分發的思路,我們正在嘗試鏡像的遠端化,通過存儲計算分離技術,用遠端盤的方式挂載鏡像,直接跳過或者說異步化了鏡像分發這一步,目前正在内部環境灰階運作中。

阿裡如何實作100%容器化鏡像化?八年技術演進之路回顧

這是 PouchContainer 内部版本的體系結構。在最底層的主控端層面,我們會做一些管理和運維,目的是為了確定容器運作依賴的基礎環境是健康的,包括主控端的一些鏡像清理,包括安全控制、權限管理等。OS 的低版本核心我們是适配到最低 2.6.32 核心,包括容器裡面的程序管理也做了很多的适配。資源隔離前面講過了,網絡模型我們内部其實主體用的是 Bridge,但是其他各種各樣的場景也都支援。

我們開發了很多插件,PouchContainer 開源後,我們才将這些插件逐漸做了标準化,相容适配了社群的 CNI 标準。最上層是一個富容器模式的支援,每個容器裡面會啟動一些跟内部的運維工具,運維系統息息相關的一些元件,包括一些釋出模式的優化。可以看到我們内部體系結構是比較複雜的,尤其依賴内部的其他系統比較多,在外部直接跑是跑不起來的,是以也沒法直接開源。

阿裡如何實作100%容器化鏡像化?八年技術演進之路回顧

是以我們開源版本是重新開始搭建的,這樣會比較清爽一些。我們引入了contained,支援不同的 runtime 實作,包括我們自己包裝 lxc 開發的 RunLXC 運作時,可以用來支援老版本 2.6.32 核心。開源版 PouchContainer 相容所有 Docker 的接口,也支援 CRI 協定,這樣也就同時支援了比較主流的兩種叢集管理系統。

網絡方面我們内部基于 libnetwork 做了增強,包括不同場景暴露出來的一些問題,一些穩定性,規模化的時候各種細節的一些優化。存儲方面我們支援了多盤,記憶體盤,遠端盤等各種不同形式的存儲。PouchContainer 可以無縫內建到上層編排工具中,包括 Kubelet 和 Swarm 等。我們内部的 Sigma 排程系統,不同的版本Docker 協定和CRI協定都會使用。

這是 PouchContainer 的開源位址:https://github.com/alibaba/pouch

如何貢獻:

https://github.com/alibaba/pouch/blob/master/CONTRIBUTING.md

最近 PouchContainer 開源版本 GA 已經釋出,PouchContainer 能夠在如此短的時間内 GA,離不開容器社群的支援,在超過 2300 個 commit 的背後,有 80 多位社群開發者的踴躍貢獻,其中不乏國内一線網際網路公司、容器明星創業公司貢獻者的參與。

PouchContainer 開源版本釋出 GA 之前,此開源容器引擎技術已在阿裡巴巴資料中心得到大規模的驗證;GA 之後,相信其一系列的突出特性同樣可以服務于行業,作為一種開箱即用的系統軟體技術,幫助行業服務在推進雲原生架構轉型上占得先機。

【Q&A】

Q:你們是怎麼樣做到把阿裡巴巴集團包括高德還有菜鳥那些,都能把這個技術推過去,因為大公司在不同的部門跨部門甚至是跨子公司之間要想推行你們的某一個部門的研究成果是一件比較困難的事情。

A:這是一個好問題,我們其實也面臨過這個問題。我們的方法就是首先要和大家宣導這個理念,讓大家在認知上都接受鏡像化運維能帶來的優勢,長遠發展的好處。雖然很難有直接立竿見影的收益,長遠來看一定能提高運維效率,降低資源使用的成本。實際上從這兩年來看,我們确實降低了不少運維成本。

Q:你好,我想問一下容器裡面的那些持久化是怎麼處理的?

A:容器我們持久化現在大體分兩類資料,一個是日志,一種是應用自己會寫一些資料,像搜尋業務。要麼就是放在本地盤,放在本地的話做遷移的時候要自己處理資料的遷移,每個不同的業務處理的都不太一樣。還有一種方式是用遠端,資料遠端化。我們有分布式存儲系統“盤古”,通過容器建立的時候在遠端存儲叢集建一塊遠端盤,我們現在用的是塊裝置,然後挂載到容器裡面,容器用完或者是遷移的時候,資料是在遠端的,可以随意遷移到另一個地方,再把這個資料盤挂載回來。

搜尋也可以放遠端,對于阿裡各種搜尋場景,我了解如果replica數多的話,用遠端存儲是比較經濟劃算的,如果replica數就1行,或2行,而且遠端性能又滿足不了部分場景的需求,短時間内就不如本地多塊盤來進行混部。總體趨勢來說,如果沒有性能要求的話,都放遠端是趨勢。

Q:哪種方式會更多一些?

A:主控端直接到容器裡面,相對來說最大的場景是在資料庫,資料庫現在大部分是在本地,但是有一部分是放在遠端的,正在演進的過程中,還沒有百分之百完成存儲計算的分離。後面有一天可能就完全沒有本地資料了。

Q:這是雲架構,一聽到雲這個架構就感覺很大,是一個什麼海量運維,海量資料,對于中小型公司規模可能沒那麼大,對于要想用這套架構,實施的成本是多少,使用者量在多少以下适合或者不适合?

A:很難有明确的臨界點,說什麼時候該用雲化架構了。從中小型公司來說可以從第一天就往這個方向,或者是朝這個模式去實作。比如說搭一個很小的資源池,通過彈性混合雲的方式,在雲上去擴容,這也是一種很好的方式。如果第一天完全不考慮這些事情,怎麼友善怎麼搭建,也不考慮這些單點,容災這些彈性的事情,後面改造起來可能就會比較痛苦。

Q:這個部署的成本,兩個人或者三個人的研發團隊,用你這個東西周期有多長時間呢?它的難易度,因為要了解整個架構,你要部署這個東西要了解這個東西,我覺得學習的曲線還有部署的難度到底是什麼樣的?

A:後面這套系統在做 Sigma 靈活版就是解決中小企業的問題,兩三個開發者不可能開發出一套像現在這個規模的完整雲化架構,最好的是用雲上支援這些場景的産品。雲産品本身經過很多使用者的考驗,有這麼多雲上運作的一些經驗,一些技術上的沉澱,比自己開發要靠譜得多。

Q:我想問一下 PouchContainer 這個容器跟底層還會去封裝 Docker 之類的東西,我第一次接觸這個,另外鏡像庫的話是能夠跟 Docker 相容嗎?

A:首先鏡像庫跟 Docker 是完全相容的,Docker 分了很多層,底層的 runv 和 containerd都貢獻到了社群,是開源的,我們在 runv 和 containerd 的基礎上做了增強。總體來說是相容兩個社群的兩種主流的技術路線,兩種叢集管理系統,kubernetes 和 Docker 公司 swarm,這種兩種路徑都支援。

原文釋出時間為:2018-09-26

本文作者:林軒

本文來自雲栖社群合作夥伴“

阿裡技術

”,了解相關資訊可以關注“

”。