Kubernetes 網路原理

來源:互聯網
上載者:User

標籤:names   coreos   中斷連線   交換   刪除   抽象   位元   eth   啟用   

Docker網路基礎

由於Kubernetes是基於Docker容器作為應用發布的載體,而Docker本身的網路特性也決定了Kubernetes在構建一個容器互連網路必須要解決Docker自身網路的缺陷。

網路命名空間

為了支援網路通訊協定棧的多個執行個體,Linux在網路命名空間中引入了網路命名空間(Network Namespace),這些網路通訊協定棧被隔離到不同的命名空間中。不同的命名空間中資源完全隔離,彼此之間無法完全通訊。通過不同的網路命名空間,就可以在一台宿主機上虛擬多個不同的網路環境。Docker正是利用了網路命令空間的特性實現了不同容器之間的網路隔離。

在Linux的網路命名空間中可以配置自己獨立的iptables規則來設定包轉寄,NAT和包過濾等。

由於網路命名空間彼此隔離,無法直接通訊,如果要打通兩個隔離的網路命名空間,實現資料互連,就需要用到Veth裝置對。Veth裝置對的一個主要作用就是打通不同的網路通訊協定棧,它就像是一個網線,兩端分別串連不同的網路命名空間的協議棧。
如果想在兩個命名空間之間進行通訊,就必須有一個Veth裝置對。

網路命名空間的操作

1、建立一個名為test的網路命名空間:

# ip netns add test

2、在此命名空間中執行ip a命令

# ip netns exec test ip a1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

如果想執行多個命令,可以直接進入此網路命名空間中執行:

# ip netns exec test sh退出執行# exit

我們可以在不同的網路命名空間中轉義裝置,如上面提到的Veth裝置對,由於一個裝置只能屬於一個網路命名空間,所以當裝置被轉移後,在當前的命名空間中就無法查看到此裝置了。

Veth裝置對

由於Veth需要串連兩個不同的網路命名空間,所以Veth裝置一般是成對出現的,稱其中一端為另一端的peer。

1、建立Veth裝置對

# ip link add veth0 type veth peer name veth1

建立一個veth裝置對,本端為veth0, 對端為veth1

2、查看裝置對:

# ip link show1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000    link/ether 52:54:00:7f:52:5a brd ff:ff:ff:ff:ff:ff3: [email protected]: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000    link/ether 26:3f:dd:c0:70:cb brd ff:ff:ff:ff:ff:ff4: [email protected]: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000    link/ether a2:91:f4:9c:5b:6b brd ff:ff:ff:ff:ff:ff

3、將veth1 分配到test網路命名空間中:

# ip link set veth1 netns test

4、查看當前裝置對情況:

# ip link show1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000    link/ether 52:54:00:7f:52:5a brd ff:ff:ff:ff:ff:ff4: [email protected]: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000    link/ether a2:91:f4:9c:5b:6b brd ff:ff:ff:ff:ff:ff link-netnsid 0

5、查看test網路命名空間的情況,發現此裝置對已經分配進來:

# ip netns exec test ip a1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:003: [email protected]: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000    link/ether 26:3f:dd:c0:70:cb brd ff:ff:ff:ff:ff:ff link-netnsid 0

6、由於兩端的裝置對還沒有地址,所以無法通訊,現在分別分配地址:

ip addr add 172.16.0.1/24 dev veth0  # 給本端的veth0分配ip地址ip netns exec test ip addr add 172.16.0.2/24 dev veth1  # 為對端的veth1 配置IP

7、可以查看veth的狀態,預設情況下都為DOWN:

# ip a|grep veth4: [email protected]: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000    inet 172.16.0.1/24 scope global veth0# ip netns exec test ip a|grep veth3: [email protected]: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000    inet 172.16.0.2/24 scope global veth1

8、啟動veth裝置對,查看網路是否打通:

# ip link set dev veth0 up# ip netns exec test ip link set dev veth1 up# ping 172.16.0.2PING 172.16.0.2 (172.16.0.2) 56(84) bytes of data.64 bytes from 172.16.0.2: icmp_seq=1 ttl=64 time=0.150 ms64 bytes from 172.16.0.2: icmp_seq=2 ttl=64 time=0.028 ms

