作者:shengdong
阿里雲K8S集群網絡目前有兩種方案,一種是flannel方案,另外一種是基於calico和彈性網卡eni的terway方案。Terway和flannel類似,不同的地方在於,terway支持Pod彈性網卡,以及NetworkPolicy功能。
今天這篇文章,我們以flannel為例,深入分析阿里雲K8S集群網絡的實現方法。我會從兩個角度去分析,一個是網絡的搭建過程,另外一個是基於網絡的通信。我們的討論基於當前的1.12.6版本。
鳥瞰
總體上來說,阿里雲K8S集群網絡配置完成之後,如下圖,包括集群CIDR,VPC路由表,節點網絡,節點的podCIDR,節點上的虛擬網橋cni0,連接Pod和網橋的veth等部分。
類似的圖,大家可能在很多文章中都看過,但是因為其中相關配置過於複雜,比較難理解。這裡我們可以把這些配置,分三種情況來理解:集群配置,節點配置以及Pod配置。與這三種情況對應的,其實是對集群網絡IP段的三次劃分:首先是集群CIDR,接著為每個節點分配podCIDR(即集群CIDR的子網段),最後在podCIDR裡為每個Pod分配自己的IP。
集群網絡搭建
初始階段
集群的創建,基於雲資源VPC和ECS,在創建完VPC和ECS之後,我們基本上可以得到如下圖的資源配置。我們得到一個VPC,這個VPC的網段是192.168.0.0/16,我們得到若干ECS,他們從VPC網段裡分配到IP地址。
集群階段
在以上出初始資源的基礎上,我們利用集群創建控制檯得到集群CIDR。這個值會以參數的形式傳給集群節點provision腳本,並被腳本傳給集群節點配置工具kubeadm。kubeadm最後把這個參數寫入集群控制器靜態Pod的yaml文件kube-controller-manager.yaml。
集群控制器有了這個參數,在節點kubelet註冊節點到集群的時候,集群控制器會為每個註冊節點,劃分一個子網出來,即為每個節點分配podCIDR。如上圖,Node B的子網是172.16.8.1/25,而Node A的子網是172.16.0.128/25。這個配置會記錄到集群node的podCIDR數據項裡。
節點階段
經過以上集群階段,K8S有了集群CIDR,以及為每個節點劃分的podCIDR。在此基礎上,集群會下發flanneld到每個階段上,進一步搭建節點上,可以給Pod使用的網絡框架。這裡主要有兩個操作,第一個是集群通過Cloud Controller Manager給VPC配置路由表項。路由表項對每個節點有一條。每一條的意思是,如果VPC路由收到目的地址是某一個節點podCIDR的IP地址,那麼路由會把這個網絡包轉發到對應的ECS上。第二個是創建虛擬網橋cni0,以及與cni0相關的路由。這些配置的作用是,從階段外部進來的網絡包,如果目的IP是podCIDR,則會被節點轉發到cni0虛擬局域網裡。
注意:實際實現上,cni0的創建,是在第一個使用Pod網絡的Pod被調度到節點上的時候,由下一節中flannal cni創建的,但是從邏輯上來說,cni0屬於節點網絡,不屬於Pod網絡,所以在此描述。
Pod階段
在前邊的三個階段,集群實際上已經為Pod之間搭建了網絡通信的幹道。這個時候,如果集群把一個Pod調度到節點上,kubelet會通過flannel cni為這個Pod本身創建網絡命名空間和veth設備,然後,把其中一個veth設備加入到cni0虛擬網橋裡,併為Pod內的veth設備配置ip地址。這樣Pod就和網絡通信的幹道連接在了一起。這裡需要強調的是,前一節的flanneld和這一節的flannel cni完全是兩個組件。flanneld是一個daemonset下發到每個節點的pod,它的作用是搭建網絡(幹道),而flannel cni是節點創建的時候,通過kubernetes-cni這個rpm包安裝的cni插件,其被kubelet調用,用來為具體的pod創建網絡(分枝)。
理解這兩者的區別,有助於我們理解flanneld和flannel cni相關的配置文件的用途。比如/run/flannel/subnet.env,是flanneld創建的,為flannel cni提供輸入的一個環境變量文件;又比如/etc/cni/net.d/10-flannel.conf,也是flanneld pod(準確的說,是pod裡的腳本install-cni)從pod裡拷貝到節點目錄,給flannel cni使用的子網配置文件。
通信
以上完成Pod網絡環境搭建。基於以上的網絡環境,Pod可以完成四種通信:本地通信,同節點Pod通信,跨節點Pod通信,以及Pod和Pod網絡之外的實體通信。
其中本地通信,說的是Pod內部,不同容器之前通信。因為Pod內網容器之間共享一個網絡協議棧,所以他們之間的通信,可以通過loopback設備完成。
同節點Pod之間的通信,是cni0虛擬網橋內部的通信,這相當於一個二層局域網內部設備通信。
跨節點Pod通信略微複雜一點,但也很直觀,發送端數據包,通過cni0網橋的網關,流轉到節點上,然後經過節點eth0發送給VPC路由。這裡不會經過任何封包操作。當VPC路由收到數據包時,它通過查詢路由表,確認數據包目的地,並把數據包發送給對應的ECS節點。而進去節點之後,因為flanneld在節點上創建了真的cni0的路由,所以數據包會被髮送到目的地的cni0局域網,再到目的地Pod。
最後一種情況,Pod與非Pod網絡的實體通信,需要經過節點上iptables規則做snat,而此規則就是flanneld依據命令行--ip-masq選項做的配置。
總結
以上是阿里雲K8S集群網絡的搭建和通信原理。我們主要通過網絡搭建和通信兩個角度去分析K8S集群網絡。其中網絡搭建包括初始階段,集群階段,節點階段以及Pod階段,這麼分類有助於我們理解這些複雜的配置。而理解了各個配置,集群通信原理就比較容易理解了。