七牛容器SDN技術與微服務架構實踐

Docker的橫空出世很大程度上推進了容器技術的熱度和發展。容器技術和傳統的虛擬化技術有很大的不一樣,具體包括:首先是相對於傳統的虛擬機,之前一個虛擬機裏作的事情,要打散成不少個容器去作,它們各自的職能會更少;第二點是會形成之前一個虛機的IP會變成不少個容器的多個IP,容器之間的關係會變得更加複雜;第三點是整個網絡中的網絡端點數量呈現一個上升的趨勢;第四點是容器的生命週期其實會更短。此外,容器因爲其輕量級的優點,可能會被不停地調度,從一臺機器調度到另一臺機器,根據資源的負載均衡,容器的生命週期實際上是比虛機要短的。以上幾點其實都是給傳統的虛擬化網絡提出的一些新的挑戰。後端

本文是對七牛資深架構師徐兆魁在2015全球架構師峯會上所作的同題目演講的整理,主要分爲三個部分。第一部分簡單介紹SDN的內涵以及它和容器之間的關係。第二部分介紹一些現有圍繞容器的一些開源的SDN的解決方案,包括Flannel、Calico和Weave。第三部分是七牛在這部分的一些實踐和案例的分享。緩存

關於SDN和容器安全

做爲近年來比較熱的一個概念,衆所周知SDN是Software Defined Network的縮寫,即軟件定義網絡。但不一樣的人對SDN有不一樣的理解。在廣義上,只要是你經過軟件實現了一個東西,而後那個東西可以靈活地去達到網絡上面的部署和伸縮,這就能夠被認爲是SDN。在後文中會對Flannel、Calico、Weave這三個解決方案進行分析,並從控制層和轉發層來着重探討它們的技術實現,雖然它們並無宣稱本身是SDN的解決方案。網絡

因爲容器技術給傳統的虛擬化網絡提出了一些新的挑戰,因此圍繞Docker產生了不少不一樣的網絡解決方案,以彌補Docker在這些方面的不足。架構

圍繞容器的開源的SDN解決方案負載均衡

Docker本身的網絡方案比較簡單,就是每一個宿主機上會跑一個很是純粹的Linux Bridge,這個Bridge能夠認爲是一個二層的交換機,但它的能力有限,只能作一些簡單的學習和轉發。而後出來的流量,出網橋的流量會走IPTABLES,作NAT的地址轉換,而後靠路由轉發去作一個宿主之間的通訊。可是當真正用它的網絡模型部署一個比較複雜的業務時,會存在不少問題,好比容器重啓以後IP就變了;或者是因爲每臺宿主機會分配固定的網段,所以同一個容器遷到不一樣宿主機時,它的IP可能會發生變化,由於它是在不一樣的網段;同時,NAT的存在會形成兩端在通信時看到對方的地址是不真實的,由於它被NAT過;而且NAT自己也是有性能損耗等。這些問題都對使用Docker本身的網絡方案形成了障礙。框架

Flannelide

圖1微服務

Flannel是CoreOS團隊針對Kubernetes設計的一個覆蓋網絡(Overlay Network)工具,如圖1所示。它們的控制平面其實很簡單,如圖2所示。工具

圖2

每一個機器上面的Flannel進程會監聽ETCD,向ETCD申請每一個節點可用的IP地址段,而且從ETCD拿到其餘全部宿主機的網段信息,這樣它就能夠作一些路由。對於它的轉發平面(圖3)——轉發平面主要表現數據流的流向——它在Docker進來的網橋基礎之上,又建立了一個新的叫VXLAN的設備(圖4),VXLAN是一個隧道的方案,它能夠把一個二層的包,前面加一個包頭,而後再把整個包做爲物理網絡的一個包,去物理網絡裏面去路由,流轉。

圖3

圖4

爲何會要有這個東西呢?由於一般虛擬網絡的IP和MAC在物理的網絡實際上是不認識的。由於識別IP須要物理網絡支持,這個實際上是個隧道的方案。

