容器網絡方案Bridge/Vlan模式的演進
容器網絡背景
如果只是在一臺機器上使用Docker,或許你基本不用關心網絡配置,因為Docker Daemon默認模式還是比較友好的,直接幫你們生一個Bridge命名為Bridge0,這樣你可以通過端口映射的模式或是主機模式就可以讓容器與外部互聯互通了,而不用使用任何網絡工具(brctl, iptables)手工創建。但是如果將容器放到一個集群環境中(如使用Mesos或者K8S編排工具),這個網絡問題就比較痛苦了。因為需要保證如何暴露容器給外部訪問,同時又沒有過多的額外性能開銷,網絡方案又是比較可控穩定,這成為了一個基于容器的PaaS平臺的成功的關鍵因素。
我們的需求:獨立IP
除了網絡性能和網絡穩定性的問題需要考量外,我們內部有個很重要的要求就是一定要確保每個容器獲得一個獨立的IP,并且確保每個容器間可以相互訪問。因為我們有自己的基于RPC的服務化體系,需要一個平面的通訊網絡,并且關聯系統如APM系統,都是依賴這個獨立IP做分析的。
網絡方案選型
***次做容器化的架構(半年前),選擇網絡方案的要點是簡單和成熟的方案。網絡選型主要有兩個大方向,一個是物理機器方案即通過交換機的方式做方案如VLAN模式,VxLan模式等。另一個是軟件方案SDN,如Overlay網絡等。因為是我們***次做容器方案,為了保險起見,我們更信任物理設備的方式,所以我們選擇了VLAN的模式作為***次選擇,而VxLan對于物理設備有要求,先暫時放棄。不過如果有硬件基礎的,則可以有限考慮VxLan方式。
***版的VLAN網絡方案
對于使用VLAN的模式,一開始我們都沒有找到合適的資料,都是自己摸索出來的,后來新版本的docker支持docker network命令后,這些就簡單一些。而我們是無需用docker create network的。主要方案如下:
"vlan mode"
***版方案的缺陷
從***版的方案上看,雖然簡單而且也比較穩定,我們在生產上跑了4個多月了,沒有出現過問題。但是從管理監控的角度看,這個方案還是有明顯的缺陷,只是在容器規模還沒有達到一定的量的時候,這個缺陷是可以忍受的。但是對于這些缺陷,我們在做下一版的平臺的時候就需要尋找合適的解決方案了。
這些缺陷主要是:
- 一臺主機上使用的IP數量被固定了,因為我們是將IP段分配給了docker daemon,這樣會存在一個風險如果機器資源還有剩余,mesos+marathon就會在該主機上啟動容器,但是有可能這個時候沒有ip了,這樣marathon就會不停的啟動容器銷毀容器。
- 在容器數量比較多的時候,二級平面網絡的容器部署,在每個容器的新創建都會廣播ARP包,這樣整個網絡的風暴比較厲害。當然在容器數量規模還未起來的時候,這個可以暫時忽略。特別是對于動態伸縮容器的場景比較小的時候,這個問題并不大。不過通過和京東的永成大神聊過后,有個workaround的方式繞開這個問題,后面會講。
- 主要問題在于核心交換機的mac-ip的這個表的容量,因為容器打破了原來的物理機體系,讓核心交換機來處理容器的mac-ip的關系,這個對于傳統的交換機并不合適。不過本人對于網絡設備只是略知一二,所以,這個問題只是聽說的程度。如果有不對,請指出。
第二版的VLAN網絡方案
第二版網絡需求
- 在確保容器能夠有一個獨立的IP的同時,不再限制單一主機的IP的數量,支持更多資源需求小的服務應用的部署。
- 能夠限制單個容器的對于網卡的使用,避免因為某個容器的網絡的使用突然過大,影響同主機的其它容器的使用。
- 減緩因為容器動態伸縮帶來的網絡ARP風暴的影響
動態IP管理方案
對于要使容器有獨立的IP,又要使每個主機的IP的管理動態化,那么就需要將IP分配放在docker daemon/mesos+marathon的外部管理,通過插件plugin的方式集成。目前可選的方式是docker daemon的IPAM接口,或者是mesos slave的IPAM接口。雖然都叫IPAM,但是他們基于的機制不同。
Docker的IPAM(IP address management)是在Docker daemon的CNM(Container Network Model)機制下的IP管理驅動。CNM的設計模型,可以參考CNM Design。 Docker IPAM可以參考Docker IPAM
而對于Mesos則是遵循CNI的規范。CNI規范可以參看CNI Spec。
不過對于只需要動態管理IP地址的話,基于任何一種IPAM的接口都是可以的。所以我們經過老肖(@熟人云)介紹,參考了Talking Data公司的Shrike來做動態的IP管理。Shrike是基于Docker deamon的IPAM的方案, 所以只能用于基于Docker容器的方案,如果是用mesos unified container,則需要自己去改造成對接CNI的IPAM的接口。
雖然Shrike比較簡單,但是目前Shrike有些局限,所以我們需要在上面做一些改造,以支持后續的擴展。主要包括:
- Shrike這個進程如果意外退出,IP的釋放消息(Release address)未被處理,就會造成IP被***占用。目前我們的思路是,在shrike啟動的時候主動去掃描本機的docker container,然后和etcd上的數據比對,如果有IP沒有被釋放,則主動清理。
- 對于上面這個約束,我們需要改造Etcd中數據結構,以支持將主機IP存入etcd中,便于后續的主動清理。同時改造etcd數據結構也是為了限流使用。
網絡限流方案
對于網絡限流,一開始的思路是想利用mesos+marathon方案的自定義資源管理的方式,但是因為marathon遲遲不支持自定義資源調度,所以這個方式暫時放下了。希望用這樣的方式管理的原因是想把網卡變成類似cpu/mem的資源同等對待,只要分配了帶寬給容器的綜合超過一定數就不再這個主機啟動容器了。Mesos的自定義資源參考mesos attr resource
在這里還是要吐槽一下Marathon,開發的進度和Mesos太不一致了,希望Mesosphere的同學好好push一下。
這條路暫時走不通,那么在用Shrike做動態IP分配的時候,我想能不能在IP動態分配的時候就同時做了這個容器的帶寬限制呢?所以就有了以下方案
"shrike"
主要的流程如下:
- 在Shrike中增加一個Throttling的模塊,Shrike動態分配IP后發送一條消息給這個Throttlilng模塊,包含容器ip信息(可惜沒有容器的id)
- Throttling模塊收到消息后,調用docker daemon接口查詢這個ip對應的容器在主機的網絡名稱(這里可以用unix socket接口或者http接口,因為是本機調用)
- 查詢這個容器的環境變量如net_in, net_out的值(這個目前是啟動容器的時候配置上去的)
- 通過調用linux下的wondershape工具來對容器進行限制帶寬
這個方案還有后續幾個事宜我們還沒有處理的:
- 如何發布Shrike,目前的思路是在安裝物理機的時候一并安裝(打成rpm的方式,用systemd方式維護)
- 或許可以嘗試用容器的方式發布,但是不知道是否可行。
我們還在構思,如圖所示提供一個Console的管理控制臺,實時展示容器的網絡配置以及使用情況,因為net_id和net_out多會寫入到Etcd中,所以完全可以在界面直接調整這兩個值,然后Throttling的模塊watch到變化就直接執行wondershape對容器進行更改就可。
減少ARP廣播包的方案
ARP廣播的目的是確定IP所在的主機的MAC地址,用于二層網絡的尋址。但是容器的創建的時候,通常MAC地址是通過一定的規則生成的,所以每次有容器啟動,都會廣播這個MAC地址和它的IP的對應關系。但是如果MAC-IP的對應關系建立后沒有關變,則ARP是無需再次廣播的。這是通俗的說法。具體可以看RFC826規范。
既然是這樣,我們是否可以找到一種手段來控制ARP包的量呢?有的,就是預先設置好IP-MAC的關系,也就是只要IP相同,它的MAC地址就是相同的。所以對于容器方案,可以預先初始化好規劃的容量的所有IP和MAC的對應關系。然后每個容器啟動時主動的去拉取這個表,并通過arp命令設置到容器中。(這里有個細節沒有去實驗,就是如果有幾萬個容器,arp命令執行這個表的時間是多少,是否影響容器啟動的時間?)
這樣容器啟動后就有所有容器的IP-MAC對應關系,就無需發送過多的ARP包了。 不過這里還有另外一個問題,那就是無法使用IPAM接口,因為IPAM接口沒有提供對應的容器的MAC的指定手段。(看CNI的源碼歷史,MAC設置原來是可以在IPAM中設置的,但是后來被挪到外層了)
所以如果需要在容器啟動后直接更新一個大的固定的IP-MAC列表,就只能通過CNM/CNI的接口方式設置IP和MAC地址了
核心交換機的MAC地址的承載能力方案
這個只能是找硬件廠商解決了。據說京東下一代的方案是直接定制核心交換機以支持容器方案。具體細節不太清楚。如果有更好的方案,請記得告訴我
小結
到此為止,基本就涵蓋我們第二版的網絡改進方案的大體思路了。或許你會問,怎么不考慮用現在熱門的幾個三層網絡方案呢?其實理由很簡單,就是還是不能完全掌握的了,特別是如果問題定位,如何調試都是比較困難的。但是依賴與硬件交換機和Linux的特性,這個還是比較有信心的。所以建議如果不是技術有足夠的掌控力,不要輕易嘗試SDN的方案,除非你買專業的技術服務。
【本文是51CTO專欄作者“VIPDOCKER-了哥 ”的原創文章,如需轉載請通過51CTO與作者聯系】