從VETH到Kubernetes網絡通信剖析

本文背景

從雲計算到雲原生,計算資源、存儲資源和網絡通信是核心的三個模塊。Kubernetes作爲主流容器編排工具,也是雲原生提及最多的名詞,在計算資源調度與存儲資源使用兩個方面表現出色。

在網絡方面,由於容器架構層次深,網絡通信過程複雜,Kubernetes對網絡通信支持不盡完美,雲計算領域普遍存在這個問題。儘管如此,Kubernetes網絡表現出很靈活,提供CNI模式給用戶使用第三方插件自定義網絡。該自定義網絡依賴傳統網絡,或者說與傳統網絡融合。

摘要

Pod是Kubernetes最小的原子調度單位,Kubernetes上的服務應用跑在Pod裏面。從業務遷移Kubernetes的角度來看,是應用從物理主機或者虛擬主機遷移部署到Pod的過程。

要保證Pod上的應用正常提供服務,之前在物理主機需要解決的問題,現在Pod裏面也要解決:機房內Pod中服務可以相互通信;Pod網絡IP地址分配;機房外可以訪問Pod中服務;有高可用方式來訪問Pod中服務;對進出Pod中網絡流量管控等等。

1 虛擬化網絡

在Pod中運行着應用的是一組Docker容器,而Docker使用的核心技術是Linux虛擬化[1]。所以,虛擬化網絡是Kubernetes網絡通信一個重要基礎。

01 網絡隔離

在Linux內核中有Namespace(命名空間)的概念,其作用是資源隔離。同一個命名空間資源共享,不同命名空間資源相互獨立。Docker使用這種隔離技術,使容器自身看起來是一個獨立的操作系統,擁有屬於自己6個命名空間下的資源:Mount、UTS、IPC、PID、Network、User。

其中Network是網絡命名空間,用來隔離網絡設備,擁有獨立的網絡協議棧以及網絡資源。以下運行容器進程PID=5146,擁有自己獨立的命名空間資源,[4026532000]是我們關注的網絡空間。

02 虛擬網卡對

網絡與通信是離不開的,單個網絡空間即使有獨立網絡資源,但並不能與其他網絡空間或者主機網絡進行通信。Veth Pair是虛擬網絡技術中常用的一對虛擬以太網卡,一端在當前空間充當網卡設備,另一端在其他空間充當網卡設備或者是主機網絡上的虛擬網卡設備。

Veth Pair打通了不同網絡空間的通信隔離,但是網絡資源上不同空間仍然獨立。容器id=[482218a11ab7]網卡eth0與主機網卡veth972d941使用Veth Pair連接,設備if34 與設備if35建立link鏈接。

Veth Pair工作在同一主機下,兩個虛擬設備端到端連接。多設備連接,Linux網絡虛擬化實現了Bridge虛擬網橋設備,邏輯上的交換設備,有多個端口連接多個虛擬設備。

在不同主機中網絡命名空間通信場景,數據報文從一臺主機上的網絡空間到另外一臺主機的網絡空間。除了路由的方案,還能在通信網絡空間之間創建隧道網絡。虛擬設備tun(tunnel,隧道)一邊連着用戶態程序,一邊連着內核態的網絡協議棧。

03 自定義網絡

從網路命名空間1流出的數據報文,經過tunnel設備完成隧道報文封裝,回到主機網絡協議棧,由主機網絡設備發送給目標網絡命名空間所在主機網絡設備。

網絡命名空間上添加虛擬設備,在主機內可以創建局部虛擬網絡拓撲。甚至在不同主機之間,結合已有的物理網絡可以創建隧道網絡。在Linux網絡虛擬化技術支持下,可以靈活創建網絡,同時,網絡鏈路也變長加深。

2 Docker網絡