總結一下Flannel方案,能夠看出它並無實現隔離,而且它也是按照網段作IP分配,即一個容器從一臺主機遷到另一臺主機的時候,它的地址必定會變化。

Calico

圖5

Calico的思路比較新,如圖5所示。它把每一個操做系統的協議棧認爲是一個路由器,而後把全部的容器認爲是連在這個路由器上的網絡終端,在路由器之間跑標準的路由協議——BGP的協議,而後讓它們本身去學習這個網絡拓撲該如何轉發。因此Calico方案實際上是一個純三層的方案,也就是說讓每臺機器的協議棧的三層去確保兩個容器,跨主機容器之間的三層連通性。對於控制平面(圖6),它每一個節點上會運行兩個主要的程序,一個是它本身的叫Felix,左邊那個,它會監聽ECTD中心的存儲,從它獲取事件,好比說用戶在這臺機器上加了一個IP,或者是分配了一個容器等。接着會在這臺機器上建立出一個容器,並將其網卡、IP、MAC都設置好,而後在內核的路由表裏面寫一條,註明這個IP應該到這張網卡。綠色部分是一個標準的路由程序,它會從內核裏面獲取哪一些IP的路由發生了變化,而後經過標準BGP的路由協議擴散到整個其餘的宿主機上,讓外界都知道這個IP在這裏,大家路由的時候獲得這裏來。

圖6

關於Calico這裏討論一個問題,由於它跑的是純三層的協議,因此其實它對物理架構有必定的侵入性。Calico官方稱,你能夠跑在一個大二層的網絡裏面。所謂大二層就是沒有任何三層的網關,全部的機器、宿主機、物理機在二層是可達的。這個方案其實有必定的弊端,事實上在不少有經驗的網絡工程師眼裏,一個大二層實際上是一個單一的故障率,也就是說任何一個都會有必定的硬件風險會讓整個大二層癱瘓。

另外,Calico跑在了一個三層網關的物理網絡上時,它須要把全部機器上的路由協議和整個物理網絡裏面的路由器的三層路所有用BGP打通。這其實會帶來一個問題,這裏的容器數量多是成千上萬的,而後你讓全部物理的路由學習到這些知識,其實會給物理集羣裏的BGP路由帶來必定的壓力,這個壓力我雖然沒有測過,但據專業的網絡工程師告知,當網絡端點數達到足夠大的時候,它自我學習和發現拓撲以及收斂的過程是須要不少的資源和時間的。

轉發平面(圖7)是Calico的優勢。由於它是純三層的轉發,中間沒有任何的NAT,沒有任何的overlay,因此它的轉發效率多是全部方案中最高的,由於它的包直接走原生TCP/IP的協議棧,它的隔離也由於這個棧而變得好作。由於TCP/IP的協議棧提供了一整套的防火牆的規則,因此它能夠經過IPTABLES的規則達到比較複雜的隔離邏輯。

圖7

Weave

圖8

Weave方案比較有趣,如圖8所示。首先它會在每臺機器上跑一個本身寫的Router程序起到路由器的做用,而後在路由器之間創建一個全打通的PC鏈接,接着在這張TCP的鏈接網裏面互相跑路由協議,造成一個控制平面(圖9)。能夠看出,它的控制平面和Calico一致,而轉發平面(圖10)則是走隧道的,這一點和Flannel一致,因此Weave被認爲是結合了Flannel和Calico這兩個方案的特色。

圖9

圖10

圖11所示是它的服務發現與負載均衡的一個簡單的方案,它在每一個容器會起兩個網卡,一個網卡連着本身起的能夠跟其餘宿主機聯通的網橋;另外一個網卡綁在原生Docker的一個網橋上,並在這個網橋上監聽一個DNS的服務,這個DNS實際上嵌在Router裏面,即它能夠從Router裏學習到一些服務的後端的一些配置。因此這時容器若是發起DNS查詢,實際上會被路由導到宿主機上,DNS Server上,而後DNS server作一些響應。它們官方負載均衡也是靠這個,可是這實際上是一個短板,由於咱們更偏向於四層或者是七層更精細的負載均衡。

