本文由 網易雲 釋出。
作為容器叢集管理技術競爭的大贏家,Kubernetes已經和微服務緊密聯絡,採用Kubernetes的企業往往都開始了微服務架構的探索。然而不同企業不同階段的微服務實踐面臨的問題千差萬別,註定要在技術路線上產生分叉。如何選擇適合自己的技術,是每一個踐行微服務的團隊面臨的第一個問題。網易雲是Kubernetes的第一批重度使用者,在不同業務場景下解決了很多挑戰,在本文中,網易雲首席解決方案架構師劉超梳理了基於Kubernetes構建微服務體系的進階之路。
高速增長階段,微服務化的必要性
一個產品的發展,通常可分為冷啟動階段、高速增長階段和成熟階段。
產品冷啟動階段,需求是以最簡單的架構驗證業務。以網易考拉海購(以下簡稱“網易考拉”)為例,最初的架構設計目標就是快速啟動,驗證產品方向,該架構包括線上、快取、線下和管理服務四個方面,即一般電商平臺加上跨境電商必備的進銷存系統,採用了Oracle資料庫、OpenStack管理的虛擬機器(VM),並沒有諸如高併發之類的考慮。
產品高速增長階段,業務規模逐漸擴大,產品複雜度也隨著增加,企業需要解決快速迭代、高可靠和高可用等問題,一個自然的選擇是服務化的拆分,把一個單體架構拆分成一些較小的模組,並遵循康威定律,用5-9個小團隊來適應架構的變化。仍以網易考拉為例,網易考拉在高速增長階段也慢慢演化出各種新的模組,比如單獨的支付模組、貨倉模組、第三方商家模組、推送模組等,並基於Dubbo框架打造服務發現功能來支援各模組之間的相互呼叫。
服務化主要解決了變更的問題。在整個架構演進的過程中,各個模組都面臨爆炸性的增長,比如海淘、自營、第三方商家的供應鏈,Web、APP、H5的呈現,限時購、秒殺、預售的活動頁,以及倉庫與物流系統、支付系統的對接等,緊耦合則牽一髮而動全身,工程臃腫,影響迭代速度,分別獨立上線更有利於適應業務發展的需求。網易考拉在高速增長階段首先按照主頁、活動頁、優惠券、支付等維度縱向拆分,之後又不斷演進成為100多個相互關聯的模組,變更頻率由每天2次增長到每天1000多次,產品質量提升52%。
容器化的優勢與挑戰
拆分成大量小模組之後,虛擬機器與服務化架構的配合就出現了很多新的挑戰,於是有了容器化的需求。
劉超解釋說,拆分之前首先要解決“合”的問題,即需要保證功能還是原來的功能,程式碼質量還是原來的程式碼質量,不會引入新的bug。他認為,微服務化需要從一開始就要做好持續整合,而容器是很好的持續整合的工具,完成從程式碼提交到自動測試、自動釋出的工作。容器化會帶來開發流程的變化,把環境交付過程從運維人員提前到開發人員手上。
在架構複雜的情況下,比如100多個模組,再加上各種副本,所有環境都由一個運維團隊來完成,不僅工作量繁重,而且還容易出錯,但這是使用虛擬機器的模式。而如果寫一個Dockerflie放到程式碼倉庫,由開發人員來考慮開發完成之後應用部署的配置環境、許可權等問題,包括測試環境的部署、聯調環境的部署、生產環境的部署,問題就很好解決了。這就是容器化帶來的流程變化。
然而,這種轉變涉及到開發人員是否願意學習容器技術。劉超推薦的解決辦法,是使用映象分層的形式,即最內部的環境包括作業系統及系統工具的映象由運維人員來做,中間層環境的映象由核心開發人員完成,普通開發人員只需把jar或者war扔到相應的路徑下即可,這就極大降低企業組織容器化的障礙。
場景一:Kubernetes + Docker + VM + Host Network
第一種場景,就是用Kubernetes管理虛擬機器,容器的網路、儲存會面臨各種各樣的選型。企業如果對容器的網路、儲存瞭解不足,可以把容器當成一個持續整合的工具,把一個容器嵌入到一個虛擬機器裡面,相當於用容器映象代替指令碼部署。這種做法需要解決兩個問題:一是IP保持的問題,二是盤保持的問題。因為原先採用虛擬機器的時候,是基於有狀態的設計,認為IP、Volume都是保持不變的。當容器僅僅作為持續整合的工具,團隊的這個習慣可能改不了。
一個方案是自己實現一個有狀態容器的方式,實現IP的保持,當一個節點掛了,重新啟動的虛擬機器和容器仍然可以使用原先分配的IP,二是把Docker容器的映象一層層地Mount到外面的Volume裡面,當一個節點掛了,Docker所有的映象和Volume其實還掛載在外面的Ceph上,資料並未丟失。這和使用VM很相似,既可以Docker化支援微服務化,也不需要改變使用者習慣。使用Kubernetes壓力相對比較大的團隊,可以通過這種方式切入。
場景二:Kubernetes + Docker + PM + Bridge Network
第二種場景,企業沒有使用虛擬機器,有一部分應用部署在PM上(注:本文中PM特指物理機),同時想把一部分應用遷移到容器裡。此時,不管物理機是否巢狀虛擬機器,直接建立一個Bridge Network,把物理網路卡也打進去,當Docker的網路卡和Bridge連起來的時候,整個網路就是平的,容器和容器旁邊的物理機都使用同一個指定的網段。網路打平之後,使用Dubbo的團隊也可以比較順暢地把一部分物理機上部署的應用逐漸遷移到容器裡,而如果沒有Bridge
Network,中間過負載均衡(LB)或者NAT時會很彆扭,因為Kubernetes層的維護人員通常很難勸說Dubbo層開發人員改變應用開發的方式。
使用Bridge
Network,Kubernetes網路配置很簡單,使用CNI的方式即可。如果有定製化以適應應用層的需求,可以參考Docker run的手動配置方式,開發自己的CNI外掛。大致流程是先建立網橋(如果不存在),獲取Namespace,配置veth pair並放到Namespace裡,然後獲取IP地址,獲取網路和路由。
場景三:Kubernetes + Docker + PM + SR-IOV Network
Bridge的方式,能夠滿足一般的Java應用部署的需求,但一些需要更高效能的應用,需要高吞吐量、高併發、高PPS,比如電商大促情況下的快取,這時候可以採用SR-IOV代替Bridge來解決問題,頻寬比較大但PPS上不去(大包或大量小包)的情況,SR-IOV都可以解決,但是需要購買SR-IOV網路卡,成本比較高。
高可用設計要點
無狀態。做好持續整合之後,第一件事情應該是把應用分為有狀態(Stateful)和無狀態(Stateless)兩個部分,並且使大部分應用是無狀態的,這樣可以更好地適應彈性伸縮。即便Kubernetes已經可以支援有狀態應用的部署,劉超還是建議在應用層儘量實現無狀態,使得有狀態應用聚集在少數的叢集裡面。有狀態最重要的是資料庫和快取,通常記憶體資料放在快取,需要持久化的資料放在資料庫裡。
分散式資料庫。資料庫的高可用,網易雲採用的是DDB(分散式資料庫)方案,基於MySQL的多臺主備及負載均衡做分庫分表,網易雲RDS基於自己的MySQL核心優化,能夠實現主備切換不丟資料,能夠很好地支援容器化,有狀態容器掛掉之後,重新啟動一個容器,只要做好前序重置和冪等,就不會有業務問題。所以網易雲RDS的主備切換也從虛擬機器向容器過渡。
快取。高併發應用需要每一層都有快取,把客戶需求儘可能地攔在前面,吞吐量就大很多。但快取不像資料庫一樣有持久化機制,其高可用、跨機房就需要做雙寫,因為快取保持在記憶體中,掛了就沒有了,修復難度很大。其他的元件,比如ZooKeeper、Kafka、訊息佇列、HBase,都有各自的高可用機制。所以,一個發展中的應用應當被分成很顯著的兩個部分,一部分是無狀態的,另一部分有狀態的就放到本身具有高可用機制的元件裡面。
成熟階段架構
產品成熟階段要解決的問題,主要是如何通過服務治理、系統運維自動化提升可靠性和可用性,如何高效完成大專案的複雜協作,如何梳理功能、深化使用者體驗。以正在進行全面服務化的網易考拉為例,2017年雙11期間其工程數量相對平時增加了20多倍,應用、儲存叢集規模膨脹了5倍,挑戰之大不必多說。劉超對成熟階段架構設計強調了兩點:
不可變基礎設施:使用Kubernetes容器技術不能沿襲虛擬機器時代的操作方式,而是應當採用不可變基礎設施,即所有的改變,都應該在Git的改變裡面有所體現,修改環境就是修改Dockerfile,修改配置檔案也是程式碼層次的改變,整個環境的部署,當程式碼merge的時候,會觸發通過容器自動部署的指令碼,這能很好地保持環境的一致性。大規模節點下,如果是手動部署,出錯很容易,排查卻很難。所以,不可變基礎設施非常重要。
IaC(基礎設施即程式碼)部署與擴容:網易雲在Kubernetes的編排之外封裝了另一個編排,也是在倉庫裡面維護的,任何的修改,比如要升級5個應用,這5個應用的版本號都在這裡面都配置好,程式碼commit之後就觸發自動部署,如果發現問題,很容易回滾,只需把程式碼revert回來,後續流程會自動觸發。如果依賴於寫Yaml檔案來做,頻繁升級且版本號控制不好時,就很容易回滾失誤。
場景四:Kubernetes+Docker+PM+Overlay Network
成熟階段通常使用Kubernetes+Docker+PM+Overlay Network的模式,企業一旦開始用Overlay Network,基本上都會使用物理機,否則使用虛擬機器會出現兩層Overlay。這時候Flannel、Calico、Romana或者Weave等很多的選型都可以,Flannel的效能已經越來越好。
場景五:Kubernetes和IaaS層深度融合
網易雲的方式,是Kubernetes與IaaS深度融合實現動態擴充套件資源,目前叢集排程規模支援30000+節點。這個規模下,首先要解決的是動態資源建立優化,這樣才符合資源精細利用、成本最優化的設計。同時,不論虛擬機器的建立還是容器的建立,對應用都是透明的,也就是說,應用只需要明確一個模組要變成3個節點還是5個節點,不需要管Docker是不是要變成多少個節點、這些節點要放在哪裡、虛擬機器和物理機是否有資源之類的問題,後續的動作都是聯動的。
動態資源建立的實現,網易雲改造了Kubernetes建立流程,主要是監聽Pod建立的事件,由Resource Controller判斷有沒有足夠的Volume資源、Network資源,Schedule判斷有沒有足夠的Node資源,有則直接繫結,無則動態申請之後再繫結,然後由Kubernetes下發。新增資源的時候,只有應用層和機房兩層,機房只需要把物理機新增到IaaS層,不需要管上面是否有Kubernetes,虛擬機器的建立全部是動態的,應用層只管應用層的事情,中間都是透明的。
其次是網路優化。網易雲大部分容器是執行在虛擬機器上的,同時也提供採用SR-IOV網路卡的裸機容器,用於需要更高效能的快取、分散式資料庫等。大部分的應用可以橫向擴充套件,還是在IaaS裡面。但是網易雲希望容器裡面的網路卡,讓最外層虛擬機器上的OVS也可以看到,即只有一層Overlay,虛擬機器裡面有一個Bridge,但如果不需要,也可以直接打到外面的OVS上,另外還有一個管理網路,跨租戶也是同一個Kubernetes來管理。只有一層Overlay意味著沒有二次的虛擬化,同時原來部署在虛擬機器裡面的應用遷移到容器中,虛擬機器和容器的網路都是通過OVS來管理,採用Dubbo做服務發現會非常平滑,這是針對業務層壓力的解決方案。其實OpenStack有一個CNI外掛,也採用了類似的做法,和Neutron聯動,把VIF打在外面的OVS上。
小結
本文結合網易雲服務內外部客戶的Kubernetes實踐經驗,總結了產品高速增長期和成熟期使用Kubernetes容器技術實現微服務架構的五種應用場景,針對不同的挑戰提出了易於執行的解決方案,並介紹了網易雲的獨門優化方法,希望對讀者有所啟發。
瞭解網易雲:
網易雲官網:www.163yun.com/
新使用者大禮包:www.163yun.com/gift
網易雲社群:sq.163yun.com/