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 数据封装,不推荐使用
数据经过用户态转发,性能低

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