1. 程式人生 > 其它 >k8s 網路

k8s 網路

Docker 網路

Docker 網路是通過 Bridge 來實現的,每個容器都會建立一個虛擬網絡卡對(Veth Pair),一個插在容器裡,一個插在 docker0 這個網橋上(交換機),這樣容器之間就可以互相通訊了。

Docker 跨主機通訊是通過 VXLAN 來實現的,Virtual Extensible LAN,每個宿主機會建立一個虛擬網路裝置 VTEP (VXLAN Tunnel End Point),這個網路裝置可以將 docker0 的 IP 包進行二次封裝(加上 VTEP 的 MAC 地址),完全由 Linux 核心進行封裝和解封裝,不需要經過使用者態。docker0 和 VTEP 都是基於 MAC 地址進行轉發的,屬於交換機。

Kubernetes 網路

由於 Docker 跨主機網路需要做複雜的地址轉換,所以 k8s 提出了一個自己的網路模型 ”IP-per-pod“,能夠很好的適應叢集的網路需求。它有如下四點基本要求:

  • 叢集裡的每個 Pod 都會有唯一的一個 IP 地址。

  • Pod 裡的所有容器共享這個 IP 地址。

  • 叢集裡的所有 Pod 都屬於同一個網段。

  • Pod 直接可以基於 IP 地址直接訪問另一個 Pod,不需要做麻煩的網路地址轉換(NAT)。

網路模型圖:

因為 Pod 都具有獨立的 IP 地址,相當於一臺虛擬機器,而且直連互通,也就可以很容易地實施域名解析、負載均衡、服務發現等工作,以前的運維經驗都能夠直接使用,對應用的管理和遷移都非常友好。

CNI

CNI 就是實現上述網路模型的標準:Container Networking Interface。

依據實現技術的不同,CNI 外掛可以大致上分成“Overlay”“Route”和“Underlay”三種。

  • Overlay 的原意是“覆蓋”,是指它構建了一個工作在真實底層網路之上的“邏輯網路”,把原始的 Pod 網路資料封包,再通過下層網路傳送出去,到了目的地再拆包。因為這個特點,它對底層網路的要求低,適應性強,缺點就是有額外的傳輸成本,效能較低。

  • Route 也是在底層網路之上工作,但它沒有封包和拆包,而是使用系統內建的路由功能來實現 Pod 跨主機通訊。它的好處是效能高,不過對底層網路的依賴性比較強,如果底層不支援就沒辦法工作了。

  • Underlay 就是直接用底層網路來實現 CNI,也就是說 Pod 和宿主機都在一個網路裡,Pod 和宿主機是平等的。它對底層的硬體和網路的依賴性是最強的,因而不夠靈活,但效能最高。

選型

Flannel( https://github.com/flannel-io/flannel/ )是最早的一種 Overlay 模式的網路外掛,使用 UDP 和 VXLAN 技術。Flannel 簡單易用,是 Kubernetes 裡最流行的 CNI 外掛,但它在效能方面表現不是太好,所以一般不建議在生產環境裡使用。

Calico( https://github.com/projectcalico/calico )是一種 Route 模式的網路外掛,使用 BGP 協議(Border Gateway Protocol)來維護路由資訊,效能要比 Flannel 好,而且支援多種網路策略,具備資料加密、安全隔離、流量整形等功能。

Cilium( https://github.com/cilium/cilium )是一個比較新的網路外掛,同時支援 Overlay 模式和 Route 模式,它的特點是深度使用了 Linux eBPF 技術,在核心層次操作網路資料,所以效能很高,可以靈活實現各種功能。在 2021 年它加入了 CNCF,成為了孵化專案,是非常有前途的 CNI 外掛。

CNI 外掛工作方式

Fannel 外掛工作方式如圖,這也是 Docker 跨主通訊的方式:

Calico 外掛的工作方式:

可以在 Calico 的網站( https://www.tigera.io/project-calico/ )上找到它的安裝方式,我選擇的是“本地自助安裝(Self-managed on-premises)”,可以直接下載 YAML 檔案:

wget https://projectcalico.docs.tigera.io/manifests/calico.yaml

Calico 的安裝非常簡單,只需要用 kubectl apply 就可以(記得安裝之前最好把 Flannel 刪除):

kubectl apply -f calico.yaml

安裝之後檢視一下 Calico 的執行狀態,它是在 kube-system 的 Namespace 中。

kubectl get pod -n kube-system

我們建立三個 Nginx 來進行實驗:

kubectl create deploy ngx-dep --image=nginx:alpine --replicas=3

我們看到了它們的 IP 地址,分別是 10.10.171.* ,10.10.219.*

然後我們來看看 Pod 裡的網絡卡情況,你會發現雖然還是有虛擬網絡卡,但宿主機上的網絡卡名字變成了 calica17a7ab6ab@if4,而且並沒有連線到“cni0”網橋上:

這是 Calico 的工作模式導致的正常現象。因為 Calico 不是 Overlay 模式,而是 Route 模式,所以它就沒有用 Flannel 那一套,而是在宿主機上建立路由規則,讓資料包不經過網橋直接“跳”到目標網絡卡去。

來看一下節點上的路由表就能明白:

假設 Pod A“10.10.219.67”要訪問 Pod B“10.10.219.68”,那麼查路由表,知道要走“cali051dd144e34”這個裝置,而它恰好就在 Pod B 裡,所以資料就會直接進 Pod B 的網絡卡,省去了網橋的中間步驟。

Calico 的網路架構示意圖,你可以再對比 Flannel 來學習:

至於在 Calico 裡跨主機通訊是如何路由的,你完全可以對照著路由表,一步步地“跳”到目標 Pod 去(提示:tunl0 裝置)。

tunl0 裝置待更新 ~~

小結:

  • Kubernetes 使用的是“IP-per-pod”網路模型,每個 Pod 都會有唯一的 IP 地址,所以簡單易管理。

  • CNI 是 Kubernetes 定義的網路外掛介面標準,按照實現方式可以分成“Overlay”“Route”和“Underlay”三種,常見的 CNI 外掛有 Flannel、Calico 和 Cilium。

  • Flannel 支援 Overlay 模式,它使用了 cni0 網橋和 flannel.1 裝置,本機通訊直接走 cni0,跨主機通訊會把原始資料包封裝成 VXLAN 包再走宿主機網絡卡傳送,有效能損失。

  • Calico 支援 Route 模式,它不使用 cni0 網橋,而是建立路由規則,把資料包直接傳送到目標網絡卡,所以效能高。