在隔離方面,Weave的方案比較粗糙,只是子網級的隔離(圖12)。好比說有兩個容器都處在10.0.1-24網段,那麼它會在全部的容器裏面加一條路由說該網段會走左邊的網橋出去,可是全部非此網段的流量會走Docker0,這個時候Docker0和其餘是不聯通的,因此它就達到一個隔離的效果。

圖11

圖12

三個方案總結

總結一下:

1. Flannel僅僅做爲單租戶的容器互聯方案仍是很不錯的,但須要額外的組件去實現更高級的功能,例如服務發現與負載均衡。

2. Calico有着良好的性能和隔離策略,但其基於三層轉發的原理對物理架構可能會有必定的要求和侵入性。

3. Weave自帶DNS,必定程度上能解決服務發現,但因隔離功能有限,若做爲多租戶的聯通方案還稍加欠缺。

4. 另外,Calico和Weave都使用了路由協議做爲控制面,而自主路由學習在大規模網絡端點下的表現實際上是未經驗證的,曾諮詢過相關的網絡工程師,大規模端點的拓撲計算和收斂每每須要必定的時間和計算資源。

七牛的具體實踐

業務需求

七牛實際上一直在擁抱容器帶來的變革,擁抱新型的微服務架構理念。因此構建了一套容器平臺,這麼作的目的,一方面想推動經過將已有業務容器化簡化研發和上線流程,另外一方面也想經過這個方式去知足用戶的一些計算需求,畢竟計算和數據離得越近越好。

因此咱們業務上對網絡的需求是:

1. 首先一點,是可以運行在底層異構的基礎網絡上,這一點對於推動已有業務的容器化來講是很重要的,不然會涉及到基礎網絡的大規模變動,這是沒法接受的。

2. 咱們試圖構造一個對容器遷移友好的網絡結構,容許容器在必要狀況下發生調度。

3. 咱們認爲服務發現和負載均衡對業務來講是個基礎而普適的需求,尤爲是在倡導微服務架構的今天,一個設計良好的組件應該是可水平伸縮的,所以對於組件的調用方,服務發現和負載均衡是很是必要的功能。固然有人會說這個功能和網絡層無關,而應由應用層去實現,這個說法挺有道理,但後面我會講到由網絡層直接支持這兩個功能的好處。

4. 爲了知足七牛自己已有的一些對隔離有要求的服務,並知足上層更豐富的權限模型和業務邏輯,咱們試圖將隔離性作的更加靈活。

在這幾個需求的驅動下,咱們最終嘗試跳出傳統網絡模型的束縛,嘗試去構造一個更加扁平而受控的網絡結構。

轉發平面

首先,在轉發層面,爲了包容異構的基礎網絡,咱們選擇了使用Open vSwitch構造L2 overlay模型,經過在OVS之間聯通vxlan隧道來實現虛擬網絡的二層互通。如圖13所示。但隧道一般是有計算成本的,隧道須要對虛擬二層幀進行頻繁解封包動做,而通用的cpu其實並不擅長這些。咱們經過將vxlan的計算量offload到硬件網卡上,從而將一張萬兆網卡的帶寬利用率從40%提高到95%左右。

選擇overlay的另外一個理由是,據咱們目前所瞭解到,當下硬件的設備廠商在對SDN的支持上一般更偏向於overlay模型。

圖13

控制平面

而在控制層面,咱們思考了容器和傳統虛機的一些不一樣:

前面提到,微服務架構下,每一個容器的職責相對虛機來講更加細化和固定,而這會形成容器與容器間的依賴關係也相對固定。那麼每臺宿主機上的容器可能產生的outbound其實也是可推演的。若是進一步想的話,其實推演出來的理論範圍一般會遠大於容器實際產生的 outbound。因此咱們嘗試使用被動的方式實現控制指令的注入。所以咱們引入了OpenFlow做爲控制面的協議。OpenFlow做爲目前SDN 控制平面的協議標準,它有着很強的表達能力。從包匹配的角度看,它幾乎可匹配包頭中的任意字段,並支持多種流老化策略。此外,擴展性也很好,支持第三方的 Vendor 協議,能夠實現標準協議中沒法提供的功能OpenFlow能夠按Table組織流表,並可在表間跳轉(這一點其實和IPTABLES很像,但OpenFlow的語義會更加豐富)。配合OpenFlow的這種Table組織方式,能夠實現相對複雜的處理邏輯。如圖14所示。

