K8s網絡模型

  •  

一、前言

k8s對Pods之間如何進行組網通信提出了要求,k8s對集羣的網絡有以下要求:

  • 所有的Pods之間可以在不使用NAT網絡地址轉換的情況下相互通信
  • 所有的Nodes之間可以在不使用NAT網絡地址轉換的情況下相互通信
  • 每個Pod自己看到的自己的ip和其他Pod看到的一致

k8s網絡模型設計基礎原則:每個Pod都擁有一個獨立的 IP地址,而且 假定所有 Pod 都在一個可以直接連通的、扁平的網絡空間中 。 所以不管它們是否運行在同 一 個 Node (宿主機)中,都要求它們可以直接通過對方的 IP 進行訪問。設計這個原則的原因 是,用戶不需要額外考慮如何建立 Pod 之間的連接,也不需要考慮將容器端口映射到主機端口等問題。

由於 Kubemetes 的網絡模型假設 Pod 之間訪問時使用的是對方 Pod 的實際地址,所以一個
Pod 內部的應用程序看到的自己的 IP 地址和端口與集羣內其他 Pod 看到的一樣。它們都是 Pod 實際分配的IP地址 (從dockerO上分配的)。將IP地址和端口在Pod內部和外部都保持一致, 我們可以不使用 NAT 來進行轉換,地址空間也自然是平的。

鑑於上面這些要求,我們需要解決四個不同的網絡問題::

  • Docker容器和Docker容器之間的網絡
  • Pod與Pod之間的網絡
  • Pod與Service之間的網絡
  • Internet與Service之間的網絡

下面我們一一進行討論每種網絡問題,以及如何解決。

二、容器和容器之間的網絡

image.png

  • 在k8s中每個Pod中管理着一組Docker容器,這些Docker容器共享同一個網絡命名空間。
  • Pod中的每個Docker容器擁有與Pod相同的IP和port地址空間,並且由於他們在同一個網絡命名空間,他們之間可以通過localhost相互訪問。
    什麼機制讓同一個Pod內的多個docker容器相互通信那?其實是使用Docker的一種網絡模型:–net=container

container模式指定新創建的Docker容器和已經存在的一個容器共享一個網絡命名空間,而不是和宿主機共享。新創建的Docker容器不會創建自己的網卡,配置自己的 IP,而是和一個指定的容器共享 IP、端口範圍等

每個Pod容器有有一個pause容器其有獨立的網絡命名空間,在Pod內啓動Docker容器時候使用 –net=container就可以讓當前Docker容器加入到Pod容器擁有的網絡命名空間(pause容器)

image.png

三、Pod與Pod之間的網絡

image.png

  • k8s中,每個Pod擁有一個ip地址,不同的Pod之間可以直接使用改ip與彼此進行通訊
  • 在同一個Node上,從Pod的視角看,它存在於自己的網絡命名空間中,並且需要與該Node上的其他網絡命名空間上的Pod進行通信。

那麼是如何做到的?這多虧了使用linux虛擬以太網設備或者說是由兩個虛擬接口組成的veth對使不同的網絡命名空間鏈接起來,這些虛擬接口分佈在多個網絡命名空間上(這裏是指多個Pod上)。

爲了讓多個Pod的網絡命名空間鏈接起來,我們可以讓veth對的一端鏈接到root網絡命名空間(宿主機的),另一端鏈接到Pod的網絡命名空間。

每對Veth就像一根接插電纜,連接兩側並允許流量在它們之間流動;這種veth對可以推廣到同一個Node上任意多的Pod上,如上圖這裏展示使用veth對鏈接每個Pod到虛擬機的root網絡命名空間。

下面我們看如何使用網橋設備來讓通過veth對鏈接到root命名空間的多個Pod進行通信。

linux以太網橋(Linux Ethernet bridge)是一個虛擬的2層網絡設備,目的是把多個以太網段鏈接起來,網橋維護了一個轉發表,通過檢查轉發表通過它傳輸的數據包的目的地並決定是否將數據包傳遞到連接到網橋的其他網段,網橋代碼通過查看網絡中每個以太網設備特有的MAC地址來決定是傳輸數據還是丟棄數據。

image.png

