7個步驟,教你搞懂 K8S 網絡之 Flannel 工作原理

雲棲號資訊:【點擊查看更多行業資訊
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!

image

一、Docker 網絡模式

在討論 Kubernetes 網絡之前,讓我們先來看一下 Docker 網絡。Docker 採用插件化的網絡模式,默認提供 bridge、host、none、overlay、maclan 和 Network plugins 這幾種網絡模式,運行容器時可以通過–network 參數設置具體使用那一種模式。

  • bridge:這是Docker默認的網絡驅動,此模式會爲每一個容器分配Network Namespace和設置IP等,並將容器連接到一個虛擬網橋上。如果未指定網絡驅動,這默認使用此驅動。
  • host:此網絡驅動直接使用宿主機的網絡。
  • none:此驅動不構造網絡環境。採用了none 網絡驅動,那麼就只能使用loopback網絡設備,容器只能使用127.0.0.1的本機網絡。
  • overlay:此網絡驅動可以使多個Docker daemons連接在一起,並能夠使用swarm服務之間進行通訊。也可以使用overlay網絡進行swarm服務和容器之間、容器之間進行通訊,
  • macvlan:此網絡允許爲容器指定一個MAC地址,允許容器作爲網絡中的物理設備,這樣Docker daemon就可以通過MAC地址進行訪問的路由。對於希望直接連接網絡網絡的遺留應用,這種網絡驅動有時可能是最好的選擇。
  • Network plugins:可以安裝和使用第三方的網絡插件。可以在Docker Store或第三方供應商處獲取這些插件。

在默認情況,Docker 使用 bridge 網絡模式,bridge 網絡驅動的示意圖如下,此文以bridge 模式對 Docker 的網絡進行說明。

image

1.1 bridge網絡的構建過程

1)安裝Docker時,創建一個名爲 docke0 的虛擬網橋,虛擬網橋使用“10.0.0.0 -10.255.255.255 “、”172.16.0.0-172.31.255.255″和“192.168.0.0——192.168.255.255”這三個私有網絡的地址範圍。

通過 ifconfig 命令可以查看 docker0 網橋的信息:

image

通過 docker network inspect bridge 可以查看網橋的子網網絡範圍和網關:

image

2)運行容器時,在宿主機上創建虛擬網卡 veth pair 設備,veth pair 設備是成對出現的,從而組成一個數據通道,數據從一個設備進入,就會從另一個設備出來。

將veth pair設備的一端放在新創建的容器中,命名爲eth0;另一端放在宿主機的docker0中,以veth爲前綴的名字命名。通過 brctl show 命令查看放在docker0中的veth pair設備。

image

1.2 外部訪問

bridge 的 docker0 是虛擬出來的網橋,因此無法被外部的網絡訪問。因此需要在運行容器時通過 -p 和 -P 參數對將容器的端口映射到宿主機的端口。實際上 Docker 是採用 NAT的方式,將容器內部的服務監聽端口與宿主機的某一個端口 port 進行綁定,使得宿主機外部可以將網絡報文發送至容器。

1)通過-P參數,將容器的端口映射到宿主機的隨機端口:

$ docker run -P {images}

2)通過-p參數,將容器的端口映射到宿主機的制定端口:

$ docker run -p {hostPort}:{containerPort} {images}

二、Kubernetes 網絡模式

Kubernetes與Docker網絡有些不同。Kubernetes網絡需要解決下面的4個問題:

集羣內:

  • 容器與容器之間的通信
  • Pod和Pod之間的通信
  • Pod和服務之間的通信

集羣外:

  • 外部應用與服務之間的通信

因此,Kubernetes假設Pod之間能夠進行通訊,這些Pod可能部署在不同的宿主機上。每一個Pod都擁有自己的IP地址,因此能夠將Pod看作爲物理主機或者虛擬機,從而能實現端口設置、命名、服務發現、負載均衡、應用配置和遷移。爲了滿足上述需求,則需要通過集羣網絡來實現。

在本文主要分析容器與容器之間,以及Pod和Pod之間的通信;Pod和服務之間,以及外部應用與服務之間的通信請參考《Kubernetes-核心資源之Service》和《Kubernetes-核心資源之Ingress》。

2.1 同一個 Pod 中容器之間的通信

這種場景對於Kubernetes來說沒有任何問題,根據Kubernetes的架構設計。Kubernetes 創建 Pod 時,首先會創建一個 pause 容器,爲 Pod 指派一個唯一的IP地址。然後,以pause的網絡命名空間爲基礎,創建同一個Pod內的其它容器(–net=container:xxx)。

因此,同一個Pod內的所有容器就會共享同一個網絡命名空間,在同一個Pod之間的容器可以直接使用localhost進行通信。

2.2 不同 Pod 中容器之間的通信

