k8s flannel 插件 基本通信原理

flannel

是一種 CNI 解決方案,也可以爲 Dokcer 提供服務,對 k8s 而言,是一個網絡插件。

  • 實現了 CNI 的網絡控制平面軟件
  • 屬於 coreOS 的子項目
  • 通過配置主機路由或者 overlay,避免對物理路由器進行配置
    • VxLAN
    • UDP
    • Host-GW

和 k8s 集成時,運行在 work node 上面,監聽 k8s master 的狀態,共用 k8s 的控制節點的 etcd 作爲自己的數據庫。
1

安裝

實驗節點分佈
在這裏插入圖片描述

  1. master node

    # 初始化 master 節點
    sudo kubeadm reset
    sudo kubeadm init --config kubadm.yaml 
    # 下載 flannel 配置文件
    wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    # 修改配置文件,net-json 改爲 k8s 安裝的 podSubnet,type 默認爲 vxlan 
      net-conf.json: |
        {
          "Network": "10.244.0.0/16",
          "Backend": {
            "Type": "vxlan"
          }
        }
    # 部署
    kubectl apply -f kube-flannel.yml
    # 查看
    kubectl get pods --all-namespaces
    ---
    NAMESPACE     NAME                           READY   STATUS              RESTARTS   AGE
    kube-system   coredns-66bff467f8-m7ghl       0/1     ContainerCreating   0          11m
    kube-system   coredns-66bff467f8-mgnj7       0/1     ContainerCreating   0          11m
    kube-system   etcd-x-vm                      1/1     Running             0          11m
    kube-system   kube-apiserver-x-vm            1/1     Running             1          11m
    kube-system   kube-controller-manager-x-vm   1/1     Running             0          11m
    kube-system   kube-flannel-ds-amd64-g7hl9    1/1     Running             0          35s
    kube-system   kube-proxy-5x7l5               1/1     Running             0          11m
    kube-system   kube-scheduler-x-vm            1/1     Running             0          11m
    # 多次查看,可以看到 coredns Pending -> ContainerCreating -> Running,因爲 flannel 初始化初始化完成之後,k8s 認爲當前節點可用,就創建了 coredns
    
    
  2. worker node

    安裝 docker、kubeadm,關閉 swap,加入到集羣中,hostname 不能重複

    # 在 master node 上初始化完成之後,會輸出如下 token
    kubeadm join 192.168.121.137:6443 --token abcdef.0123456789abcdef \
        --discovery-token-ca-cert-hash sha256:719b052641c7681b770f9609e82d6a8001ef9aa1125db6cea7b1a452d555c34a
    # 加入完成後,在 master node 上查看
    kubectl get nodes
    NAME     STATUS   ROLES    AGE   VERSION
    worker   Ready    <none>   52s   v1.18.4
    x-vm     Ready    master   23m   v1.18.4
    

    在 worker node 上查看容器,確認 flannel、kube-proxy 已經運行
    1

  3. 調整 coredns,使其分佈到 worker node 上

    # -n 指定 namespace,先刪除
    kubectl scale -n kube-system  deployment.v1.apps/coredns --replicas=0
    # 再將數量調整爲 2,期望結果是兩個 codedns 的 pod 分佈到兩個節點上
    kubectl scale -n kube-system  deployment.v1.apps/coredns --replicas=2
    

    查看 pod 分佈情況 kubectl get pods --all-namespaces -o wide,已經分佈到兩個節點上
    在這裏插入圖片描述
    查看 worker node 網卡信息,可以看到 doredns 容器對應的 veth 已經存在,而且也有了 cni 網卡
    在這裏插入圖片描述

host-gw 實現

基本原理

在 kube-net 網絡實現中:

  • 同 node 中的 pod 互相通信是通過 cbr0 網橋二層互通
  • 跨 node 通信是通過主機的默認路由,路由到物理網絡中進行數據轉發,此時需要在物理路由器上進行路由相關的配置

部署 flannel 時,將配置文件中 net-json 字段的 Type 修改爲 host-gw
Flannel host-gw 實現方案中,由於 linux 具有路由轉發功能,所以可以將物理路由器相關的配置下沉到 work node (主機)上,由主機進行路由,類似於DVR,也避免了單點故障。
Flannel 連接 k8s 的數據庫,每個 node 上的 flanned 進程知道所有 podSubnet 對應的 node,進而在主機的網絡空間中配置 podSubnet 的路由指向對應的 node。
Flannel 環境中連接 pod 的 Linuxbridge 爲 cni0(kube-net 是 cbr0),所有的 work node 必須在同一個二層網絡中(添加路由時必須是二層可達纔會生效)