網橋實現了ARP協議用來根據給定的ip地址找到對應機器的數據鏈路層的mac地址,一開始轉發表爲空,當一個數據幀被網橋接受後,網橋會廣播該幀到所有的鏈接設備(除了發送方設備),並且把響應這個廣播的設備記錄到轉發表;隨後發往相同ip地址的流量會直接從轉發表查找正確的mac地址,然後轉發包到對應的設備。

image.png

如上圖顯示了兩個Pod通過veth對鏈接到root網絡命名空間,並且通過網橋進行通信

3.1 同一個Node中的Pod之間的一次通信

鑑於每個Pod有自己獨立的網絡命名空間,我們使用虛擬以太網設備把多個Pod的命名空間鏈接到了root命名空間,並且使用網橋讓多個Pod之間進行通信,下面我們看如何在兩個pod之間進行通信:

image.png

  • 通過網橋這裏把veth0和veth1組成爲一個以太網,他們直接是可以直接通信的,另外這裏通過veth對讓pod1的eth0和veth0、pod2的eth0和veth1關聯起來,從而讓pod1和pod2相互通信。
  • Pod 1通過自己默認的以太網設備eth0發送一個數據包,eth0把數據傳遞給veth0,數據包到達網橋後,網橋通過轉發表把數據傳遞給veth1,然後虛擬設備veth1直接把包傳遞給Pod2網絡命名空間中的虛擬設備eth0.

3.2 不同Node中的Pod之間通信

k8s網絡模型需要每個pod必須通過ip地址可以進行訪問,每個pod的ip地址總是對網絡中的其他pod可見,並且每個pod看待自己的ip與別的pod看待的是一樣的(雖然他沒規定如何實現),下面我們看不同Node間Pod如何交互

k8s中每個集羣中的每個Node都會被分配了一個CIDR塊(無類別域間路由選擇,把網絡前綴都相同的連續地址組成的地址組稱爲CIDR地址塊)用來給該Node上的Pod分配IP地址。(保證pod的ip不會衝突)
另外還需要把pod的ip與所在的nodeip關聯起來()

 

image

  • 如上圖Node1(vm1)上的Pod1與Node2(vm2)上Pod4之間進行交互。
  • 首先pod1通過自己的以太網設備eth0把數據包發送到關聯到root命名空間的veth0上,然後數據包被Node1上的網橋設備cbr0接受到,網橋查找轉發表發現找不到pod4的Mac地址,則會把包轉發到默認路由(root命名空間的eth0設備),然後數據包經過eth0就離開了Node1,被髮送到網絡。
  • 數據包到達Node2後,首先會被root命名空間的eth0設備,然後通過網橋cbr0把數據路由到虛擬設備veth1,最終數據表會被流轉到與veth1配對的另外一端(pod4的eth0)

每個Node都知道如何把數據包轉發到其內部運行的Pod,當一個數據包到達Node後,其內部數據流就和Node內Pod之間的流轉類似了。

對於如何來配置網絡,k8s在網絡這塊自身並沒有實現網絡規劃的具體邏輯,而是制定了一套CNI(Container Network Interface)接口規範,開放給社區來實現。

例如AWS,亞馬遜爲k8s維護了一個容器網絡插件,使用CNI插件來讓亞馬遜VPC(虛擬私有云)環境中的Node與Node直接進行交互.

CoreOS的Flannel是k8s中實現CNI規範較爲出名的一種實現。

3.2.1 VXLAN

  • UDP幀格式

     

    image.png

  • vlan

     

    image.png

image.png

  • vxlan協議格式
    VXLAN 全稱是 Virtual eXtensible Local Area Network,虛擬可擴展的局域網。它是一種 overlay 技術,通過三層的網絡來搭建虛擬的二層網絡,其幀格式:

     

    image.png

從這個報文中可以看到三個部分:
1.最外層的 UDP 協議報文用來在底層網絡上傳輸,也就是 vtep 之間互相通信的基礎
2.中間是 VXLAN 頭部,vtep 接受到報文之後,去除前面的 UDP 協議部分,根據這部分來處理 vxlan 的邏輯,主要是根據 VNI 發送到最終的虛擬機
3.最裏面是原始的報文,也就是虛擬機看到的報文內容

 

