跨VPC或者跨雲供應商搭建K8S集群正確姿勢-番外篇
- 2020 年 2 月 26 日
- 筆記
本文靈感主要是來自於張館長的文章《跨VPC或者跨雲供應商搭建K8S集群正確姿勢》,因此取名《跨VPC或者跨雲供應商搭建K8S集群正確姿勢-番外篇》
上周發了幾篇關於Kubernetes集群搭建相關的文章,裡面有一個部分談到了Kubernetes集群CNI插件(也就是容器網路介面)的部署,很多讀者看到了這個部分之後有問到「如何跨VPC或者跨雲供應商打通集群之間的網路訪問」,我當時搭建集群和寫文章的時候也沒有注意這點,只是根據以往的經驗單純地把幾台機器搞在一起再加上部署好CNI就想當然的以為Kubernetes集群算是「全網通」了。經過讀者的提醒和自己的實踐,發現忽略了一個嚴重的問題,也是大多數人在個人搭建Kubernetes集群常常會碰到的問題,也是就今天需要談論的問題—「如何跨VPC或者跨雲供應商搭建Kubernetes集群,保證集群網路互通」。
為了解決這個問題需要從幾個方面思考:
- 單一VPC和跨VPC/雲供應商的網路方面的區別
- 單一VPC和跨VPC/雲供應商的網路環境下Kubernetes集群的區別
- 跨VPC/雲供應商的Kubernetes集群搭建時需要注意的點
- 採用何種CNI來保證跨VPC/雲供應商的Kubernetes集群的網路互通
本文會基於以上幾點問題來展開,最後會根據我們思考的點給大家演示下具體的實戰,可能有些點說的不太清楚,希望大家可以狠狠的批評!
1. Kubernetes集群搭建相關問題思考
1.1
單一VPC和跨VPC/雲供應商的網路方面的區別
首先了解下什麼是VPC?

這裡直接搬出百度百科的解釋,直白地說,首先從服務的角度來看,VPC指的是一種雲(Cloud),這與它的字面意思相符。你或許聽過公有雲(Public Cloud),私有雲(Private Cloud),混合雲(Hybrid Cloud)。不過,VPC不屬於這三種雲中任一種。這是一種運行在公有雲上,將一部分公有雲資源為某個用戶隔離出來,給這個用戶私有使用的資源的集合。VPC是這麼一種雲,它由公有雲管理,運行在公共資源上,但是保證每個用戶之間的資源是隔離,用戶在使用的時候不受其他用戶的影響,感覺像是在使用自己的私有雲一樣。它在概念上有點類似於VPN(Virtual Private Network),不過VPN只是在網路資源上的隔離,VPC更像是VPN的超集,VPC是對各種資源上對各個用戶的隔離。
而我們這次主要講不同VPC網路上面的隔離,用一個圖來演示下不同VPC之間的關係。

從上面這張圖可以看出,每個VPC都有自己獨立的IPv4 CIDR和IP地址,在單個VPC中的每個Node節點又會根據網址劃分規則獲取自己的VPC內網地址,由於Node A1和Node A2是同處一個網段,可以相互通訊(原理上是源節點根據發送ARP請求到廣播域讓目標節點獲得ARP請求把MAC地址單播到源節點,獲取到MAC地址之後,封裝XX等協議包經由物理傳輸進行通行通訊)。而在不同VPC之間,由於網段的不同,比如Node A1(10.4.0.1)和Node B1(10.3.0.1),不能直接通過內網地址通訊,需要通訊的話一是通過兩個Node的公網IP來訪問,二是通過VPC的封裝轉發來通訊,大家想要仔細了解可以參考Docker的網路原理。
上面說了這麼多都是為了讓大家理解VPC具體在網路方面做了什麼隔離,那麼大家現在應該可以明白單一VPC和跨VPC/雲供應商之間的網路區別是什麼,在單一VPC集群里,各個節點都是在同一網段下,可以直接進行通訊,不需要配置額外的轉發,而在跨VPC/雲供應商的環境中,各個Node節點是不能夠直接通過內網IP進行通訊的,不過可以通過公網IP進行通訊。
1.2
單一VPC和跨VPC/雲供應商的網路環境下Kubernetes集群的區別
上個問題我們理解到不同VPC之間的Node節點是不能直接訪問的,那麼這點對於我們在搭建Kubernetes集群的時候有什麼影響呢?
假設我們現在有1台Master節點、1台Node節點,要搭建雙節點的集群,我們從幾個特定的場景看看單一VPC和跨VPC/雲供應商的網路環境有什麼區別。
當在單一VPC中的時候,Master為10.0.0.1,Node為10.0.0.2,當在跨VPC/雲供應商的時候,Master為10.0.0.1,Node為10.0.0.2
- 場景一:Node要加入集群