9、查看對端裝置
當裝置對比較多的情況下,無法確認對端的裝置是屬於哪個裝置對的,可以使用ethtool命令來查看對端的裝置編號:

# ethtool -S veth0       # 查看veth0的對端裝置編號NIC statistics:     peer_ifindex: 3     # 這裡顯示的對端的裝置編號為3# ip netns exec test ip link |grep 3:  # 對端裝置編號為3的裝置資訊3: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000# 本地的veth0 編號為4# ip link |grep veth4: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000#在對端驗證# ip netns exec test ethtool -S veth1NIC statistics:     peer_ifindex: 4
橋接器

Linux中的橋接器和現實中的交換器類似,是一個虛擬二層裝置。橋接器上可以attach若干個網路介面裝置,如eth0,eth1等,當有資料到達橋接器時,橋接器會根據報文中MAC地址資訊進行轉寄或丟棄處理。橋接器會自動學習內部的MAC連接埠映射,並會周期性的更新。

橋接器和現實中的裝置有一個區別,那就是從網路介面過來的資料會直接發送到橋接器上,而不是從特定的連接埠接收。

橋接器可以設定IP地址,當一個裝置如eth0添加到橋接器上之後,綁定在裝置上的IP就無效了,如果要實現通訊,需要給橋接器配置一個IP。

1、如果要配置橋接網卡,需要安裝bridge-utils工具:

 # yum install bridge-utils -y

2、添加一個橋接器裝置br0

 # brctl addbr br0

3、將eth0添加到br0上(此步執行後,eth0上的IP會失效,雖然IP還在eth0上,但是無法接收資料,如果使用ssh將會中斷連線):

 # brctl addif br0 eth0 

4、 刪除eth0上的ip:

 ip addr del dev eth0 10.0.0.1/24

5、給br0添加此IP

 ifconfig br0  10.0.0.1/24 up

6、給br0添加預設路由:

 route add default gw 10.0.0.254

7、我們可以通過如下命令查卡當前的路由資訊:

 ip route list netstat -rn route -n
Docker 網路實現

在純Docker的環境,Docker支援4類網路模式:

  • host模式:使用宿主機的IP和連接埠
  • container模式:和已存在的容器共用網路
  • none模式: 不進行網路設定
  • bridge模式: 預設模式,使用橋接網路,Kubernetes使用此模式。

由於Kubernetes中只使用bridge模式,所以這裡只討論bridge模式。

Docker 網路模型

網路樣本圖:

通過,可以清楚的表示容器的網路結構,其中容器中的網卡eth0和綁定在Docker0橋接器上的vethxxx裝置是一對veth裝置對。其中vethxxx由於綁定到docker0橋接器,所以沒有IP地址,容器中的eth0分配了和docker0同一網段的地址,這樣就實現了容器的互聯。

通過查看運行兩個容器的宿主:

# ip a1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00    inet 127.0.0.1/8 scope host lo       valid_lft forever preferred_lft forever    inet6 ::1/128 scope host        valid_lft forever preferred_lft forever2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000    link/ether 52:54:00:15:c2:12 brd ff:ff:ff:ff:ff:ff    inet 192.168.20.17/24 brd 192.168.20.255 scope global eth0       valid_lft forever preferred_lft forever    inet6 fe80::5054:ff:fe15:c212/64 scope link        valid_lft forever preferred_lft forever3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP     link/ether 02:42:fa:6f:13:18 brd ff:ff:ff:ff:ff:ff    inet 172.17.0.1/16 scope global docker0       valid_lft forever preferred_lft forever    inet6 fe80::42:faff:fe6f:1318/64 scope link        valid_lft forever preferred_lft forever7: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP     link/ether f2:4e:50:a5:fb:b8 brd ff:ff:ff:ff:ff:ff link-netnsid 0    inet6 fe80::f04e:50ff:fea5:fbb8/64 scope link        valid_lft forever preferred_lft forever19: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP     link/ether 7a:96:bc:c7:03:d8 brd ff:ff:ff:ff:ff:ff link-netnsid 1    inet6 fe80::7896:bcff:fec7:3d8/64 scope link        valid_lft forever preferred_lft forever