image.png

  • VTEP(VXLAN Tunnel Endpoints):vxlan 網絡的邊緣設備,用來進行 vxlan 報文的處理(封包和解包)。vtep 可以是網絡設備(比如交換機),也可以是一臺機器(比如虛擬化集羣中的宿主機)

  • VNI(VXLAN Network Identifier):VNI 是每個 vxlan 的標識,是個 24 位整數,一共有 2^24 = 16,777,216(一千多萬),一般每個 VNI 對應一個租戶,也就是說使用 vxlan 搭建的公有云可以理論上可以支撐千萬級別的租戶

  • Tunnel:隧道是一個邏輯上的概念,在 vxlan 模型中並沒有具體的物理實體想對應。隧道可以看做是一種虛擬通道,vxlan 通信雙方(圖中的虛擬機)認爲自己是在直接通信,並不知道底層網絡的存在。從整體來說,每個 vxlan 網絡像是爲通信的虛擬機搭建了一個單獨的通信通道,也就是隧道

3.2.1 Flannel

Flannel是CoreOS團隊針對Kubernetes設計的一個網絡規劃實現,簡單來說,它的功能有以下幾點:

  • 使集羣中的不同Node主機創建的Docker容器都具有全集羣唯一的虛擬IP地址。

  • 建立一個覆蓋網絡(overlay network),通過這個覆蓋網絡,將數據包原封不動的傳遞到目標容器。覆蓋網絡是建立在另一個網絡之上並由其基礎設施支持的虛擬網絡。覆蓋網絡通過將一個分組封裝在另一個分組內來將網絡服務與底層基礎設施分離。在將封裝的數據包轉發到端點後,將其解封裝。

  • 創建一個新的虛擬網卡flannel0接收docker網橋的數據,通過維護路由表,對接收到的數據進行封包和轉發(vxlan)。

  • 路由信息一般存放到etcd:多個node上的Flanneld依賴一個etcd cluster來做集中配置服務,etcd保證了所有node上flanned所看到的配置是一致的。同時每個node上的flanned監聽etcd上的數據變化,實時感知集羣中node的變化

  • Flannel首先會在Node上創建一個名爲flannel0的網橋(vxlan類型的設備),並且在每個Node上運行一個名爲flanneld的代理.每個node上的flannel代理會從etcd上爲當前node申請一個CIDR地址塊用來給該node上的pod分配地址。

  • Flannel致力於給k8s集羣中的nodes提供一個3層網絡,他並不控制node中的容器是如何進行組網的,僅僅關心流量如何在node之間流轉

    image.png

     

  • 如上圖ip爲10.1.15.2的pod1與另外一個Node上的10.1.20.3的pod2進行通信。

  • 首先pod1通過veth對把數據包發送到docker0虛擬網橋,網橋通過查找轉發表發現10.1.20.3不在自己管理的網段,就會把數據包
    轉發給默認路由(這裏爲flannel0網橋)

  • flannel.0網橋是一個vxlan設備,flannel.0收到數據包後,由於自己不是目的地10.1.20.3,也要嘗試將數據包重新發送出去。數據包沿着網絡協議棧向下流動,在二層時需要封二層以太包,填寫目的mac地址,這時一般應該發出arp:”who is 10.1.20.3″。但vxlan設備的特殊性就在於它並沒有真正在二層發出這個arp包,而是由linux kernel引發一個”L3 MISS”事件並將arp請求發到用戶空間的flanned程序。

  • flanned程序收到”L3 MISS”內核事件以及arp請求(who is 10.1.20.3)後,並不會向外網發送arp request,而是嘗試從etcd查找該地址匹配的子網的vtep信息,也就是會找到node2上的flanel.0的mac地址信息,flanned將查詢到的信息放入node1 host的arp cache表中,flanneel0完成這項工作後,linux kernel就可以在arp table中找到 10.1.20.3對應的mac地址並封裝二層以太包了:

image.png

  • 由於是Vlanx設備,flannel0還會對上面的包進行二次封裝,封裝新的以太網mac幀:

     

    image.png

  • node上2的eth0接收到上述vxlan包,kernel將識別出這是一個vxlan包,於是拆包後將packet轉給node上2的flannel.0。flannel.0再將這個數據包轉到docker0,繼而由docker0傳輸到Pod2的某個容器裏。