如圖所示,Node加入集群需要通過訪問Master節點的ApiServer服務加入,既然要通過訪問服務加入,也就是需要Node、Master互通才能做到訪問,當然也可以通過Node訪問Master節點的公網IP來訪問,前提是Kubernetes集群初始化的時候暴露出公網地址。
- 場景二:Master調度Pod到Node,需要獲取Pod具體情況

從圖裡面可以看出,每個節點都有自己的INTERNAL-IP,而當Master節點調度Pod到Node上的時候,Master節點通過describe和logs等命令獲取數據時也是需要Master節點和Node節點互通的,Master和Node節點能否互通是通過查看INTERNAL-IP是否是同一網段的,而INTERNAL-IP是通過Kubectl查詢節點上面的物理網卡(例如eth0,enoxxx)的地址,而物理網卡的地址往往都是子網的地址,所以在跨VPC/雲供應商的網路環境必然是不可能處於同一網段的。
- 場景三:Master需要收集Node節點數據 同理場景二,當Master節點需要獲取Node節點的數據的時候,需要通過訪問Node節點暴露出的埠來獲取數據,此時也是需要Master能夠與Node節點互通的。
1.3
跨VPC/雲供應商的Kubernetes集群搭建時需要注意的點
這個問題是我本次基於跨VPC或者跨雲供應商搭建Kubernetes集群時所想到的,也是一個個人搭建Kubernetes集群時注意到的點。
- 雖然是跨VPC,但是需要保證每個節點都有自己獨立的公網IP。
- 由於使用的是Kubeadm Config的方式來初始化Kubernetes集群,所以需要保證Kubeadm將ApiServer服務暴露在公網,其他具體的Kubeadm Config配置會在之後的實戰時具體講解。
- 由於Node節點加入集群的時候被登記的INTERNAL-IP是節點內網IP,這樣Master節點在和Node節點通訊的時候會直接訪問Node的內網IP,所以需要做Iptables的NAT轉發。
1.4
採用何種CNI來保證跨VPC/雲供應商的Kubernetes集群的網路互通
經過詢問各位大佬的建議和自己的實際操作,發現主要有以下幾種方式:
- Flannel VXLAN的模式
Flannel網路通訊原理可以看看這篇文章:
https://blog.51cto.com/liuzhengwei521/2427495 https://blog.51cto.com/14143894/2462379
Flannel主要有三種模式,UDP、VXLAN、host-gw,而由於host-gw的原理是將每個flannel的子網的下一跳,設置成該子網對應的宿主機的IP地址,也就是在於IP包在封裝成幀發送出去的時候,會使用路由表的「下一跳」來設置目的MAC地址,這就要求必須通過二層網路到達目的宿主機,所以host-gw模式必須要求集群宿主機之間是二層連通的,host-gw模式就被我們放棄了。

而UDP是Flannel最開始採用的方案,但是由於IP包多次在內核態和用戶態之間做切換,因此效率最慢,作為Kubernetes集群的網路平台顯然會拖累整個集群的響應能力,因此也被放棄了,那麼只剩最後的VXLAN模式,也是目前官方主推的模式,我們來簡單理解下VXLAN模式的原理:

一句話概括,當兩層網路抵達不了的時候,通過虛擬設備的封包解包模擬出一層網路,造成「第三層網路」,在網路上實現互通。
- Calico IPIP的模式 Calico主要有兩種模式:BGP和IPIP模式,和Flannel CNI類似,Calico BGP類似於Flannel host-gw模式,是一種基於路由的模式,沒有封包和解包過程,完全基於兩端宿主機的路由表進行轉發,因此效率很高,但是必須要求兩層互通,而且也會因為Iptables膨脹導致性能降低,因為宿主機上每個容器需要在本機添加一條路由規則,而不同宿主機之間需要廣播自己的網段路由規則。而IPIP和Flannel VXLAN原理一樣,就是基於隧道的模式來建立的,但是好一點的是Calico的封裝協議IPIP的header更小,所以性能比Fannel VXLAN要好一點點。
- Canal 這個Canal不是阿里出的MySQL Binlog同步工具,而是華為出的基於Calico和Flannel開發的工具,不過這個工具的文檔較少,所以沒有具體研究。
2. Kubernetes集群搭建實戰
上面講了很多「不清不楚」的原理,下面可以開始正式的實戰了,本次採用三個雲伺服器作為節點,三個節點均處於不同的VPC網路下面,每個節點都有自己的公網IP,張館長的部落格寫明了在搭建好集群之後所有配置,但是沒有寫明初始化集群的時候如何配置,我在初始化集群的時候發現加入集群之後總是導致新的Flannel Pod無法啟動,原因是因為無法和集群的ApiServer通訊,因此在初始化的時候需要更改寫Config的參數。
2.1
Kubeadm Config初始化集群
首先來看下我的Kubeadm Config配置

主要需要注意的點是三個部分,從上往下看
- controlPlaneEndpoint 這個配置需要填寫公網IP以及對應的開放給公網的埠,如圖中的xxxx:6443,如果沒有寫上這個的話,會默認訪問clusterip:443,為了更方便對外網訪問以及調試,可以做修改。
- apiServer 控制apiServer的暴露地址,修改為公網IP是為了能夠讓Node節點從公網進行訪問。
- networking.podSubnet 劃分子網的CIDR,這個是根據我們選擇的CNI插件來填寫的,默認Flannel的是10.244.0.0/16,默認Calico的是192.168.0.0/16,這個配置可以根據需求自由填寫。
2.2
Flannel CNI部署及修改
Flannel CNI插件默認開啟的模式就是VXLAN模式,可以參考官方配置文件

可以看到Backend使用的是vxlan模式。
Flannel主要修改在於部署好Flannel CNI插件之後對於每個節點的Annotations上的public-ip參數進行修改,默認的都是使用內網IP,在使用Flannel VXLAN進行通訊的時候也是訪問不同,因此需要進行修改。
2.3
Iptables相關修改
參考張館長的文章,Master通過logs和describe命令調用Node上的某一Pod的時候,往往會出現timeout的情況,這是由於Master和Node之間不能直接通訊,而Master調用Node是根據Node的網卡地址的IP,這個IP是內網IP,因此需要做Iptables的NAT轉發,如圖

2.4
Metrics Server相關修改
在部署metrics server的時候會遇到不能獲取Node節點數據的情況,原因還是因為Master節點訪問不通Node節點,而Master訪問的方式是通過Hostname:xxx的方式,而正常解析域名的時候會把Hostname解析成Node的內網IP,這樣會訪問不通,所以需要增加hostAliases來自定義hosts,讓Master解析域名的時候解析到Node節點的公網IP上才能對Node節點上的數據進行收集。

3. 後續
以上就是對於跨VPC或者跨雲供應商搭建K8S集群的思考,雖然成功的實現了集群之間的互通,但是方式上顯得不那麼「友好」,後續會繼續研究相關方案,希望大佬們能夠提供寶貴的意見。

– END –
關注公眾號,回復【docker】【k8s】【電子書】【ppt】,有更多資料供你學習!