通過查看橋接網卡資訊,可以驗證這兩個veth綁定在docker0上:

# brctl  showbridge name bridge id       STP enabled interfacesdocker0     8000.0242fa6f1318   no      veth36fb1f6                                        veth37e9040

預設情況下,docker隱藏了網路命名空間的配置,如果要通過ip netns list命令查看資訊,需要進行如下操作:

# docker inspect 506a694d09fb|grep Pid            "Pid": 2737,            "PidMode": "",            "PidsLimit": 0,# mkdir /var/run/netns# ln -s /proc/2737/ns/net /var/run/netns/506a694d09fb# ip netns list506a694d09fb (id: 0)6d9742fb3c2d (id: 1)

分別查看兩個容器的IP:

# ip netns exec 506a694d09fb ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00    inet 127.0.0.1/8 scope host lo       valid_lft forever preferred_lft forever6: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP     link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0    inet 172.17.0.2/16 scope global eth0       valid_lft forever preferred_lft foreve# ip netns exec 6d9742fb3c2d ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00    inet 127.0.0.1/8 scope host lo       valid_lft forever preferred_lft forever18: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP     link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0    inet 172.17.0.3/16 scope global eth0       valid_lft forever preferred_lft forever

可以發現這兩個容器屬於不同網路命名空間,但是在同一網段,通過veth裝置對,綁定docker0互聯。
通過ethtool -S veth-name 可以查看到對應的peer端,這裡就不再示範,其實通過veth的名稱([email protected])也可以發現所指的介面資訊。

Kubernetes的網路實現

Kubernetes主要解決以下幾個問題:

  • 容器到容器之間的通訊
  • 抽象Pod到Pod之間的通訊
  • Pod到Service之間的通訊
  • 叢集外部和叢集內部之間的通訊
容器與容器之間的通訊

同一個Pod中的容器屬於同一個網路命名空間,共用同一個Linux網路通訊協定棧,通過本地的localhost網路來與Pod內的其他容器通訊,pod中的容器如:

Pod與Pod之間的通訊

同宿主機上的通訊:

在宿主機內部通過docker0的橋接網卡,可以實現Pod之間的直接通訊,這裡和純docker環境下的多個容器互連原理相似。

另一種情況是在不同宿主機上的不同Pod之間通訊,其原理圖如下:

網路外掛程式CNI

CNI是由CoreOS公司提出的一種容器網路規範,定義容器運行環境與網路外掛程式之間的簡單介面規範。
CNI模型涉及兩個概念:

  • 容器:擁有獨立Linux網路命名空間的環境,如Docker和rkt。
  • 網路:網路表示可以互聯的一組實體,這些實體擁有獨立,唯一的IP地址。
Kubernetes 中使用的網路外掛程式

Kubernetes目前支援多種網路外掛程式,可以使用CNI外掛程式規範實現的介面,與外掛程式提供者進行對接。當在Kubernetes中指定外掛程式時,需要在kubelet服務啟動參數中指定外掛程式參數:

... --network-plugin=cni   --cni-conf-dir=/etc/cni/net.d \  # 此目錄下的設定檔要符合CNI規範。  --cni-bin-dir=/opt/kubernetes/bin/cni ...

目前有多個開源的項目支援以CNI網路外掛程式的形式部署到Kubernetes,包括 Calico、Canal、Cilium、Contiv、Fannel、Romana、Weave等。

Flannel網路實現原理

Flannel原理圖:

我們之所以要單獨使用第三方的網路外掛程式來擴充k8s,主要原因是在使用docker的環境中,在每個node節點的docker0預設的網段都是172.17.0.0/16的網路。如果要實現不同宿主node上pod(這裡也可以理解為容器)互相通訊,就不能使用預設的docker0提供的網段,我們需要部署一個Fannel的覆蓋網路,讓每個node節點的docker0網路都處於不同的網段,這樣,通過添加一些路由轉寄策略,就能讓叢集中各個pod在同一個虛擬網路中實現通訊。