圖14

選擇了OpenFlow,咱們的控制平面會顯得很中規中矩,也就是邏輯上的集中式控制,沒有weave/calico的P2P那麼炫酷。在這樣的結構下,當ovs遇到未知報文時,會主動提交包信息給Controller,Controller會根據包信息判斷後,給ovs下發合適的流表規則。爲了實現負載均衡和高可用,咱們給每組ovs配置多個Controller。如圖15所示。

例如:

1. 對於非法流量Controller會讓ovs簡單丟棄,並在未來一段時間內不要再詢問。

2. 對於合法流量,Controller會告訴ovs如何路由這個包並最終到達正確的目的地。

圖15

服務發現和負載均衡

關於服務發現和負載均衡,咱們提供瞭如下幾個對象模型:

1. Container,容器實例,多個Container構成一個Pod(實體)。

2. Pod,每一個Pod共享一個網絡棧,IP地址和端口空間(實體)。

3. Service,多個相同Pod副本構成一個Service,擁有一個Service IP(邏輯)。

4. 安全組,多個Service構成一個安全組(邏輯)。

其中,可動態伸縮的關係是一個Service與其後端Pod的映射,這一步是靠平臺的自動服務發現來完成。只要發起對Service IP的訪問,那麼Service自己就會完成服務發現和負載均衡的功能。後端Pod若是發生變更,調用方徹底無需感知。

從實現上來講,咱們將這個功能實現到了每一個宿主機上,每一個宿主機上的這個組件會直接代理本機產生的Service流量,這樣能夠避免額外的內網流量開銷。

功能上,咱們實現了IP級的負載均衡,什麼意思,就是每一個Service IP的可訪問端口與後端Pod實際監聽的端口是一致的,好比後端Pod監聽了12345,那麼直接訪問Service IP的12345端口,便可直接訪問,而無需額外的端口配置。

這裏對比一下常見的幾種負載均衡:

1. 比DNS均衡更加精細。

2. 比端口級的負載均衡器更容易使用,對業務入侵更小。

另外,7層的負載均衡實際上有很大的想象空間,咱們實現了大部分Nginx的經常使用配置,使用者能夠靈活配置。業務甚至還能夠指定後端進行訪問。

安全組

在隔離層面,咱們在邏輯上劃分了安全組,多個service組成一個安全組,安全組之間能夠實現靈活的訪問控制。相同安全組內的容器能夠互相不受限制的訪問。其中最多見的一個功能是,將安全組A中的某些特定的Service Export給另外一組安全組B。Export後,安全組B內的容器則能夠訪問這些導出的Service,而不能訪問A中的其餘Service。如圖16所示。

圖16

介紹完了咱們網絡的基礎功能,這裏經過分析兩個七牛的實際案例來講明這樣的結構是如何推進業務的架構演變的。

案例分析1——七牛文件處理FOP架構演變

第一個是七牛的文件處理架構(File OPeration),如圖17所示。文件處理功能一直是七牛很是創新、也是很核心的一個功能,用戶在上傳了一個文件後,經過簡單地在資源url中添加一些參數,就能直接下載到按參數處理後的文件,例如你能夠在一個視頻文件的url中添加一些參數,最終下載到一張在視頻某一幀上打了水印並旋轉90度並裁剪成40x40大小的圖片。

圖17

而支撐這樣一個業務的架構,在早期是很是笨拙的。圖17左側是業務的入口,右側是實際進行計算的各類worker集羣,裏面包含了圖片處理,視頻處理,文檔處理等各類處理實例。

1. 集羣信息寫死在入口配置中,後端配置變動不夠靈活。

2. 業務入口成爲流量穿透的組件(業務的指令流與數據流混雜在一塊兒)。

3. 突發請求狀況下,應對可能不及時。