Docker容器擁有自己獨立的網絡空間,容器創建過程中按照定義的網絡模式,進行網絡配置初始化,添加特定功能的虛擬網絡設備。常用的Docker網絡模式有Bridge、Host、Link、None4種。

  • Bridge:橋接網絡,上面提及Bridge虛擬設備,功能與Veth Pair類似,網絡流量從設備一端流入,在另外一端流出,但是Bridge設備支持多個端口,像是物理設備上的交換機。

Docker初始化網絡環境過程,在容器的網絡命名空間,新建了一個虛擬的以太網卡eth0,並且綁定eth0在VethPair上一端,Veth Pair另外一端與docker0連接。docker0是主機上Docker服務創建的Bridge網橋,使用Bridge方式的容器默認會連接到這個網橋,用戶也可以自定義網橋。

數據報文從Veth Pair一端進入docker0,在上面執行路由判斷,決定是流向其他容器還是轉發到主機的網卡,再流向主機以外,使用NAT網絡地址端口轉發,修改源地址爲流出網卡地址,向目的地址發出去。

  • Host:主機網絡,容器加入到主機的網絡命名空間,與主機共享網絡協議棧和網絡資源,主機容器數量較大時,容易造成資源衝突,不易於管理。
  • Link:共享網絡,容器加入到其他容器的網絡命名空間,與其他容器共享網絡協議棧和網絡資源。
  • None:不使用Docker提供的幾種網絡模式,啓動的容器只有一個lo網卡(迴環網絡),用戶可以自定義網絡方式。
  • Macvlan技術在主機網卡上創建多個子網卡,並且分配不同的IP地址和MAC地址,每個子網卡相互隔離,並且分配給容器使用。
  • Overlay在原有的網絡拓撲結構上創建一層虛擬的通信網絡,上面提到的隧道網絡是一個Overlay例子。

3 Kubernetes網絡

Kubernetes網絡主要解決Pod網絡IP地址分配和網絡通信的問題,在創建Pod過程中,Kubelet支持CNI(Container Network Interface)插件,爲Pod定義網絡。同理,在Pod刪除過程中,由CNI接口銷燬網絡。常用的CNI插件有:Flannel[2]、Calico[3]、Waeve等等。

01 Flannel網絡

最早實現CNI標準的網絡插件,架構簡單明瞭。在集羣節點上運行flanneld常駐進程,監聽獲得Etcd中設置的網段,修改Docker啓動參數中網段配置,確定節點上Pod的網絡地址範圍,並且對進出Pod的數據報文做封包解包。

Etcd集羣保存Kubernetes集羣節點劃分的網絡信息,節點flanneld從Etcd中拉取數據,並且生成路由信息,內容爲訪問某個Pod地址,從flannel0設備出去,下一跳是Pod所在的主機地址。

其實Flannel常用Overlay、VXLAN、Host-gw幾種模式。Overlay模式數據報文經過flannel0虛擬tunnel設備(一端連接協議棧一端連接用戶態進程),flanneld對報文封裝成UDP報文,轉給協議棧處理,最後由當前節點網卡發送到目的節點網卡。同理接收端流程,數據報文由flanneld對UDP報文解包,轉給網絡協議棧發給目的Pod網卡。

VXLAN模式數據報文傳輸過程與Overlay模式相似,但是報文不再經過flanneld封包解包,flannel0網卡替換成flannel.1的VXLAN網卡,在flannel.1上完成內核態內核VXLAN封包解包,不再流向用戶態處理,提升效率。Linux內核3.7開始支持VXLAN,內核3.12完備VXLAN功能,所以在內核3.7以前系統不支持使用VXLAN。

Host-gw模式效率最高,以主機網卡作爲出口網關,跨節點通信使用路由表完成,要求集羣節點都在同一個網絡內,限制了集羣規模,並且路由表規則數量過多也會影響性能。

02 Calico網絡

Calico性能較好,功能較全面的CNI網絡插件。與Flannel大有不同,集羣外部可以直接訪問Pod的網絡地址。在架構上分四個部分:Felix、BGP Client、中心節點、Etcd。