如上圖,總的來說就是建立VXLAN 隧道,通過UDP把IP封裝一層直接送到對應的節點,實現了一個大的 VLAN。

4.Pod與Service之間的網絡

上面展示了Pod之間如何通過他們自己的ip地址進行通信,但是pod的ip地址是不持久的,當集羣中pod的規模縮減或者pod故障或者node故障重啓後,新的pod的ip就可能與之前的不一樣的。所以k8s中衍生出來Service來解決這個問題。

k8s中 Service管理了一系列的Pods,每個Service有一個虛擬的ip,要訪問service管理的Pod上的服務只需要訪問你這個虛擬ip就可以了,這個虛擬ip是固定的,當service下的pod規模改變、故障重啓、node重啓時候,對使用service的用戶來說是無感知的,因爲他們使用的service的ip沒有變。

當數據包到達Service虛擬ip後,數據包會被通過k8s給該servcie自動創建的負載均衡器路由到背後的pod容器。下面我們看看具體是如何做到的

4.1 netfilter

爲了實現負載均衡,k8s依賴linux內建的網絡框架-netfilter。Netfilter是Linux提供的內核態框架,允許使用者自定義處理接口實現各種與網絡相關的操作。 Netfilter爲包過濾,網絡地址轉換和端口轉換提供各種功能和操作,以及提供禁止數據包到達計算機網絡內敏感位置的功能。在linux內核協議棧中,有5個跟netfilter有關的鉤子函數,數據包經過每個鉤子時,都會檢查上面是否註冊有函數,如果有的話,就會調用相應的函數處理該數據包

 

         |
         | Incoming
         ↓
+-------------------+
| NF_IP_PRE_ROUTING |
+-------------------+
         |
         |
         ↓
+------------------+
|                  |         +----------------+
| routing decision |-------->| NF_IP_LOCAL_IN |
|                  |         +----------------+
+------------------+                 |
         |                           |
         |                           ↓
         |                  +-----------------+
         |                  | local processes |
         |                  +-----------------+
         |                           |
         |                           |
         ↓                           ↓
 +---------------+          +-----------------+
 | NF_IP_FORWARD |          | NF_IP_LOCAL_OUT |
 +---------------+          +-----------------+
         |                           |
         |                           |
         ↓                           |
+------------------+                 |
|                  |                 |
| routing decision |<----------------+
|                  |
+------------------+
         |
         |
         ↓
+--------------------+
| NF_IP_POST_ROUTING |
+--------------------+
         |
         | Outgoing
         ↓
  • NF_IP_PRE_ROUTING: 接收的數據包剛進來,還沒有經過路由選擇,即還不知道數據包是要發給本機還是其它機器。

  • NF_IP_LOCAL_IN: 已經經過路由選擇,並且該數據包的目的IP是本機,進入本地數據包處理流程。

  • NF_IP_FORWARD: 已經經過路由選擇,但該數據包的目的IP不是本機,而是其它機器,進入forward流程。

  • NF_IP_LOCAL_OUT: 本地程序要發出去的數據包剛到IP層,還沒進行路由選擇。

  • NF_IP_POST_ROUTING: 本地程序發出去的數據包,或者轉發(forward)的數據包已經經過了路由選擇,即將交由下層發送出去。

netfilter是工作在那一層?

4.2 iptables