後面負責文件處理的同事將架構進化成了這樣(如圖18)。

1. 增長Discovery組件,用於集羣中worker信息的自動發現,每一個worker被添加進集羣都會主動註冊本身。

2. 業務入口從Discovery獲取集羣信息,完成對請求的負載均衡。

3. 每一個計算節點上新增Agent組件,用於向Discovery組件上報心跳和節點信息,並緩存處理後的結果數據(將數據流從入口分離),另外也負責節點內的請求負載均衡(實例可能會有多個)。

4. 此時業務入口只需負責分發指令流,但仍然須要對請求作節點級別的負載均衡。

圖18

圖19描述的是文件處理架構遷移到容器平臺後的早期結構,較遷移以前有以下變動。

1. 每一個Agent對應一個計算worker,並按工種獨立成Service,好比Image Service,Video Service。

2. 取消業務的Discovery服務,轉由平臺自身的服務發現功能。

3. 每一個Agent的功能退化:

l 無需和Discovery維護心跳,也不在須要上報節點信息。

l 因爲後端只有一個worker,所以也不須要有節點內的負載均衡邏輯。

4. 業務入口無需負載均衡,只需無腦地請求容器平臺提供的入口地址便可。

圖19

圖20是遷移後發生的另外一次演變,實際上上一個階段中,每一個Agent仍然和計算實例綁定在一塊兒,而這麼作其實只是爲了方便業務的無痛遷移,由於Agent自己的代碼會有一些邏輯上的假設。

這張圖中,咱們進一步分離了Agent和worker,Agent獨立成一個Service,全部的worker 按工種獨立成Service,這麼分離的目的在於,Agent是可能會有文件內容緩存、屬於有狀態的服務,而全部的worker是真正幹活、無狀態的服務。分離以後的好處在於,worker的數量能夠隨時調整和伸縮,而不影響Agent中攜帶的狀態。

好處:

1. 能夠看到,相比於最先的架構,業務方只需集中精力開發業務自己,而無需重複造輪子,實現各類複雜的服務發現和各類負載均衡的代碼。

2. 另外,自從部署到容器平臺以後,平臺的調度器會自動更具節點的資源消耗情況作實例的遷移,這樣使得計算集羣中每一個節點的資源消耗更加均衡。

案例分析2——用戶自定義文件處理UFOP架構演變

另外一個案例是七牛的用戶自定義文件處理。

用戶自定義文件處理(User-defined File OPeration,UFOP)是七牛提供的用於運行用戶上傳的文件處理程序的框架。他的做用實際上和前面介紹的是一致的,只是容許用戶自定義他的計算實例。例如七牛現有的鑑黃服務,就是一個第三方的worker,能夠用於識別出一個圖片是否包含黃色內容。而正是因爲引入了用戶的程序,因此UFOP在架構上和官方的 FOP的不一樣在於,UFOP對隔離有要求。

圖20是本來UFOP的架構,事實上,這裏已經使用了容器技術進行資源上的隔離,全部的容器經過Docker Expose將端口映射到物理機,而後經過一個集中式的註冊服務,將地址和端口信息註冊到一箇中心服務,而後入口分發服務經過這個中心服務獲取集羣信息作請求的負載均衡。

而在網絡的隔離上,因爲Docker自身的弱隔離性,這個架構中選擇了禁止全部的容器間通訊,而只容許入口過來的流量。這個隔離尺度必定程度上限制了用戶自定義程序的靈活性。

圖20

而在遷移到容器平臺後,因爲有靈活的安全組控制,不一樣用戶上傳的處理程序自然就是隔離的,而用戶能夠建立多種職責不一樣的Service來完成更復雜的處理邏輯。如圖21所示。

另外,遷移後的程序將擁有完整的端口空間,進一步放開了用戶自定義處理程序的靈活性。

圖21

以上內容是七牛首度公開關於多租戶虛擬網絡方面的探索和實踐,並總結了咱們對這一領域的觀察和思考,還有不少更爲細節的點值得探討,望之後能與你們作更充分的交流。

相關文章
相關標籤/搜索