實操

Flannel 安裝完成後,查看路由信息:
在這裏插入圖片描述

# 在 master node 上創建一個臨時的 pod,使用 nodeSelector 指定運行的 node
kubectl run -it --rm --restart=Never test1 --image busybox --overrides='{"apiVersion": "v1","spec": {"nodeSelector": {"kubernetes.io/hostname": "x-vm"}}}' sh
# 新開一個窗口,在 work node 上創建一個臨時的 pod
kubectl run -it --rm --restart=Never test2 --image busybox --overrides='{"apiVersion": "v1","spec": {"nodeSelector": {"kubernetes.io/hostname": "worker"}}}' sh

新開一個窗口,檢查一個 pod 運行情況,可以看到分佈在兩個 node 上,IP 分別是 11.0.0.5 和 11.0.1.3
在這裏插入圖片描述
用 pod test1 去 ping test2,在 work node 上抓包
在這裏插入圖片描述
可以從物理網卡抓到兩個 pod 之間的通信流量
在 pod test1 上 traceroute test2,可以看到路徑經過了 work node 到達 test2
在這裏插入圖片描述

VxLAN 實現

基本原理

  • Ethernet Frame 封裝到 UDP 中
  • 不考慮物理網絡衝突問題
  • 封裝需要額外的 50 字節(網卡默認 MTU 爲 1450)
  • 允許 woker node 分佈到三層網絡中

VxLAN 數據包封裝:
在這裏插入圖片描述

Flannel VxLAN 基於 Linux 原生的方式實現 VxLAN

# Linux 通過 VxLAN 字節口實現 VxLAN 的封裝解封裝
ip link add vxlan0 type vxlan id 1 \
remote 192.168.121.137 \
local 192.168.121.138 \
dstport 8472 \
dev eth0
# 通過監聽端口來攔截數據進行封裝解封裝

Flannel 的 VxLAN 實現

Flannel 會在 node 上額外創建 flannel.<vni> 設備,掛載的 ip 爲當前 node podSubnet 的第 0 個地址作爲 VTEP 地址。

當有多個 node 時,如果按照 Linux 原生方式實現 VxLAN 時,每個 node 都要和其他 node 建立 VxLAN 隧道,也就是每個 node 上都要創建多個類型爲 vxlan 的 netdev 設備,這樣子接口的數量就是 n^2。

爲了避免這種情況,flannel 添加 flannel.vni 子接口的時候,並沒有指定 remote ip,而是添加了對端 flannel.vni 的靜態 arp 表項,並添加二層轉規則(bridge fdb 查看),如果是發往對端的 flannel.vni 的 MAC 地址的話,從本端子接口發出,且指定了遠端的 VTEP 地址。

在這裏插入圖片描述

實操

  1. 清理 host-gw 環境,修改配置文件,重新部署 flannel

    # 刪除 flannel
    kubectl delete -f kube-flannel.yml
    # 刪除 coredns
    kubectl scale -n kube-system  deployment.v1.apps/coredns --replicas=0
    # 修改 kube-flannel.yml 中 net-json type 爲 vxlan
    # 重新部署
    kubectl apply -f kube-flannel.yml
    # 添加 coredns
    kubectl scale -n kube-system  deployment.v1.apps/coredns --replicas=2
    
  2. 查看網卡信息

    ip addr,可以看到 vni 接口
    在這裏插入圖片描述
    查看 arp 表
    在這裏插入圖片描述
    查看轉發數據庫,bridge fdb
    在這裏插入圖片描述
    在 work node 上查看接口,MAC 地址和 master node 上的轉發表一致
    在這裏插入圖片描述

  3. 創建 pod ,抓包驗證

    # 在 master node 上創建一個臨時的 pod,使用 nodeSelector 指定運行的 node
    kubectl run -it --rm --restart=Never test1 --image busybox --overrides='{"apiVersion": "v1","spec": {"nodeSelector": {"kubernetes.io/hostname": "x-vm"}}}' sh
    # 新開一個窗口,在 work node 上創建一個臨時的 pod
    kubectl run -it --rm --restart=Never test2 --image busybox --overrides='{"apiVersion": "v1","spec": {"nodeSelector": {"kubernetes.io/hostname": "worker"}}}' sh
    
    

    查看 pods 分佈情況:
    在這裏插入圖片描述

    用 test1 ping test2 ,在 worker 物理接口上抓包,可以看到封裝數據包的內容
    在這裏插入圖片描述

UDP 實現

非 VxLAN 的 UDP 數據封裝,不推薦使用
數據經過用戶態轉發,性能低

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