iptables是運行在用戶態的用戶程序,其基於表來管理規則,用於定義使用netfilter框架操作和轉換數據包的規則。根據rule的作用分成了好幾個表,比如用來過濾數據包的rule就會放到filter表中,用於處理地址轉換的rule就會放到nat表中,其中rule就是應用在netfilter鉤子上的函數,用來修改數據包的內容或過濾數據包。目前iptables支持的表有下面這些:

  • Filter:從名字就可以看出,這個表裏面的rule主要用來過濾數據,用來控制讓哪些數據可以通過,哪些數據不能通過,它是最常用的表。

  • NAT(*):裏面的rule都是用來處理網絡地址轉換的,控制要不要進行地址轉換,以及怎樣修改源地址或目的地址,從而影響數據包的路由,達到連通的目的,這是家用路由器必備的功能。

  • Mangle:裏面的rule主要用來修改IP數據包頭,比如修改TTL值,同時也用於給數據包添加一些標記,從而便於後續其它模塊對數據包進行處理(這裏的添加標記是指往內核skb結構中添加標記,而不是往真正的IP數據包上加東西)。

  • Raw:在netfilter裏面有一個叫做connection tracking的功能,主要用來追蹤所有的連接,而raw表裏的rule的功能是給數據包打標記,從而控制哪些數據包不被connection tracking所追蹤。

  • Security:裏面的rule跟SELinux有關,主要是在數據包上設置一些SELinux的標記,便於跟SELinux相關的模塊來處理該數據包。

在k8s中,iptables規則由kube-proxy控制器配置,該控制器監視K8s API服務器的更改。當對Service或Pod的虛擬IP地址進行修改時,iptables規則也會更新以便讓service能夠正確的把數據包路由到後端Pod。

iptables規則監視發往Service虛擬IP的流量,並且在匹配時,從可用Pod集合中選擇隨機Pod IP地址,iptables規則將數據包的目標IP地址從Service的虛擬IP更改爲選定的Pod的ip。總的來說iptables已在機器上完成負載平衡,並將指向Servcie的虛擬IP的流量轉移到實際的pod的IP。

在從service到pod的路徑上,IP地址來自目標Pod。 在這種情況下,iptables再次重寫IP頭以將Pod IP替換爲Service的IP,以便Pod認爲它一直與Service的虛擬IP通信。

4.3 IPVS

k8s的最新版本(1.11)包括了用於集羣內負載平衡的第二個選項:IPVS。 IPVS(IP Virtual Server)也構建在netfilter之上,並實現傳輸層負載平衡(屬於Linux內核的一部分)。 IPVS包含在LVS(Linux虛擬服務器)中,它在主機上運行,並在真實服務器集羣前充當負載均衡器。 IPVS可以將對基於TCP和UDP的服務的請求定向到真實服務器,並使真實服務器的服務在單個IP地址上顯示爲虛擬服務。這使得IPVS非常適合Kubernetes服務。

聲明Kubernetes服務時,您可以指定是否要使用iptables或IPVS完成羣集內負載平衡。 IPVS專門用於負載平衡,並使用更高效的數據結構(哈希表),與iptables相比,允許幾乎無限的規模。在創建IPVS負載時,會發生以下事情:在Node上創建虛擬IPVS接口,將Service的IP地址綁定到虛擬IPVS接口,併爲每個Service額IP地址創建IPVS服務器。將來,期望IPVS成爲集羣內負載平衡的默認方法。

4.4 Pod到Service的一個包的流轉

image

  • 如上圖當從一個Pod發送數據包到Service時候,數據包先從Pod1所在的虛擬設備eth0離開pod1,並通過veth對的另外一端veth0傳遞給網橋cbr0,網橋找不到service對應ip的mac地址,所以把包轉發給默認路由,也就是root命名空間的eth0

  • 在root命名空間的設備eth0接受到數據包前,數據包會經過iptables進行過濾,iptables接受數據包後會使用kube-proxy在Node上安裝的規則來響應Service或Pod的事件,將數據包的目的地址從Service的IP重寫爲Service後端特定的Pod IP(本例子中是pod4).

  • 現在數據包的目的ip就不再是service的ip地址了,而是pod4的ip地址。

  • iptables利用Linux內核的conntrack來記住所做的Pod選擇,以便將來的流量路由到同一個Pod(禁止任何擴展事件)。 從本質上講,iptables直接在Node上進行了集羣內負載均衡,然後流量使用我們已經檢查過的Pod-to-Pod路由流到Pod。

4.5 Service到Pod的一個包的流轉

image

  • 收到此數據包的Pod將會回發包到源Pod,回包的源IP識別爲自己的IP(比如這裏爲Pod4的ip),將目標IP設置爲最初發送數據包的Pod(這裏爲pod1的ip)。
  • 數據包進入目標Pod(這裏爲Pod1)所在節點後,數據包流經iptables,它使用conntrack記住它之前做出的選擇,並將數據包的源IP重寫爲Service的IP。 從這裏開始,數據包通過網橋流向與Pod1的命名空間配對的虛擬以太網設備,並流向我們之前看到的Pod1的以太網設備。

