1. 程式人生 > >Kubernetes 核心原理 之二

Kubernetes 核心原理 之二

kubernetes 網路模型

kubernetes網路模型設計的一個基礎原則是:每個Pod都擁有一個獨立的IP地址,而且假定所有Pod都在一個可以直接連通的、扁平網路空間中。所以不管他們是否執行在同一個Node(宿主機)中,都要求他們可以直接通過對方IP進行訪問。

kubernetes的網路模型假設Pod之間訪問時使用的是對方的Pod的實際地址,所以一個Pod內部的應用程式看到的自己的IP地址和埠號與叢集內部內其他Pod看到的是一樣,他們都是Pod實際分配的地址(從docker0分配的)。一個Pod一個IP的模型還有另外一層含義,那就是同一個Pod內的容器會共享一個網路名稱空間,也就是同一個網路協議棧,這意味著同一個Pod裡面的容器可以通過localhost來連線對方的埠。

IP-per-Pod模型是一個簡單的相容性好的模型。從該模型網路的埠分配、域名解析、服務發現、負載均衡、應用配置和遷移到呢個角度來看、Pod都能被當作一臺獨立的”虛擬機器”或物理機。
kubernetes對叢集的網路有如下要求:

  1. 所有的容器都可以在不用NAT的方式下同別的容器通訊;
  2. 所有容器節點都可以在不用NAT的方式下同所有容器通訊;
  3. 容器的地址和別人看到的地址是同一個地址

Docker的網路基礎

kubernetes的網路依賴於Docker,Docker的網路又離不開Linux作業系統核心特性的支援。
Docker使用到的與Linux網路有關的主要技術主要包含如下幾種:

網路名稱空間

通過對網路資源的隔離,就能在一個宿主機上虛擬多個不同的網路環境。讓處於不同名稱空間的網路進行通訊,Veth裝置對的一個重要作用就是開啟互相看不到的協議棧之間的壁壘。

Veth 裝置對

引入veth裝置對是為了在不同的網路名稱空間之間進行通訊,利用它可以直接將兩個網路名稱空間連線起來,Veth裝置都是成對出現的,很像一對乙太網卡,並且中間有一條直連的網線。

網橋

網橋是一個二層網路裝置,可以解析收發的報文,讀取目標MAC的地址資訊,和自己的MAC地址結合,來決策報文的轉發埠。
Linux核心通過一個虛擬的網橋裝置來實現橋接的,這個虛擬裝置可以繫結若干乙太網介面裝置,從而將他們橋接起來。

docker自動完成了對網橋的建立和維護,常用的操作:
* brctl addr xxx ; 增加一個網橋
* 網橋的物理網絡卡作為一個埠,由於在鏈路層工作,就不需要IP地址了,這樣上面的IP地址

Iptables/Netfilter

在Linux網路協議棧中有一組回撥函式掛載點,通過這些掛載點掛接的鉤子函式可以在Linux網路棧處理資料包的過程中對資料包進行一些操作,如過濾、修改、丟棄等,整個掛接點技術叫Netfilter和Iptables。

這些掛載點掛接的規則也分不同的型別(也就是規則表),目前支援的Table型別為:RAW,MANGLE,NAT,FILTER;當Linux協議棧的資料處理執行到掛載點時,會依次呼叫掛接點上的所有掛接函式,直到資料包的處理結果是明確地接受或者拒絕。

路由

路由功能由IP層維護的一張路由表來實現,路由表中的資料一般以條目形式存在,主要有: 目的IP地址、下一個路由器的IP地址、標誌、網路介面規範、

Linux路由表至少要包括兩個表,一個是LOCAL,另一個是MAIN,在LOCAL表中會包含所有的本地裝置地址,它是在配置網路設配時自動建立的。LOCAL表用於
供Linux協議棧識別本地地址,以及進行本地各個不同網路介面之間資料的轉發。MAIN表用於各類網路地址的轉發,它的建立既可以使用靜態配置完成,也可以使用動態路由協議完成。動態路由發現協議一般用組播功能來通過傳送路由發現數據,動態的交換和獲取網路的路由資訊,並更新到路由表中。

Docker的網路實現

