Flannel网络组件实践(vxlan、host-gw)

Kubernetes网络组件之 Flannel

Flannel是CoreOS维护的一个网络组件,Flannel为每个Pod提供全局唯一的IP,Flannel使用ETCD来存储Pod子网与Node IP之间的关系。flanneld守护进程在每台主机上运行,并负责维护ETCD信息和路由数据包。

1、Flannel 部署

https://github.com/coreos/flannel

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
2、 Flannel工作模式及原理

Flannel支持多种数据转发方式:

  • UDP:最早支持的一种方式,由于性能最差,目前已经弃用。
  • VXLAN:Overlay Network方案,源数据包封装在另一种网络包里面进行路由转发和通信。==(100台左右node适用)==
  • Host-GW:Flannel通过在各个节点上的Agent进程,将容器网络的路由信息刷到主机的路由表上,这样一来所有的主机都有整个容器网络的路由数据了。==(node数量超过130台,性能瓶颈)==

查看flannel 分配子网信息:

[root@k8s-master1 ~]# cat /var/run/flannel/subnet.env
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
查看flannel配置文件:
[root@k8s-master1 ~]# more /etc/cni/net.d/10-flannel.conflist

VXLAN
# kubeadm部署指定Pod网段
kubeadm init --pod-network-cidr=10.244.0.0/16

# 二进制部署指定(启用cni)
cat /opt/kubernetes/cfg/kube-controller-manager.conf
--allocate-node-cidrs=true \
--cluster-cidr=10.244.0.0/16 \
# kube-flannel.yml
net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

为了能够在二层网络上打通“隧道”,VXLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备就叫作 VTEP,即:VXLAN Tunnel End Point(虚拟隧道端点)。下图flannel.1的设备就是VXLAN所需的VTEP设备。示意图如下:

mark

如果Pod 1访问Pod 2,源地址10.244.1.10,目的地址10.244.2.10 ,数据包传输流程如下:

  1. 容器路由:容器根据路由表从eth0发出

    / # ip route
    default via 10.244.0.1 dev eth0 
    10.244.0.0/24 dev eth0 scope link  src 10.244.0.45 
    10.244.0.0/16 via 10.244.0.1 dev eth0
  2. 主机路由:数据包进入到宿主机虚拟网卡cni0,根据路由表转发到flannel.1虚拟网卡,也就是,来到了隧道的入口。

    # ip route
    default via 192.168.31.1 dev ens33 proto static metric 100 
    10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1 
    10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink 
    10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
  3. VXLAN封装:而这些VTEP设备(二层)之间组成二层网络必须要知道目的MAC地址。这个MAC地址从哪获取到呢?其实在flanneld进程启动后,就会自动添加其他节点ARP记录,可以通过ip命令查看,如下所示:

    # ip neigh show dev flannel.1
    10.244.1.0 lladdr ca:2a:a4:59:b6:55 PERMANENT
    10.244.2.0 lladdr d2:d0:1b:a7:a9:cd PERMANENT
  4. 二次封包:知道了目的MAC地址,封装二层数据帧(容器源IP和目的IP)后,对于宿主机网络来说这个帧并没有什么实际意义。接下来,Linux内核还要把这个数据帧进一步封装成为宿主机网络的一个普通数据帧,好让它载着内部数据帧,通过宿主机的eth0网卡进行传输。

  5. 封装到UDP包发出去:现在能直接发UDP包嘛?到目前为止,我们只知道另一端的flannel.1设备的MAC地址,却不知道对应的宿主机地址是什么。

    flanneld进程也维护着一个叫做FDB的转发数据库,可以通过bridge fdb命令查看:

    # bridge fdb show  dev flannel.1
    
       d2:d0:1b:a7:a9:cd dst 192.168.31.61 self permanent
       ca:2a:a4:59:b6:55 dst 192.168.31.63 self permanent

    可以看到,上面用的对方flannel.1的MAC地址对应宿主机IP,也就是UDP要发往的目的地。使用这个目的IP进行封装。

  6. 数据包到达目的宿主机:Node1的eth0网卡发出去,发现是VXLAN数据包,把它交给flannel.1设备。flannel.1设备则会进一步拆包,取出原始二层数据帧包,发送ARP请求,经由cni0网桥转发给container。

Host-GW

host-gw模式相比vxlan简单了许多, 直接添加路由,将目的主机当做网关,直接路由原始封包。

下面是示意图:

==线上更改网路模式一定要放在夜深人静去变更!!==

# more /tmp/k8s/kube-flannel.yaml

net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "host-gw"
      }
    }

修改如上为host-gw然后应用:
[root@k8s-master1 ~]# kubectl apply -f kube-flannel.yml
podsecuritypolicy.policy/psp.flannel.unprivileged configured
clusterrole.rbac.authorization.k8s.io/flannel unchanged
clusterrolebinding.rbac.authorization.k8s.io/flannel unchanged
serviceaccount/flannel unchanged
configmap/kube-flannel-cfg configured
daemonset.apps/kube-flannel-ds-amd64 configured
daemonset.apps/kube-flannel-ds-arm64 created
daemonset.apps/kube-flannel-ds-arm created
daemonset.apps/kube-flannel-ds-ppc64le created
daemonset.apps/kube-flannel-ds-s390x created

###如上如果未生效,评估下风险,可删除后再次重建
[root@k8s-master1 ~]# kubectl delete -f kube-flannel.yml
[root@k8s-master1 ~]# kubectl apply -f kube-flannel.yml

当你设置flannel使用host-gw模式,flanneld会在宿主机上创建节点的路由表:

# ip route  ##这样我们就看到了如上host-gw的特色,将目的主机当做网关。

default via 192.168.31.1 dev ens33 proto static metric 100 
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1 
10.244.1.0/24 via 192.168.31.63 dev ens33   ##集群另外两台node的路由
10.244.2.0/24 via 192.168.31.61 dev ens33   ##集群另外两台node的路由
192.168.31.0/24 dev ens33 proto kernel scope link src 192.168.31.62 metric 100

目的 IP 地址属于 10.244.1.0/24 网段的 IP 包,应该经过本机的 eth0 设备发出去(即:dev eth0);并且,它下一跳地址是 192.168.31.63(即:via 192.168.31.63)。

一旦配置了下一跳地址,那么接下来,当 IP 包从网络层进入链路层封装成帧的时候,eth0 设备就会使用下一跳地址对应的 MAC 地址,作为该数据帧的目的 MAC 地址。

而 Node 2 的内核网络栈从二层数据帧里拿到 IP 包后,会“看到”这个 IP 包的目的 IP 地址是 10.244.1.20,即 container-2 的 IP 地址。这时候,根据 Node 2 上的路由表,该目的地址会匹配到第二条路由规则(也就是 10.244.1.0 对应的路由规则),从而进入 cni0 网桥,进而进入到 container-2 当中。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!