對於此場景,情況現對比較複雜一些,這就需要解決 Pod 間的通信問題。在Kubernetes 通過 flannel、calic 等網絡插件解決 Pod 間的通信問題。本文以 flannel 爲例說明在 Kubernetes 中網絡模型,flannel 是 kubernetes 默認提供網絡插件。Flannel 是由 CoreOS 團隊開發社交的網絡工具,CoreOS 團隊採用 L3 Overlay 模式設計 flannel, 規定宿主機下各個Pod屬於同一個子網,不同宿主機下的Pod屬於不同的子網。

flannel會在每一個宿主機上運行名爲flanneld代理,其負責爲宿主機預先分配一個子網,併爲Pod分配IP地址。Flannel使用Kubernetes或etcd來存儲網絡配置、分配的子網和主機公共IP等信息。數據包則通過VXLAN、UDP或host-gw這些類型的後端機制進行轉發。

image

2.3 Flannel 在 K8S 中運行的整體過程

1)設置集羣網絡

flannel默認使用etcd作爲配置和協調中心,首先使用etcd設置集羣的整體網絡。通過如下的命令能夠查詢網絡配置信息:

$ etcdctl ls /coreos.com/network/config

2)設置 Node 節點上的子網

基於在 etcd 中設置的網絡,flannel 爲每一個 Node 分配 IP 子網。

獲取子網列表

$ etcdctl ls /coreos.com/network/subnets

獲取子網信息

$ etcdctl ls /coreos.com/network/subnets/{IP網段}

3)在每個 Node 上啓動 flanneld

flannel 在每個 Node 上啓動了一個 flanneld 的服務,在flanneld啓動後,將從etcd中讀取配置信息,並請求獲取子網的租約。

所有 Node 上的 flanneld 都依賴 etcd cluster 來做集中配置服務,etcd 保證了所有node 上 flanned 所看到的配置是一致的。同時每個 node 上的 flanned 監聽etcd上的數據變化,實時感知集羣中node的變化。flanneld一旦獲取子網租約、配置後端後,會將一些信息寫入/run/flannel/subnet.env文件。

$ cat /var/run/flannel/subnet.env

image

4)創建虛擬網卡

在Node節點上,會創建一個名爲flannel.1的虛擬網卡。

$ ip addr show flannel.1

image

5)創建Docker網橋

併爲容器配置名爲docker0的網橋,實際是通過修改Docker的啓動參數–bip來實現的。通過這種方式,爲每個節點的Docker0網橋設置在整個集羣範圍內唯一的網段,從保證創建出來的Pod的IP地址是唯一。

$ ip addr show docker0

image

6)修改路由表

flannel會對路由表進行修改,從而能夠實現容器跨主機的通信。

$ route -n

image

2.4 數據傳遞過程

在源容器宿主機中的數據傳遞過程:

1)源容器向目標容器發送數據,數據首先發送給 docker0 網橋

在源容器內容查看路由信息:

$ kubectl exec -it -p {Podid} -c {ContainerId} -- ip route

2)docker0 網橋接受到數據後,將其轉交給 flannel.1 虛擬網卡處理

docker0 收到數據包後,docker0的內核棧處理程序會讀取這個數據包的目標地址,根據目標地址將數據包發送給下一個路由節點:

查看源容器所在Node的路由信息:

$ ip route

3)flannel.1 接受到數據後,對數據進行封裝,併發給宿主機的 eth0

flannel.1收到數據後,flannelid會將數據包封裝成二層以太包。

Ethernet Header的信息:

  • From:{源容器flannel.1虛擬網卡的MAC地址}
  • To:{目錄容器flannel.1虛擬網卡的MAC地址}

4)對在flannel路由節點封裝後的數據,進行再封裝後,轉發給目標容器 Node 的 eth0

由於目前的數據包只是vxlan tunnel上的數據包,因此還不能在物理網絡上進行傳輸。因此,需要將上述數據包再次進行封裝,才能源容器節點傳輸到目標容器節點,這項工作在由linux內核來完成。

Ethernet Header 的信息:

  • From: {源容器 Node 節點網卡的 MAC 地址}
  • To: {目錄容器 Node 節點網卡的 MAC 地址}

IP Header的信息:

  • From:{源容器Node節點網卡的IP地址}
  • To:{目錄容器Node節點網卡的IP地址}

通過此次封裝,就可以通過物理網絡發送數據包。

在目標容器宿主機中的數據傳遞過程:

5)目標容器宿主機的eth0接收到數據後,對數據包進行拆封,並轉發給flannel.1虛擬網卡;

6)flannel.1 虛擬網卡接受到數據,將數據發送給docker0網橋;

7)最後,數據到達目標容器,完成容器之間的數據通信。

【雲棲號在線課堂】每天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/live

立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK

原文發佈時間:2020-06-24
本文作者: 高效運維
本文來自:“高效運維公衆號”,瞭解相關信息可以關注“高效運維

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