5.Internet與Service之間的網絡

到目前爲止,我們已經瞭解瞭如何在Kubernetes集羣中路由流量。下面我們希望將服務暴露給外部使用(互聯網)。 這需要強調兩個相關的問題:(1)從k8s的service訪問Internet,以及(2)從Internet訪問k8s的service.

5.1 k8s流量到Internet

從Node到公共Internet的路由流量是特定於網絡的,實際上取決於網絡配置。爲了使本節更具體,下面使用AWS VPC討論具體細節。

在AWS中,k8s集羣在VPC內運行,其中每個Node都分配了一個可從k8s集羣內訪問的私有IP地址。要使羣集外部的流量可訪問,需要將Internet網關連接到VPC。 Internet網關有兩個目的:在VPC路由表中提供可以路由到Internet的流量的目標,以及爲已分配公共IP地址的任何實例執行網絡地址轉換(NAT)。 NAT轉換負責將羣集專用的節點內部IP地址更改爲公共Internet中可用的外部IP地址。

通過Internet網關,Node可以將流量路由到Internet。不幸的是,有一個小問題。 Pod具有自己的IP地址,該IP地址與承載Pod的Node的IP地址不同,並且Internet網關上的NAT轉換僅適用於Node的 IP地址,因爲它不知道Node上正在運行那些Pod - Internet網關不是容器感知的。讓我們再次看看k8s如何使用iptables解決這個問題。

本質都是使用NAT來做

5.1.1 Node到Internet

image

  • 如上圖中,數據包源自Pod1的網絡命名空間,並通過veth對連接到root命名空間。
  • 一旦root命名空間,數據包就會從網橋cbr0流傳到到默認設備eth0,因爲數據包上的目的IP與連接到網橋的任何網段都不匹配,在到達root命名空間的以太網設備eth0之前,iptables會修改數據包。
  • 在這種情況下,數據包的源IP地址是Pod1的ip地址,如果我們將源保持爲Pod1,則Internet網關將拒絕它,因爲網關NAT僅瞭解連接到vm的IP地址。解決方案是讓iptables執行源NAT - 更改數據包源 - 以便數據包看起來來自VM而不是Pod。
  • 有了正確的源IP,數據包現在可以離開VM,併到達Internet網關。 Internet網關將執行另一個NAT,將源IP從VM內部IP重寫爲Internet IP。最後,數據包將到達公共互聯網。在回來數據包的路上,數據包遵循相同的路徑,任何源IP都會與發送時候做相同的修改操作,以便系統的每一層都接收它理解的IP地址:Node,以及Pod命名空間中中的Pod IP。

5.2 Internet到k8s

image.png

讓Internet流量進入k8s集羣,這特定於配置的網絡,可以在網絡堆棧的不同層來實現:

  • (1) NodePort
  • (2)Service LoadBalancer
  • (3)Ingress控制器。

5.2.1 第四層流量入口:NodePort

讓外網訪問k8s內部的服務的第一個方法是創建一個NodePort類型的Service,
對於NodePort類型的Service,k8s集羣中的每個Node都會打開一個端口(所有Node上的端口相同),並將該端口上收到的流量重定向到具體的Service。

對於NodePort類型的Service,我們可以通過任何Node的ip和端口號來訪問NodePort服務。

創建NodePort類型的服務:

 

image.png

如下圖,服務暴露在兩個節點的端口30123上,到達任何一個端口的鏈接會被重定向到一個隨機選擇的Pod。

 

image.png

如何做到的?

NodePort是靠kube-proxy服務通過iptables的nat轉換功能實現的,kube-proxy會在運行過程中動態創建與Service相關的iptables規則,這些規則實現了NodePort的請求流量重定向到kube-proxy進程上對應的Service的代理端口上。

kube-proxy接受到Service的請求訪問後,會從service對應的後端Pod中選擇一個進行訪問(RR)