Felix與BGP Client運行在集羣節點,負責路由和ACL規則配置,以及通過BGP(Border Gateway Protocol)協議[4]同步路由到集羣其他節點;Etcd保存網絡數據,提供watch機制協同組件交互;Route Reflector(中心節點)是集羣規模較大時使用的路由交換中心,負責集中式路由分發。

Calico基於BGP路由協議支持扁平網絡,也支持Overlay的方式。BGP路由模式Pod中數據報文從虛擬的eth0流向虛擬網卡calixxx,兩個虛擬網卡使用Veth Pair連接起來。報文來到主機內核網絡協議棧並且匹配路由表,判斷同主機的Pod訪問,爲是則轉發到對應calixxx虛擬網卡,爲否則轉發到目的Pod所在主機的IP地址,並且從eth0網卡出去。

有時候,機房網絡不支持BGP模式,例如開啓源和目的地址檢測等,使用Overlay的模式代替。基於IPIP的隧道網絡,與前面Flannel Overlay網絡不同,IPIP是在內核層完成報文封裝。同樣,Pod數據報文出來,同節點訪問是一樣的鏈路。而不同節點通過tunl0虛擬網卡進行節點主機源和目的地址的IP頭部封包,再由eth0發送出去。

IPIP隧道,比常規的數據報文多了一層IPIP的網絡層數據包頭,報文進入內核網絡協議棧,解析到第一層IP頭部,發現協議是IPIP,即進行第二次IP協議解析,拿到原始的IP報文。

CNI在地址管理上有三種分配IP地址的方式,Kubernetes 註解方式、CNI 配置以及基於節點選擇器的IP池。Calico網絡常用方式爲集羣節點基於節點選擇器的IP池,爲集羣節點打上不同的網絡標示Label,把Pod的網絡分配給相應的節點。

  • 同節點pod鏈路,Pod中的eth0連通Veth Pair綁定在節點主機上的虛擬網卡,進入內核路由選擇,流向另外一個Pod的Veth Pair端口。
  • 跨節點pod鏈路,Pod中的eth0連通Veth Pair綁定在節點主機上的虛擬網卡,進入內核路由選擇,或者進行封包,經過eth0流向目的主機,然後逆向前面的過程。
  • 外部到pod鏈路,通過Ingress、Service的NodePort、公網IP綁定LoadBalance幾種方式

4 Kubernetes Service

Kubernetes引入了Service的概念做負載均衡,通過Label匹配的方式綁定後端Pod的IP地址作爲Endpoints,從而提高服務穩定性與可用性。Service實現的負載均衡操作由集羣節點上的Kube-Proxy來完成。實現了ClusterIP、NodePort、LoadBalance三種方式。

ClusterIP使用集羣IP地址的方式表示Service,訪問該地址就會負載均衡到Label匹配的Pod。NodePort使用端口映射的方式,集羣內全部節點暴露端口,做網絡地址端口映射到後端的Pod。LoadBalance需要接入負載均衡服務。

Kube-Proxy分別在用戶空間、Iptables、IPVS三種模式下實現Service的功能。Iptables是常用的一種,IPVS性能較好,也要依賴Iptables。

01 Netfilter鉤子

Netfliter[5]是Linux內核網絡數據報文處理子模塊,IPVS與Iptables內核層實現在Netfliter上鉤子處理各自定義函數。

在5個地方創建鉤子:PRE、IN、OUT、FWD、POST,分別對應Netfliter數據解析流中:流入主機、進入本機、流出本機、轉發、流出主機。這裏,進出主機指無論數據報文是否發給當前主機IP地址,數據報文都經過當前主機,進出本機指當前數據報文以本機IP地址作爲目的地址。

圖片來源:Netfilter官網

02 Iptables模式

