Rancher容器網絡-Floating IP解決方案
Rancher網絡使用中遇到的問題
首先,在為某一個stack編寫Rancher catalog的時候,假設在docker-compose里指定了ports A:B,那么,cattle在調度的時將首先過濾掉所有已經占用了port A的主機。這也就意味著,假設用戶只有4臺host作為Rancher agent,但是需要運行5個在外網中占用80端口的服務,這顯然是不行的。
另一方面,客戶端通過主機的IP地址來訪問Stack提供的服務,一旦由于系統異常,或者微服務內部程序崩潰導致Service被重新調度到其他主機,勢必導致訪問Stack服務IP地址的更改。
為了讓客戶端不被影響,常見的解決方案是通過使用Rancher提供的external-DNS;如果業務在公網,有像AWS的Router-53之類的解決方案;若是自建數據中心也可以通過使用支持RFC-2136的硬件路由器等來實現DNS條目的及時刷新。
從當前Github代碼看External-DNS已經支持下面的Provider了:
但是,通過刷新DNS的方案要么價格昂貴,要么需要自己維護一個Rancher外部的DNS Server,都存在一定缺陷。
那么,有沒有一種方式,既能夠解決端口沖突,又能夠解決stack對外服務IP變更的問題呢?答案就是今天我們的主角:Floating IP!
Floating IP解決方案
上一次Alan為大家分享的「關于在Rancher中使用keepalived」中就有提到VIP的概念,只是keepalived需要在Active+Passive的主機之間周期性發送心跳報文,然后基于優先級來判斷將VIP綁定到哪一個host,它解決了服務遷移后訪問的目標IP地址變化的問題。
而Floating IP卻是從另一個角度來解決問題。熟悉OpenStack的人對Floating IP應該都不會陌生,所謂Floating IP就是為某臺虛擬機綁定的一個外網IP地址。綁定之后,無論該虛擬機在OpenStack內被遷移到哪一臺hypervisor,外網都可以通過Floating IP來訪問到該虛擬機。我們來看Rancher中是怎么引入Floating IP的。首先上一張總體模塊框圖:
從圖上我們可以看到,整個Floating IP的實現,只需要兩個模塊,或者說兩個微服務:Metadata-confd和Network-plugin。至于IPAM為什么不需要重新實現,我們后面會講到。接下來我們講一下各個模塊功能和作用。
Metadata-confd:
這是一個使用了Rancher managed網絡的service,通過managed網絡,它按照一定的周期從Agent-Instance上polling metadata信息。采用分布式架構,每一個Metadata-confd只關注屬于自己host上的容器。
但是,也并非所有的container都會觸發后續行為,只有該host上帶有“io.rancher.container.floating.ip” 標簽的容器有被新增、刪除或更新IP的時候,Metadata-confd才會通過docker client向docker daemon發送操作命令。
需要注意的是,這里的network均是指Floating IP所在的網絡。
對于Metadata-confd的實現方式,除了通過通過周期性polling之外,也可以采用支持Rancher backend的confd來生成map文件(包含ip <—> floating ip映射),然后使用confd里面的reload-cmd參數,指定腳本去解析和做后續處理。當然,這種方法存在不少坑,大家可以下來自己研究。
FIP Network Plugin:
FIP Network Plugin是按照CNM的定義來實現的一個libnetwork的remote driver。該service使用host網絡,遵照docker deamon發送過來的請求指令,實現網絡相關的操作。Network plugin所做的事情,我們可以通過下圖來理解:
原生的docker bridge driver創建了docker0網橋,然后將所有的container通過link pair掛到橋上。在network root namespace內,通過NAPT規則將對Host上特定port的訪問DNAT到container的內部port。而在Floating IP網絡中,FIP network plugin創建了一個新的bridge,然后將label含Floating IP的container連接到該bridge上。
由于使用了與docker0 共享的“default” driver的IPAM,FIP network bridge的IP地址段不會與docker0所在的網段重疊,從而保障container在連接了兩個網段后,路由不會沖突。
按照CNM的定義,Docker Network Plugin主要需要實現以下方法:
- create network
- delete network
- create endpoint
- delete endpoint
- join endpoint to network
- leave endpoint from network
而FIP Network Plugin除了要實現基本的功能外,還需要為Floating IP添加以下功能:
- 當收到join endpoint to network請求時,將Floating IP配置到host IP所在的接口上;
- 更新主機的NAT規則,將所有destination IP為FIP的報文DNAT到container的內網IP;
- 當container銷毀時,執行反向的操作。
這些修改之后,container其實還無法通過FIP回包,為什么呢?有興趣的可以研究一下掛載了兩個network后container的路由表條目。至于還需要如何配置,大家可以下來自己實驗。
演示
現在我們來做一個實驗,看看Floating IP的報文轉發是如何工作的。
1.首先在Rancher catalog中選擇“Wise2C Floating IP”,從詳細頁面看,Floating IP這個stack不需要添加任何配置參數:
啟動過程中,可以看到:該stack在一個host ”vm-153-5”上啟動了兩個containers(在每個host上均會被調度):
2.服務啟動成功后,我們到host里面可以看到已經初始化好的network(其網段是172.18.0.0/16):
3.然后我們再通過Rancher創建一個帶有標簽為“io.rancher.container.floating.ip=192.168.99.200”的container。這里的IP地址就是我們希望為該container綁定的Floating IP:
4.當container啟動成功后,metadata-confd會檢測到該label,然后向docker daemon發送請求將該container加入到wise2c network。我們可以進入container查看interface詳情來了解到:
上圖中接口eth1@if9就是接入到wise2c network的接口,其IP地址屬于172.18.0.0/16網段。
5.再來看host上的IP地址和NAT規則
其中enp0s8就是我們host的default gw對應的出口網卡,可以看到floating ip:192.168.99.200已經被添加到上面了。
主機的NAT表:
上圖就是我們的network-plugin為Floating IP創建的基于destination IP的DNAT規則,其中br-d62debee292b是FIP network plugin為wise2c network創建的bridge。
下面的DNAT規則是將所有不來自br-d62debee292b,且目標IP地址為192.168.99.200的報文DNAT到172.18.0.2容器。
6.接下來就是驗證網絡,在客戶機(192.168.99.1)上ping Floating IP:
到wise2c network的bridge上抓包:
可以看到,DNAT規則已經生效。
總結
我們再來整理一下使用場景。
初始化:
1.首先FIP catalog指定在所有運行了Rancher agent的主機上均啟動Floating IP service;
2.在服務啟動后,Metadata-confd向docker daemon請求創建FIP network,然后開始polling Rancher metadata信息;
一旦發現本機上存在帶FIP標簽的容器,Metadata-confd就向docker daemon請求將容器接入FIP network;
3.接下來network-plugin從docker daemon收到創建FIP network和將容器接入FIP network的請求后,執行操作。
在這個過程中,Floating IP被添加到host上默認網關對應的網卡,并更新NAT規則,保障外網訪問Floating IP的流量被DNAT到容器。
容器遷移:
1.當容器從Host-A遷移到Host-B,Host-A上的docker-daemon會發起將container移出FIP network。network-plugin只需要按照leave endpoint from network的流程,逐一刪除NAT規則,并移除host上的Floating IP address。
2.在Host-B上執行的操作除少了初始化時候的創建FIP network外,其他操作流程同“初始化”。
Q & A
Q:其他編排引擎怎么支持?
A:除了通過CNM來實現外,還可以通過外部實現,只需要能夠為主機配置IP地址和NAT規則就能夠支持的了。只是如果通過CNM實現,對資源的釋放可以由docker daemon來觸發,不需要完全自主控制。
Q:Metadata-confd poll metadata service的間隔是不是需要很短?否則是不是可能存在舊的host IP還沒有移除,新的host已經在嘗試添加IP的情況,導致IP沖突?
A:如果采用poll的方式來實現肯定是有一定的時間間隔的缺陷的,如果無法接受,就可以采用支持Rancher backend的confd來實現。
Q:今天講的FIP在k8s環境下也可以用嗎?
A:其實理論上是可用的,但我們還沒測試。因為方案只用了docker label, Rancher metadata service 和 docker libnetwork,這些在Rancher 的k8s 環境都是有的。
Q:managed網絡還是基于ipsec的隧道網絡嗎?性能上怎么樣呢?
A:是的,基于ipsec,在很多生產環境的實際使用中,沒什么性能問題,性能就是和普通V*N 一樣。在Docker本身提供的幾種網絡基礎上提供了一種叫做Managed的網絡特性,官方說法如下:The Rancher network uses IPsec tunnelling and encryption for security。
簡單理解就是在容器之間構建了一條私有網絡,只有容器與容器之間可以訪問。
Rancher會為每個容器分配一個 10.42. . 的私有網絡地址,這個地址只在容器之間是可達的,對外不可見,有點類似一種純軟件上的VPC方式。從路由上可以看出,對于10.42網段的路由是通過docker0接口,docker0的特殊的配置了IP也包含了10.42網段。
來自:http://dockone.io/article/1962