Docker 支援四種模式:

  • host模式
  • container 模式
  • none模式
  • bridge模式

kubernetes的網路實現

kubernetes的網路設計主要致力於解決以下場景:
* 容器到容器之間的通訊
* 抽象的Pod到Pod之間的通訊
* Pod到Service之間的通訊
* 叢集外部與內部元件之間的通訊

容器到容器之間的通訊

在同一個Pod內的容器(pod內的容器是不會跨越主機的)共享同一個網路名稱空間,共享同一個Linux協議棧。

Pod之間的通訊

同一個Node內的Pod之間的通訊

每一個Pod都有一個真實的全域性IP地址,同一個Node內的不同Pod之間可以直接採用對方Pod的IP地址通訊,而且不需要使用使用其他發現機制。


Pod1和Pod2是通過Veth連線在docker0網橋上的,它們的IP地址IP1,IP2都是從docker0的網段上動態獲取的,他們和網橋本身的IP3是同一個網段的。
在Pod1、Pod2的Linux協議棧上,預設路由都是docker0的地址,也就是所有非本地地址的網路資料,都會預設傳送到docker0網橋,由docker0網橋直接中轉。

不同Node上的Pod之間進行通訊

docker0網橋與宿主機網絡卡是兩個完全不同的IP網段,並且Node之間的通訊只能通過宿主機的物理網絡卡進行,因此要想實現位於不同Node上的Pod容器之間的通訊,就必須想辦法通過主機的IP地址進行定址和通訊。

另一方方面,這些動態分配並且隱藏在docker0之後的所謂”私有IP地址”也是可以找到的。Kubernetes會記錄所有正在執行的Pod的IP分配資訊,並且將這些資訊儲存在etcd中(作為service的Endpoint),這些私有IP對Pod到Pod之間的通訊是非常重要的。

綜上,要想支援不同的Node上的Pod之間的通訊,就要達到兩個條件:
1. 在整個kubernetes叢集中對Pod的IP進行規劃,不能有衝突
2. 找到一種方法,將Pod的IP和所在Node關聯起來,通過這個關聯讓Pod可以相互訪問。

根據1在部署kubernetes的時候,對docker0的IP地址進行規劃,保證每一個Node上的docker0地址沒有衝突。我們可以在規劃後手工配置到每個Node上,或者做一個分配規則,有安裝的程式自己去分配佔用,kubernetes的網路增強軟體Flannel就能夠管理資源的分配。

根據2的要求,Pod中的資料在發出時,需要有一個機制能夠知道對方那個Pod的IP地址掛在那個具體的Node上,也就是說先要找到Node對應宿主機的IP地址,將資料傳送到這個宿主機的網絡卡上,然後在宿主機上將相應的資料傳送到具體的docker0上。一旦資料到達宿主機Node,則那個Node內部的docker0便知道如何將資料傳送到pod。

跨Node的Pod通訊模型如下:

開源的網路元件

Flannel

Flannel能實現以下兩點:
* 它能協助kubernetes,給每個Node上的Docker容器分配不衝突的IP地址。
* 它能在這些IP之間建立一個覆蓋網路(Overlay Network),通過這個覆蓋網路,將資料包原封不動的傳遞到目標容器內。


flannel首先建立一個名為flannel0的網橋,並且這個網橋的一端連線docker0網橋,另外一端連線一個叫做flanneld的服務程序。

flanneld程序首先連上etcd,利用etcd來管理可分配的IP地址段資源,同時監控etcd裡面每個Pod的實際地址,並在記憶體中建立了一個Pod節點路由表,然後下連docker0和物理網路,並適用記憶體中的Pod節點路由表,將docker0傳送給它的資料包包裝起來,利用物理網路的連線將資料包投遞到目標flanneld上,從而完成了Pod到Pod之間的直接的地址通訊。

直接路由

docker0網橋上的IP地址在Node上是看不見的,從一個Node到另外一個Node內的docker0是不通的。
我們可以通過部署MulitiLayer Switch(MLS)來實現這一點,在MSL中配置每個Docker0子網到Node地址的路由選項,通過MLS將docker0的IP定址定向到對應的Node上。