Iptables有5張表,按照執行先後順序爲(Raw\Mangle\NAT\Filter\Security)表除了執行順序還有一個作用是進行規則歸類。Raw做鏈路跟蹤(與上圖Conntrack對應),Mangle修改IP數據報文,NAT做數據報文地址轉發,Filter做數據報文匹配過濾,Security是安全規則匹配。有5條鏈對應Netfilter上5個鉤子,在鏈上定義規則,轉發成Netfilter內核處理函數:PREROUTING\INPUT\FORWARD\OUTPUT\POSTROUTING

Kube-Proxy使用Iptables:app-vs-pre對外暴露NodePort=30035服務,通過節點訪問30035端口或者ClusterIP訪問10086端口,轉發到NAT表上面定義:隨機轉發概率均等(0.50000000000)的流量轉發規則,並且目的地址修改成app-vs-pre Service後端Endpoint。

03 IPVS模式

IPVS與Iptables不同,只在IN、FWD、POST 3個點掛鉤子,支持多種負載均衡方式(NAT、TUN、DR)和調度算法。Service中NodePort方式數據報文經過本機LOCAL_IN鏈,ip_vs_in 將其轉到POSTROUTING進行目的地址端口轉發,指向真實的Endpoint。

圖片來源:Interaction between LVSand Netfilter (iptables)

Kube-Proxy使用IPVS示例:Kube-Proxy爲IPVS創建dummy網卡,默認命名爲kube-ipvs0,將所有新建Service的ClusterIP綁定到該網卡,上面提到IPVS的DNAT鉤子掛載在LOCAL_IN生效,所以ClusterIP要被認爲是本機IP地址纔會走到這一步。

以下my-Nginx的ClusterIP(10.144.18.2)綁定在kube-ipvs0,後端設置地址爲19.18.112.102,19.18.15.42的兩個Endpoint。ipvsadm工具查詢IPVS規則列表,10.144.18.2:80作爲VIP負載兩個後端Endpoint,RR輪詢算法並且做NAT地址端口轉換。

5 Kubernetes Ingress

工作在HTTP\HTTPS層,可以做外部訪問內部入口。Kubernetes提供原生的 Controller,也可以自定義其他的HTTP負載均衡插件。原生Ingress Controller基於Nginx轉發,配置多個Service域名轉發到Service的ClusterIP。Ingress可以綁定Service的NodePort暴露或者通過公網IP映射暴露給外部訪問。

以下是Nginx官方[6]提供作爲Ingress Controller服務轉發示例,Controller部署後通過client-go的watch機制感知Service的Endpoint變化,實時設置Nginx服務中轉發配置,HTTP請求會根據不同的hostname,按照Nginx轉發配置,重定向到後端Pod的服務。

總結展望

  • 回顧虛擬網絡,Linux虛擬化技術中命名空間進行資源隔離,包括網絡隔離。不同命名空間網絡相互獨立,使用虛擬以太網卡對 Veth Pair,相互獨立的網絡命名空間可以相互通信。Bridge網橋技術支持多個端口,同時支持多個隔離空間通信。命名空間與cgroup在Docker容器中佔重要地位,命名空間使得Docker像獨立的操作系統運行。

    Kubernetes中最小原子調度單位,由一組Docker容器組成,在網絡方面共享網絡命名空間。Kubernetes提供CNI插件支持用戶靈活自定義網絡,使用路由、覆蓋網絡等技術,實現Pod的通信。

  • 後續工作,Kubernetes CNI插件中:Flannel、Calico等廣泛應用到生產環境,在網絡可用性、網絡性能和網絡功能上,仍然存在部分有待開展的工作。網絡質量監控方案調研與落地;Ingress 網關方案調研與落地;Service 中LoadBalance方式基礎原理與實現過程;Kube-Proxy Service模式切換穩定性驗證等等。

參考文獻

本文轉載自公衆號vivo人工智能技術(ID:)。

原文鏈接

https://mp.weixin.qq.com/s/9tGVnjb71M-7LY3nNGMX3Q

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章