PPTV Docker叢集的網路方案選型
原作者:李周 轉載來源:http://dockone.io/article/1673
PPTV Docker叢集的網路方案選型
作者介紹:李周,現PPTVDCOS技術主要負責人。專注於Docker網路解決方案、容器監控、DevOps。目前主要研究方向是容器網路改造、多套測試環境隔離、容器深度監控。之前在中小創業公司長期負責客戶現場實施工作;積累了大量關於網路、監控、許可權認證、大資料、Oracle、中介軟體等經驗;擅長linux系統和網路的各種操作,同時也喜歡研究各種新興技術。
PPTV OAK專案介紹
專案背景
PPTV作為國內視訊領域的領先者,對於大規模流媒體的儲存、處理、分發及應用,有著迫切的要求。容器技術及微服務模式的出現,使大規模的研發交付效率大為提高。本文介紹了PPTVOAK專案中Docker網路方案選型,以及對比了多種docker網路解決方案的特點後,最終結合PPTV網路架構的特點,選定了PPTV的Docker網路方案。
剛才有一個關鍵詞叫OAK,OAK是橡樹的英文單詞。PPTV的OAK專案,基於Docker技術打造了DCOS。底層基於Mesos + Marathon 為核心,結合Docker和Nginx,在此基礎上開發了DCOS管理控制檯、許可權管理模組、統一日誌管理模組、IP池管理模組、儲存管理模組,並與持續整合平臺Jenkins整合,實現應用容器的建立、執行。OAK致力於快速部署、彈性擴縮容、助力敏捷開發、實現故障自愈以及提高資源利用率。
OAK建設歷程
圖 1 OAK建設歷程
OAK功能框架
圖 2 OAK功能框架
2016年初的時候,我們開始在測試環境引入Docker。最早的計劃是將PPTV的所有開發測試環境都遷移到容器裡,考慮使用者群(研發/測試人員)對Docker的命令列操作不熟悉,如果我們直接把Docker底層的管理操作暴露給使用者,他們的學習成本會很高。為此我們使用了Mesos+ Marathon,可以通過Marathon快速建立容器,實現容器故障自動恢復。而實際上使用者對於容器的操作和原理完全不關心,他們只關心如何可以快速、簡單的構建一個開發或者測試環境。Marathon對於使用者來說還是過於生疏。為了讓使用者能更容易接受Docker,我們將容器的建立與Jenkins平臺結合。Jenkins是開發、測試人員比較熟悉的平臺。我們在Jenkins的編譯job中,把編譯出來的應用包儲存到一臺集中的伺服器上,同時呼叫Marathon的API建立一個與之對應的APP。這個APP會通過Marathon的uri引數把編譯好的應用包掛載到容器中,實現應用自動部署。
到了這裡,還存在一個問題,使用者要怎麼訪問已經部署好的應用?容器裡的網路預設用是一個私網的IP,此IP與容器所在宿主機上的Docker0網絡卡做了橋接,是不能跟外界通訊。所以Marathon在建立容器的時候,通過NAT將容器服務埠對映到宿主機的一個隨機埠上。也就是說,每一次容器重啟之後,對應的服務地址是會動態變化的。為此,我們引入了consul實現服務註冊和服務發現。每次容器服務地址變化時,將其更新到nginx反向代理的記錄中。同時,,應用的域名解析到nginx上。使用者訪問應用域名的時候,nginx會將請求轉發到具體的容器裡。到此為止,使用者已經可以通過Jenkins“一鍵”生成執行環境。
OAK架構圖
圖 3 OAK架構圖
2016年6月的時候,PPTV已經有80%以上的應用將測試環境遷移到了Docker中,所以我們也開始將目標轉移到了生產環境上。與測試環境不同,PPTV的生產環境網路流量很大(以視訊播放為主),所以對網路效能要求非常嚴格。Docker預設的bridge模式無法滿足。另外,生產環境是運維在管理。運維人員希望像管理虛擬機器一樣管理容器,希望容器有自己的IP,通過這個IP SSH登入到這個容器裡,他可以查日誌,監控,同步配置,或做一些其他的操作。到了這裡,就對容器的網路有了更高的要求,除了效能,還需要獨立IP,docker叢集之間的容器要互通,容器還需要和傳統環境的網路打通,能和傳統環境裡的應用IP通訊。
對Docker瞭解比較早同學應該會清楚。在Docker早期,還有Mesos+Marathon框架早期,是沒法滿足容器獨立IP的需求的。一直到2015年的11月,Docker1.9釋出,正式支援Overlay網路,支援跨主機網路模組的通訊。
Docker網路方案對比
早期的容器網路
早期的容器網路,就是主機內部的網路,想要把服務暴露出去需要通過iptables做埠對映。這是屬於“遠古時代”的東西,很難被企業使用。
圖 4 早期的容器網路
Docker早期的4種網路模式:
- Bridge模式:預設模式,為容器分配Namespace、網絡卡和IP等,並連線到宿主機的虛擬網橋(docker0)
- HOST模式:使用宿主機Namespace、IP和埠
- Container模式:使用已經存在容器的Namespace、IP和埠
- None模式:容器擁有自己的Namespace,需要另外新增網絡卡、配置IP等
Docker Overlay網路
圖 5 Docker overlay網路
Overlay網路是指在不改變現有網路基礎設施的前提下,通過某種約定通訊協議,把二層報文封裝在IP報文之上的新的資料格式。這樣不但能夠充分利用成熟的IP路由協議程序資料分發,而且在Overlay技術中採用擴充套件的隔離標識位數,能夠突破VLAN的4000數量限制,支援高達16M的使用者,並在必要時可將廣播流量轉化為組播流量,避免廣播資料氾濫。因此,Overlay網路實際上是目前最主流的容器跨節點資料傳輸和路由方案。
在Docker的1.9中版本中正式加入了Overlay網路的支援。
Flannel容器網路
圖 6 Flannel容器網路
Flannel是由CoreOS主導的解決方案。Flannel為每一個主機的Dockerdaemon分配一個IP段,通過etcd維護一個跨主機的路由表,容器之間IP是可以互相連通的,當兩個跨主機的容器要通訊的時候。會在主機上修改資料包的header,修改目的地址和源地址,經過路由表傳送到目標主機後解包。封包的方式,可以支援udp、vxlan、host-gw等,但是如果一個容器要暴露服務,還是需要對映IP到主機側的。
Calico 網路方案
圖 7 Calico網路
Calico是個年輕的專案,基於BGP協議.完全通過三層路由實現,對網路不熟悉的同學可能都沒有聽說過。Calico的目標很大,可以應用在虛機,物理機,容器環境中。在Calico執行的主機上可以看到大量由linux路由組成的路由表,這是calico通過自有元件動態生成和管理的。這種實現並沒有使用隧道,沒有NAT,導致沒有效能的損耗,效能很好,從技術上來看是一種很優越的方案。這樣做的好處在於,容器的IP可以直接對外部訪問,可以直接分配到業務IP,而且如果網路裝置支援BGP的話,可以用它實現大規模的容器網路。但BGP帶給它的好處的同時也帶給他的劣勢,BGP協議在企業內部還很少被接受,企業網管不太願意在跨網路的路由器上開啟BGP協議。
方案對比小結
簡單總結一下上邊提到的幾種網路方案,不外乎出自兩個技術流派,隧道方案和路由方案。
- 隧道方案
比如Flannel的VxLan。特點是對底層的網路沒有過高的要求,一般來說只要是三層可達就可以,只要是在一個三層可達網路裡,就能構建出一個基於隧道的容器網路。問題也很明顯,一個大家共識是隨著節點規模的增長複雜度會提升,而且出了網路問題跟蹤起來比較麻煩,大規模叢集情況下這是需要考慮的一個點。 - 路由方案
路由技術從三層實現跨主機容器互通,沒有NAT,效率比較高,和目前的網路能夠融合在一起,每一個容器都可以像虛擬機器一樣分配一個業務的IP。但路由網路也有問題,路由網路對現有網路裝置影響比較大,路由器的路由表應該有空間限制一般是兩三萬條。而容器的大部分應用場景是執行微服務,數量集很大。如果幾萬新的容器IP衝擊到路由表裡,導致下層的物理裝置沒辦法承受;而且每一個容器都分配一個業務IP,業務IP消耗會很快。
PPTV Docker網路解決方案
對比了幾種解決方案之後,結合PPTV的實際情況:
- 網路組人力不足以維護一個Overlay網路,Overlay網路出問題排查複雜,會出現失控的狀態。
- 隧道技術影響效能,不能滿足生產環境對網路效能的要求。
- 開啟bgp對現有網路改動太大,無法接受。
- 運維組同學希望能通過網路橋接的方案解決容器網路。
容器網路橋接
最終,我們的解決方案,基於Docker的bridge模式,將預設的Docker bridge網橋替換為Linux bridge,把Linux bridge網段的IP加入到容器裡,實現容器與傳統環境應用的互通。
實現思路很簡潔清晰,現在有一個Mesos主機:
- 首先會在該主機上新增一個Linux bridge,把主機網絡卡,可以是物理機的,也可以是虛擬機器的,把這個網絡卡加入bridge裡面,bridge配上網絡卡原本的管理IP。
- 建立一個新的Docker bridge網路,指定bridge子網,並將該網路的網橋繫結到上一步建立的網橋上。
- 容器啟動時候,指定容器網路為第二步中建立的bridge網路,同時為容器指定一個該網路子網內的IP。容器啟動後網路IP預設即可與外界互通。
這裡要注意的是第二步,我們的同學在研究這個方案的時候繞了一個很大的圈子,因為Docker容器使用Docker bridge網路模式的時候,在容器啟動時會預設把容器的閘道器指向到宿主機上的網橋IP,即Linux bridge的IP,而這個IP並不是該網段的閘道器。所以我們需要在容器啟動的時候將容器閘道器指向到實際的閘道器地址,而解決這個問題的方法在docker官方文件中並沒有提到,我們最終是在一個issue裡找到了解決辦法。
連結在此 https://github.com/docker/docker/issues/20758
給個簡單的例子
docker network create --gateway10.199.45.200 --subnet 10.199.45.0/24 -o com.docker.network.bridge.name=br-oak--aux-address "DefaultGatewayIPv4=10.199.45.1" oak-net
關鍵引數:--aux-address"DefaultGatewayIPv4=10.199.45.1"
以上邊的命令為例,該命令中建立了一個Docker bridge網路,並與Docker所在主機的br-oak網橋做橋接,該網路的使用了10.199.45.0/24這個子網,同時通過 --aux-address"DefaultGatewayIPv4=10.199.45.1" 這個引數將容器啟動時的閘道器指向到10.199.45.1
通過網橋的方式解決容器網路有兩個問題:
- Linux bridge 只能新增跟slavehost 同一個vlan的IP,也就是說容器IP必須要和宿主機在同一vlan下,這在一定程度上就限制了容器跨宿主機漂移的範圍。
不過這個問題在PPTV的生產環境中天然不存在,因為我們的生產環境中,每個資料中心的主機都在一個很大的子網內,基本能滿足容器在整個資料中心的任意節點下漂移。 - 要讓容器IP在不同的宿主機上漂移,宿主機的Docker網路需要使用同一個CIDR,也就是各宿主機的容器使用同一個網段。而不同宿主機的使用同一個容器網段就會涉及到IPAM的問題,因為宿主機的Docker daemon只知道他本機上的容器使用了哪些IP,而這些IP在其他宿主機上有沒有被使用,是不知道的。
在預設的Docker bridge中,因為這些ip不會直接與外部通訊,所以容器使用相同IP也不會有問題,但是當容器網路通過linux bridge打通以後,所有容器都是2層互通的,也就是會出現IP衝突的問題。
為了解決上邊提到的問題,實現全域性的IP管控,我們開發了IP池管理平臺,實現對容器IP的分配管理。由這個平臺管理的IP有三種狀態:
- 未分配給應用
- 已非配給應用並且在使用中
- 已分配給應用但是當前未使用
管理平臺以Marathon上的APP資訊作為資料來源,定期去呼叫Marathon的API更新IP列表。當我們要在Marathon上建立一個使用固定IP的容器時,首先會請求IP池管理平臺的IP分配介面,請求的時候把APP ID發給分配介面,管理平臺根據APP ID判斷這個應用是否是新應用,如果是新應用則從IP池中返回一個未使用的IP,並將此IP與應用關聯。如果是已經存在的應用則分配已關聯的IP。IP與應用關聯之後,此IP就不會再分配給其他應用,除非IP池已經沒有可用IP,這樣做是為了防止應用如果重啟或者重新構建的時候,IP有可能會被其他在同一時間啟動的例項使用掉的風險。
IP池管理模組分配IP的流程圖大致如下:
圖 8 IP分配流程圖
後續工作
網路方案搞定,固定IP搞定。我們要做的還有很多。
通過網橋的方式、解決了容器網路的問題,我們接下來還要面臨其他的問題。
首當其衝的就是原先的服務自動註冊、自動發現,不再適應了。因為原先的方案是基於NAT的模式做的,而現在實現了獨立IP的功能。我們需要將現有的平臺與PPTV內部的DNS做自動化對接,每當有容器建立和生成時,都會自動對容器的IP做DNS解析。
另外一個問題是負載均衡,PPTV的負載均衡基本都是通過LVS + Nginx實現的,但對於後臺的容器應用來說,每次擴容和縮容、或者建立新的應用,負載均衡的後端配置也是需要自動更新的。
原文連結:PPTV Docker叢集的網路方案選型