Fannel首先連上etcd,利用etcd來管理可分配的IP位址區段資源,同時監控etcd中每個Pod的實際地址,並在記憶體中建立一個Pod節點路由表,將docker0發給它的資料包封裝,利用物理網路的串連將資料投遞到目標flannel上,從而完成Pod到Pod之間的通訊。
Fannel為了不和其他節點上的Pod IP產生衝突,每次都會在etcd中擷取IP,Flannel預設使用UDP作為底層傳輸協議。

Calico 網路實現原理

Kubernetes中如果要實現Network Policy,僅僅使用Flannel網路是無法實現的,其本身只是解決了Pod互聯的問題,如果需要Network Policy功能,需要使用如Calico、Romana、Weave Net和trireme等支援Network Policy的網路外掛程式。這裡將介紹常用的Calico的原理。

Calico介紹

Calico是一個基於BGP的純三層的網路解決方案。Calico在每個節點利用Linux Kernel實現了一個高效的vRouter來負責資料的轉寄。 每個vRouter通過BGP1協議把在本節點上啟動並執行容器的路由資訊向整個Calico網路廣播,並自動化佈建到其它節點的路由轉寄規則。Calico保證所有所有容器之間的資料流量都是通過IP路由的方式完成互聯。Calico節點群組網可以直接利用資料中心的網路結構(L2和L3),不需要額外的NAT、隧道或者Overlay Network,所以就不會有額外的封包和解包過程,能夠節省CPU的運算,提升網路效率,相比而言Calico網路比Flannel效能更高。

Overlay網路和Calico網路資料包結構對比(簡圖):

特性:

  • Calico在小規模叢集中可以直接互聯,在大規模叢集中可以通過額外的BGP route reflector來完成。
  • Calico基於iptables還提供了豐富的網路原則。實現了Kubernetes的Network Policy策略,用於提供容器間網路可達性限制的功能。
  • 在需要使用Overlay網路的環境,Calico使用 IP-in-IP隧道的方式,也可以與其它的overlay網路相容,如flannel。
  • Calico還提供網路安全規則的動態實施。
  • Calico比較適合部署在物理機和私人雲端環境中的大型Kubernetes叢集,相比於覆蓋網路(如flannel)效能更高,更加簡單,易於部署和維護。

使用Calico的簡單策略語言,您可以實現對容器,虛擬機器工作負載和裸機主機端點之間通訊的細粒度控制。

Calico v3.0與Kubernetes和OpenShif整合的環境已經過大規模的生產驗證。

Calico架構及組件

Calico架構圖:

Calico組件:

  • Felix: Calico的agent,需要運行在每一台主機上,主要為容器或虛擬機器設定網路資源(IP地址,路由規則,Iptables規則等),保證跨主機容器網路互連。
  • etcd: 用於Calico的資料存放區。
  • Orchestrator Plugin : 特定於orchestrator的代碼,將Calico緊密整合到該orchestrator中,主要提供與整合平台的API轉換和反饋Felix agent的狀態。
  • BIRD: BGP的用戶端組件,負責分發各個節點的路由資訊到Calico網路中。(使用BGP協議)
  • BGP Route Reflector(BIRD): 可以通過單獨一個和多個BGP Router Reflector 來完成大規模叢集的分級路由分發。(可選組件)
  • Calicoctl: Calico的命令列工具。
各組件的功能和實現Felix

Felix是一個守護進程,它在每個提供endpoint的電腦上運行:在大多數情況下,這意味著在託管容器或VM的宿主節點上運行。 它負責設定路由和ACL以及主機上所需的任何其他任務,以便為該主機上的端點提供所需的串連。
Felix一般負責以下任務:

  • ==介面管理==:
    Felix將有關介面的一些資訊編程到核心中,以使核心能夠正確處理該端點發出的流量。 特別是,它將確保主機使用主機的MAC響應來自每個工作負載的ARP請求,並將為其管理的介面啟用IP轉寄。它還監視出現和消失的介面,以便確保在適當的時間應用這些介面的編程。

  • ==路由規劃==:
    Felix負責將到其主機端點的路由編程到Linux核心FIB(轉寄資訊庫)中。 這確保了發往那些到達主機的端點的資料包被相應地轉寄。

  • ==ACL規劃==:
    Felix還負責將ACL編程到Linux核心中。 這些ACL用於確保只能在端點之間發送有效流量,並確保端點無法繞過Calico的安全措施。

  • ==狀態報表==:
    Felix負責提供有關網路健康情況的資料。 特別是,它報告配置其主機時的錯誤和問題。 該資料被寫入etcd,以使其對網路的其他組件和操作人員可見。