但 NodePort 還沒有完全解決外部訪問 Service 的所有問題,比如負載均衡問題,假如我們 的集羣中有 10 個 Node,則此時最好有一個負載均衡器,外部的請求只需訪問此負載均衡器的 IP 地址,由負載均衡器負 責轉發流量到後面某個 Node 的 NodePort 上

5.2.2 第四層流量入口:LoadBalancer

該方式是NodePort方式的擴展,這使得Service可以通過一個專用的負載均衡器來訪問,這個是由具體雲服務提供商來提供的,負載均衡器將流量重定向到所有節點的端口上,如果雲提供商不支持負載均衡,則退化爲NodePort類型

創建k8s service時,可以選擇指定LoadBalancer。 LoadBalancer的實現由雲控制器提供,該控制器知道如何爲您的service創建負載均衡器。 創建service後,它將公佈負載均衡器的IP地址。 作爲最終用戶,可以開始將流量定向到負載均衡器以開始與提供的service進行通信。

創建一個負載均衡服務:

 

image.png

藉助AWS,負載均衡器可以識別其目標組中的Node,並將平衡羣集中所有節點的流量。 一旦流量到達Node,之前在整個羣集中爲Service安裝的iptables規則將確保流量到達感興趣的Service的Pod上。

下面看下LoadBalancer到Service的一個數據包的流轉過程:

 

image

  • 我們來看看LoadBalancer在實踐中是如何運作的。部署Service後,正在使用的雲提供商將會創建一個新的負載均衡器(1)。

  • 由於負載均衡器不能識別容器,因此一旦流量到達負載均衡器,它就會把數據包發送到在構成羣集的某個Node中(2)。每個Node上的iptables規則將來自負載均衡器的傳入流量重定向到正確的Pod(3)

  • 這些iptables規則是在service創建時候創建。從Pod到請求方的響應將返回Pod的IP,但請求方需要具有負載均衡器的IP地址。這就需要iptables和conntrack用於在返回路徑上正確地重寫IP。

上圖顯示了承載Pod的三個Node前面的網絡負載平衡器。首先流量被傳到的Service的負載均衡器(1)。一旦負載均衡器收到數據包(2),它就會隨機選擇一個VM。這裏我們故意選擇了沒有Pod運行的node:node 2。在這裏,node上運行的iptables規則將使用kube-proxy安裝在集羣中的內部負載平衡規則將數據包定向到正確的Node 中的Pod。 iptables執行正確的NAT並將數據包轉發到正確的Pod(4)。

需要注意的是每個服務需要創建自己獨有的負載均衡器,下面要講解的一種方式所有服務只需要一個公開服務。

5.2.3 第七層流量入口:Ingress Controller

這是一個與上面提到的兩種方式完全不同的機制,通過一個公開的ip地址來公開多個服務,第7層網絡流量入口是在網絡堆棧的HTTP / HTTPS協議範圍內運行,並建立在service之上。

 

image.png

 

如上圖,不像負載均衡器每個服務需要一個公開ip,ingress所有服務只需要一個公網ip,當客戶端向Ingress發送http請求時候,ingress會根據請求的主機名和路徑決定請求轉發到那個服務。

創建Ingress資源:

 

image.png

 

如上定義了一個單一規則的Ingress,確保Ingress控制器接受的所有請求主機kubia.example.com的http請求被髮送到端口80上的kubia-nodeport服務上。

工作原理:
如下圖,客戶端首先對kubia.example.com執行DNS查找,DNS服務器返回Ingress控制器的IP,客戶端拿到IP後,向Ingress控制器發送Http請求,並在Host投中指定kubia.example.com。控制器接受到請求後從Host頭部就知道該訪問那個服務,通過與該Service關聯的endpoint對象查詢Pod ip,並將請求轉發到某一個Pod。

這裏Ingress並沒把請求轉發給Service,而是自己選擇一個一個Pod來訪問。

 

image.png

第7層負載均衡器的一個好處是它們具有HTTP感知能力,因此它們瞭解URL和路徑。 這允許您按URL路徑細分服務流量。 它們通常還在HTTP請求的X-Forwarded-For標頭中提供原始客戶端的IP地址。

本文參考了大量資料,並結合作者的理解,如有不對,歡迎討論^^

參考

 

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