1. 程式人生 > >宜信PaaS平臺基於Calico的容器

宜信PaaS平臺基於Calico的容器

容器雲面臨的網路挑戰

  在傳統的IDC的架構裡面網路是很重要的事情,在虛擬機器環境中網路的發展已經有很多成熟的解決方案,現在為什麼還在研究新的方案呢?因為雲端計算。雲端計算在2013、2014年之前的時間段,其主要的發力點在虛擬機器。但是從容器技術出現之後,虛擬機器被更輕量的容器方式顛覆,從而大幅降低開發、運維、測試和部署、維護的成本。當然也帶來了很多在虛擬機器裡沒有面臨過的問題。

  在網路層面,容器的本質是幾個被封裝了的程序。這必然導致每個容器都會有自己完整的網路棧、有自己的IP。所以整個雲的基礎設施——叢集裡有大量的網路和IP要管理,並且程序的啟動和結束是與容器伴生的,程序生滅的頻繁程度超過了虛擬機器幾個量級。建立一個虛擬機器會開啟很多程式,程式之間彼此通訊,但和虛擬機器外部的通訊是少很多的。而容器的誕生,從網路管理角度來說,微服務架構呼之欲出。

  用容器做遷移的時候,如果一臺機器宕機了,對應用而言希望是無感知的。因此,如果容器所在的主機出故障,就帶來了新的問題,即容器IP的任意漂移。在建立虛擬機器的時候,IP地址的分配是一種靜態方式;但是在容器上面,IP地址的分配通常是動態分配。一個容器啟來的時候,通常我們不會知道它的IP是什麼,只有起來之後才知道。

  在容器雲的場景下,我們傾向於把多個應用放在一個應用上執行,這導致應用和應用之間需要做安全隔離——我們不希望一個出問題的應用會影響其他的應用。所以說容器之間需要決定哪個容器可以通訊,哪個不能通訊。以前在虛擬機器的時代,通過大量分層可以解決,但容器環境裡這件事情的難度提高了。

  所以我們選擇網路解決方案的需求也發生了變化,最大的要求是容易管理。網路間通訊量大了,不能夠承受太大的損耗。而當發生容器間遷移的時候,需要一種機制,來保證遷移後的IP不會發生變化。同時,它的解決方案是需要細粒度的安全策略。

  容器本身是一個單機軟體,並沒有為跨主機的網路考慮太多。跨主機容器互聯的解決方案最典型的是兩臺主機之間通過一個交換節點實現連通。在主機內起十到幾十個主機的規模,考慮到主機上有沒有足夠的CPU和記憶體,在這個主機上做靜態IP規劃幾乎是不太可能。這時候我們就引入SDN技術——用軟體的方式定義網路,軟體資料發生變化時網路就相應地發生變化。

  常見SDN方案

  簡單的談一下DockerBridge,關於主機內部的網路管理工作。每個容器裡面都有一個虛擬網絡卡,和主機上的虛擬網絡卡做配合,所有容器內的虛擬網絡卡都可以和主機通訊。通過埠對映,我呼叫對方的容器服務的時候,不能使用該容器直接的地址,必須使用它主機的地址。因為有了這樣一個轉發,網路通訊的效能有所損耗。當然,還有一個問題更嚴重,訪問你的容器先要搞清楚你的主機是什麼,這樣網路通訊會跳來跳去。不但麻煩,還會帶來埠衝突。每建立一個容器會繫結一個埠,怎麼管理好這些埠是一個很大的挑戰。

  第二個解決方案是Flannel,這個想法很好。每個主機負責一個網段,在這個網段裡面分配一個IP地址。訪問另外一臺主機的時候,通過網橋到達主機上的IP地址,這邊會有一個裝置,程式會把你發的包讀出來,去判斷你的目標地址是什麼,歸哪臺機器管。還會把你的IP包外面加一個UDP包,發到目標地址。收到之後,會把前面的包扔掉,留下來的就是目標容器地址。這個方法有幾個問題,第一個是要做封包的操作。第二個問題是每個主機上的容器是固定的,容器的不同主機之前的遷移必然帶來IP的變化。

  再來說說Weave,他的思路是共享IP而非繫結。在傳輸層先找到目標地址,然後把包發到對端,節點之間互相通過協議共享資訊。Flannel和Weave的特點是類似的,都用的是UDP或者是VxLAN的技術。事實上使用UDP效能是很差的,VxLAN和UDP差不多,它有一個網路切隔,而且在裡面可以跑二層協議。還有一種是IPIP封包,直接把一個IP包封裝在一個IP包裡面。

  以上不難看出,原生網路效能比較差,使用UDP的時候效能損失在50%以上,使用VxLAN也會有20%~30%的損耗。所以我要在核心上封包,使用硬體來解決這些問題。而且容器和容器之間出現通訊故障,除錯的時候非常困難。

  關於封包

  回過頭來想一下,我們為什麼要封包?其實它是改包,主要解決的問題是同一個問題。即容器網路裡,主機間的不知道對方的目標地址,沒有辦法把IP包投遞到正確的地方。

  傳統的二層網路是用路由來互相訪問,不需要封包。但是路由規則怎麼維護?利用BGP(基於TCP之間兩兩連線)搞一個分散式的路由叢集能否滿足規模?

  Metaswitch:容器內部配一個路由指向自己宿主機的地址,路由規則下發,這是一個純三層的網路沒有封包,接近原生網路效能。

  在容器裡面我們怎麼做呢?我們發現了Calico專案。不同主機上的每個容器內部都配一個路由,指向自己所在的IP地址;每臺伺服器變成路由器,配置自己的路由規則,通過網絡卡直接到達目標容器,整個過程沒有封包。

  所以這是一個純三層網路,沒有引入一個DP,沒有封包。在主機內部做另外一個容器,可以三條到達終端,你可以知道是誰出了問題,除錯的時候很容易,很好管理。容器內的應用資料傳出來,和二層完全隔離,對於我們絕大多數的應用來講只需要三層就夠了,很少有應用處理二層。

  那麼,路由交換是不是很難呢?用傳統的BGP技術就可以實現。這個協議在大規模應用下是一個很好的場景。而且BGP有一個自治域的概念。在這個場景下會有一個問題,路由之間的資訊交換實際上是基於TCP協議,每兩個之間都有一個TCP連線,規模大了以後複雜度非常高。所以在這種場景下,大概是幾百個主機直接使用BGP的方式來做;再大一點的話,選擇分散式互聯,這樣可以把網路規模繼續擴大,最後能夠支援到幾萬臺機器。如果不需要這些策略,不做商業邏輯和業務邏輯,只是用BGP來做路由互聯的話,其實還是很簡單和高效的。

  金融業務的具體實現

  宜信內部的做法是用powerstrip實現,還有一個是手工去做,啟動容器直接用Docker,然後自己再去設定IP。如果容器之間都互通,建立容器的時候都通過配置環境變數,會建立一個Profile,配置好iptables 以及ipset可以保護我們的伺服器。再稍微複雜一點的話,可以修改ACL規則,如果有很多個APP,每個APP都需要訪問資料庫,每增加一個IP都要修改配置這樣顯得太麻煩,我們可以通過給所有的APP打標籤的方式來解決這個問題。

  配置容器的三種方法:

  用powerstrip來Hijack劫持Docker的API,這個思路很有意思。

  calicoctr container命令。

  libnetwork驅動(需Docker1.9以上)。

  因為做的是金融業務,效能其實不是最吸引人的,ACL應用是宜信關注的重點。比如在宜信的場景下做雲平臺的時候,會有應用的概念。一個應用有多個容器,互相可訪問;不同應用的容器互相不能訪問;一個應用對另外一個應用提供服務,作為服務容器並且規定哪些可以訪問。所有的應用容器能夠訪問叢集,應用容器不可以訪問自己所在的叢集的任何一臺伺服器。總之,我們要實現應用可以訪問主機上指定的服務,可以訪問除本網段之外的其他網段。

  Calico使用總結

  Calico的應用場景主要是IDC內部,推薦部署在二層網路上,這樣所有路由器之間是互通的。這種場景是大二層的解決方案,所有伺服器都在裡面。但大二層主要的問題是彈性伸縮的問題。頻繁開關機的時候,容器啟停雖然不影響交換機,但容易產生廣播風暴。網路規模太大的時候,一旦出現了這樣的問題,整個網路都會有故障,這個問題還沒有解決的特別好。

  Calico作為一個純二層的應用問題不大。我們可以把叢集分成了很多網段,對外是三層網路的結構。叢集內部分成多個自制域,比如一個機櫃是一個自制域,之間通過交換路由的方式實現在三層容器到容器的互通。瓶頸在於容器的路由資訊容量。所以說本質上它不是一個應對網際網路規模的解決方案,但對宜信場景是夠用的。

  我們實施的時候遇到一些坑,比如容器在啟動時沒有網路、操作ETCD的時候BGP配置頻繁載入,等等,最後我們多一一解決了。我們也發現了driver方案功能方面的弱點,現在還繼續使用劫持API的方法。如果要在雲上使用,如果支援BGP,直接可以用;如果不支援BGP可以用IPIP。現在英特爾的網絡卡支援兩個協議,一個是GRE、一個是VxLAN。如果真的把它放在雲上,我們可以考慮一下把VxLAN引進來,效能上的差別不是很大。

  本文根據洪強寧在ECUG Con的演講整理而成,ECUG(Effective Cloud User Group,實效雲端計算使用者組)是由Erlang愛好者、分散式領域的知名專家組成的民間技術團體。ECUG Con是該組織一年一度交流雲計算產業前沿技術的大會。