Orchestrator 外掛程式(可選)

與Felix 沒有單獨的Orchestrator外掛程式相反,每個主要的雲編排平台(如Kubernetes)都有單獨的外掛程式。這些外掛程式時將Calico更緊密的綁定到協調器中,允許使用者管理Calico網路,就像他們管理協調器中的網路工具一樣。Kubernetes中可以直接使用CNI外掛程式來代替此功能。
一個好的Orchestrator外掛程式樣本是Calico Neutron ML2機制驅動程式。 該組件與Neutron的ML2外掛程式整合,允許使用者通過Neutron API調用來配置Calico網路。 這提供了與Neutron的無縫整合。主要有以下功能:

  • ==API轉換==:
    協調器將不可避免地擁有自己的一套用於管理網路的API。 Orchestrator外掛程式的主要工作是將這些API轉換為Calico的資料模型,然後將其儲存在Calico的資料存放區區中。
    這種轉換中的一些將非常簡單,其他位元可能更複雜,以便將單個複雜操作(例如,即時移轉)呈現為Calico網路的其餘部分期望的一系列更簡單的操作。

  • ==反饋==:
    如有必要,orchestrator外掛程式將從Calico網路向協調器提供反饋。 例子包括:提供有關Felix活力的資訊; 如果網路設定失敗,則將某些端點標記為失敗。
etcd

Calico使用etcd提供組件之間的通訊,並作為一致的資料存放區,確保Calico始終可以構建準確的網路。
根據orchestrator外掛程式,etcd可以是主要資料儲存,也可以是單獨資料存放區的輕量級副本鏡像.主要功能:

  • ==資料存放區==:
    etcd以分布式,容錯的方式儲存Calico網路的資料(這裡指使用至少三個etcd節點的etcd叢集)。 這確保Calico網路始終處於已知良好狀態。
    Calico資料的這種分布式儲存還提高了Calico組件從資料庫讀取的能力,使它們可以在叢集周圍分發讀取。

  • ==通訊樞紐==:
    etcd也用作組件之間的通訊匯流排。通過查詢etcd中資料的變化來使得各個組件做出相應的操作。
BGP Client(BIRD)

Calico在每個也承載Felix的節點上部署BGP用戶端。 BGP用戶端的作用是讀取Felix程式進入核心並將其分布在資料中心周圍的路由狀態。
在Calico中,這個BGP組件最常見的是BIRD,但是任何BGP用戶端(例如可以從核心中提取路由並分發它們的GoBGP)都適用於此角色。

  • ==路由分發==:
    當Felix將路由插入Linux核心FIB時,BGP用戶端將接收它們並將它們分發到部署中的其他節點。 這可確保在部署周圍有效地路由流量。
BGP Route Reflector (BIRD)

對於大型叢集的部署,簡單的BGP可能由於瓶頸而成為限制因素,因為它要求每個BGP用戶端串連到網狀拓撲中的每個其他BGP用戶端。 這使得用戶端的串連將以N ^ 2量級增長,當節點越來越多將變得難以維護。因此,在大型叢集的部署中,Calico將部署BGP Route Reflector。 通常在Internet中使用的此組件充當BGP用戶端串連的中心點,從而防止它們需要與群集中的每個BGP用戶端進行通訊。為了實現冗餘,可以無縫部署多個BGP Route Reflector。
BGP Route Reflector純粹參與網路控制:沒有端點資料通過它們。在Calico中,此BGP組件也是最常見的BIRD,配置為BGP Route Reflector而不是標準BGP用戶端。

  • ==大規模叢集的路由分發==:
    當Calico BGP用戶端將路由從其FIB通告到BGP Route Reflector時,BGP Route Reflector會將這些路由通告給Calico網路中的其他節點。

Kubernetes 網路原理

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.