Kubernetes网络组件之Flannel策略实践(vxlan、host-gw)

4.3 Kubernetes网络组件之 Flannel
Flannel是CoreOS维护的一个网络组件,Flannel为每个Pod提供全局唯一的IP,Flannel使用ETCD来存储Pod子网与Node IP之间的关系。flanneld守护进程在每台主机上运行,并负责维护ETCD信息和路由数据包。
其实k8s网络组件flannel和calico主要解决的问题是k8s节点之间容器网络的通信,flannel要保证每个pod的IP是唯一的,怎么保证是唯一的,大部分组件的做法是在每个Node上分配一个唯一的子网,node1是一个单独的子网,node2是一个单独的子网,可以理解是不同网段,不同vlan,所以每个节点都是一个子网,所以flannel会预先设置一个大的子网,然后在这个每个node上分配子网,这些信息都会由flannel存储到etcd中,并且每个子网绑定到node上都有关系记录的,然后方便下次进行二次的数据包传输,并且flannel在node上会启动一个守护进程并运行,守护进程主要维护的是本地的路由规则,和维护etcd中的信息。

1、Flannel 部署

 https://github.com/coreos/flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

部署好之后会以daemonset的形式在每个node上启动一个pod,来启动一个flannel的守护进程,主要负责本机路由表的设定和etcd中的数据,本地的子网上报到etcd中,所以守护进程是非常重要的
可以在flannel的配置文件去设定大的子网,还有属性模式

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

---

这个配置完之后会放到cni这个目录下,由于flannel是使用网桥的模式,实现的同节点数据包到达宿主机这个的通信,所以子网信息并没写到这个配置文件里,而是放到了这个 cat /var/run/flannel/subnet.env 下,这个通过ip a也能看到设备分配的ip,每个节点都会分配一个子网,网络接口设备为cni0,也就是一个node上可以分配255个小的子网

[[email protected] ~]# 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

还有一个cni的二进制文件, /opt/cni/bin,这个就是kubelet调用这个二进制接口为创建的每个pod创建网络信息,并且是从我们的配置的子网中去拿IP

配置的话修改的是就是预先设定它的子网,以及工作模式,另外就是这个网络不能与k8s本身的内网冲突,否则导致网络不通的状况

2、 Flannel工作模式及原理
Flannel支持多种数据转发方式:
UDP:最早支持的一种方式,由于性能最差,目前已经弃用。
VXLAN:Overlay Network方案,源数据包封装在另一种网络包里面进行路由转发和通信
这也是网络的虚拟化技术,也就是原来是有一个包数据包,有源IP和目的IP,但由于某些情况这个数据包到达不了目的地址上,这可能就会借助物理上的以太网网络进行封装一个数据包带上,然后通过这种物理网络传输到目的地址上,这是一种叠加式的网络,里面是有两种数据包的,这种也叫做隧道方案
Host-GW:Flannel通过在各个节点上的Agent进程,将容器网络的路由信息刷到主机的路由表上,这样一来所有的主机都有整个容器网络的路由数据了,这样它就知道这个数据包到达这个节点转发到这个机器上,也就是路由表之间转发的,这种也叫路由方案
VXLAN

使用kubeadm部署的话默认是支持的

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

但是使用二进制部署就得去启动cni的支持,默认我ansible部署的k8s集群都是启动的
二进制部署指定

cat /opt/kubernetes/cfg/kube-controller-manager.conf
--allocate-node-cidrs=true \     允许node自动分配cidr这个网络
--cluster-cidr=10.244.0.0/16 \   指定pod网络的网段,这个网段要和flannel的网段对应上

另外也都要在每个node节点的kubelet的配置文件上进行对cni的支持

[[email protected] ~]# cat /opt/kubernetes/cfg/kubelet.conf
--network-plugin=cni \

这样的话就能以cni的标准来为k8s配置网络

kube-flannel.yml
net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

在节点1上有个容器,与节点2上的容器进行通信,这两个是进行跨主机进行的通信,如果本机通信之间使用网桥使用二层的传输了,像原生的docker网就能解决了,最重要的是这两个节点的数据包传输

flannel保证每个node都是唯一的ip,它是在每个node上都分配一个子网
可以看到flannel是基于宿主机创建的,它会为每个node创建独立的子网,并为当前pod分配ip

[[email protected] ~]# kubectl get pod -n kube-system -o wide
kube-flannel-ds-amd64-4jjmm           1/1     Running   0          14d   10.4.7.11     k8s-master1   <none>           <none>
kube-flannel-ds-amd64-9f9vq           1/1     Running   0          14d   10.4.7.21     k8s-node2     <none>           <none>
kube-flannel-ds-amd64-gcf9s           1/1     Running   0          14d   10.4.7.12     k8s-node1     <none>           <none>

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

vxlan是怎么工作的?
vlan是Linux上支持的一个隧道的技术,隧道也就是点到点,端到端的两个设备的通信,其实vxlan实现是有一个vtep的设备做数据包的封装与解封装,而现在已经封装到flannel.1这个进程里面了,也就是这个虚拟网卡包含了veth来去使用对这个vxlan进行封装和解封装。

现在是Node1节点上的pod 1是1.10,现在要与Node2节点上的pod 2的2.10进行通信,他们是不在一个网络的,当这个数据包发出去的时候,pod1 的容器的网卡eth0,先出这个网卡,然后会连接这个veth这个好比就是一个网线,etch0是一头,veth是一头,也就是veth是这个设备的另一头,
这个veth是在宿主机上,那么这个宿主机就拿到了这个容器的数据包,然后这个数据包到达这个网桥上面,这个网桥也好比一个二层的交换机,所有的容器都会加入到这个网桥里面,可以通过yum -y install bridge-utils看到veth的另一端是不是加入到cni的网桥中,这个网桥就是flannel创建的,并且这个网桥有独立的mac地址和IP都可以看到

[[email protected] ~]# brctl show cni0
bridge name bridge id       STP enabled interfaces
cni0        8000.4a025e87aa87   no      veth08925d5a
                            veth2591a36f
                            veth676a1e86
                            veth718beeac
                            veth81dadcbd
                            veth8a96f11c
                            veth8c90fdb6
                            veth8f350182
                            veth90818f0b
                            vetha471152b

这个就是当我们创建好pod的时候由flannel去分配并加入这个网桥中的,这个后面有个interfaces有这个接口,这个相当于交换机的接口,这正是宿主机上的虚拟网卡,如果本地的话,直接走这个网桥就能直接找到了,然后就可以发送一个ARP广播包进行封包传输了,cni0就相当于一个二层交换机,帮你扩散,找目的的mac进行响应,所以说同节点就可以直接走网桥这个,那么这个目的地址不在这个网桥里面,就像2.10,当前的node是不知道2.10上的pod在哪,那么它只能走路由表了,也就是它它不一定目的地址的时候就会走默认网关,所以flannel会在宿主机上生成很多路由表通过ip router可以看到

[[email protected] ~]# ip route
default via 10.4.7.1 dev eth0 proto static metric 100
10.4.7.0/24 dev eth0 proto kernel scope link src 10.4.7.21 metric /
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 /
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 

部署docker生成的路由表,这里的docker0网桥是没有用到,当部署flannel的时候是默认使用的是自己的网桥,这个的原理和flannel的是一样的,只不过flannel用的是自己做的,也是为了方便自己处理数据包

这里的路由表都记录下来了,它会找哪个是目的地址2.10pod2的IP地址,所以它会根据这个路由表,然后发送到flannel的这个设备上,这个flannel是采用vxlan的模式,vxlan需要veth的数据封装与解封装,所以flannel就把这个数据包交给vxlan,而vxlan是一个内核级的驱动程序,有它去封装这个包,因为vxlan本身是工作在二层的,它还需要目的的mac地址

那么就可以通过ip neigh show dev flannel.1去查看mac地址

 [[email protected] ~]# ip neigh show dev flannel.1
10.244.2.0 lladdr ea:ca:d6:62:be:21 PERMANENT
10.244.1.0 lladdr 4e:e3:fa:5f:d2:34 PERMANENT

而flannel.1的vxlan实现是有一个vtep的设备做数据包的封装与解封装,因为它在2层进行封包,就要知道目的的mac地址,那么这个目的mac就由flannel去提供给vetp,flannel去存储对应下一跳的网关,那么这个网关肯定不是在本地,当我们拿到目的的mac地址之后你们就封装成一个完整的帧,那么封装好之后,对于宿主机没有太多的实际意义,因为这个数据包帧发不出去,要是按二层的走肯定到不了另外一个节点,因为在不同的子网里面,如果没有路由的介入肯定是通信不了的,接下来就需要linux内核的数据帧封装一个宿主机普通的数据帧,也就是udp封装一个普通的数据帧,也就是在这之上再加一层udp的包,这样做的目的能让数据包直接传输到目的容器的主机上。

vxlan是使用的udp协议,它会将原始的报文放在内部,而外部由udp封装的源IP与目的地址

[[email protected] ~]# bridge fdb show  dev flannel.1
a6:a4:e5:5d:19:9b dst 10.4.7.21 self permanent
ea:ca:d6:62:be:21 dst 10.4.7.12 self permanent

可以看到,上面用的对方flannel.1的MAC地址对应宿主机IP,也就是UDP要发往的目的地。使用这个目的IP进行封装。
也就是这些flannel都是知道的,为什么说flannel维护这etcd的数据,守护本地的路由规则,其实etcd的数据要和flannel,把它当前的数据写到etcd中,由各个节点都存储一份,所以根据这个地址拿到了mac地址,然后这又是一个完整的包,由vxlan封装的udp的包,这个udp包里面就有两个IP包的存在,udp就直接能发送到node2的节点上,数据包已经传输过去了,因为宿主机之间是同网段的,到达31.63上之后,接收到udp的包之后,会进行拆分,解包会将原始的包拿出来,所以这里就有一个vxlan的标记,本身flannel是由vtep处理的,所以在封包的时候对着干包打了个标记,也就是vxlan header的标记,首先打上vxlan的头部,那么这就意味着这就是一个vxlan的数据包,并且加了一个VNI的编号,VNI是为了区分vxlan的点对点隧道,多个数据包也是分外多个编号,也是为了区分,而这个编号被flannel引用到了,所以这是内部的一个编号,确认这个数据包无误,然后交给flannel.1这个设备,它处理这个数据包,拿到了源IP和目的IP,而去判断,会发现这个是cni网桥的,所以它根据路由表放到了cni网桥,根据这个路由表拆分这个目的地址,正好这个目的地址匹配到了,所以它会将这个转发到cni网桥里,到cni就跟之前一样了,就相当于一个二层交换机,拿到这个数据包,它会进行一个ARP的广播,发现正在这个网桥里面,然后就进行数据包的转发了。

从此看来;vxlan使用重叠网络,进行封包解封包,性能就下降了很多

小结:

  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
  1. 二次封包:知道了目的MAC地址,封装二层数据帧(容器源IP和目的IP)后,对于宿主机网络来说这个帧并没有什么实际意义。接下来,Linux内核还要把这个数据帧进一步封装成为宿主机网络的一个普通数据帧,好让它载着内部数据帧,通过宿主机的eth0网卡进行传输。
  2. 封装到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进行封装。

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

Host-GW
host-gw模式相比vxlan简单了许多, 直接添加路由,将目的主机当做网关,直接路由原始封包。
切换成host-gw的模式,上面的转发还是一样,pod1容器的网卡先连接veth到宿主机上,然后到达cni0的网桥上,这个网桥就相当于一个二层的交换机,这个数据包到cni的网桥之后,也就是到达宿主机上,那么宿主机的网络协议栈会根据路由表决定转发到哪个网关上,因为它的目的IP地址不是同网段的,肯定走路由表,它会根据路由表判断目的地址是2.10,也就是来自这个数据的数据包转发到了它的下一跳,也就是网关,通过接口之间转发到31.63上了,也就是直接安照宿主机的网络,因为这个数据包是宿主机处理的,所以宿主机要想访问31.63,会进行重新封包,目的地址就是31.63,它判断了31.63下一跳的网关是同一子网,而且是二层的传输,二层的传输又需要获取到目的的mac地址,如果它本地不知道31.63的mac地址的话,它会发送一个ARP广播包,知道了对方的mac就进行封包,所以经过二层的传输到达31.63,31.63收到之后数据包之后,它又会去判断路由表了,然后进入cni的网桥,二层又转发到了容器里面。

最重要两条,host-gw是把每个节点都当成一个网关,它会加入其他节点并设成网关,当数据包到达这个节点的时候,就根据路由表之间发送到下一跳了,也就是节点IP,这个都是同网段的IP,直接通过2层之间把这个数据,转发到另一个节点上,另一个节点再根据另一条规则,根据目的的地址转发到cni网桥,cni网桥根据2层又转发到容器里面,一个是数据的流入,就是当数据包到达这个节点之后,然后发给谁,这是流入数据包,一个是数据包的流出,当从节点出来的数据包,应该转发到哪个node上,这些都是由flannel去维护的
这个的局限是每个node在2层都能通,否则下一跳转发不过去,但是它的性能要比vxlan的性能高很多,不需要封包解封包,这种接近原生,性能也是最好的

下面是示意图:

kube-flannel.yml

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

看名字就能看出hots-gw它把目的的主机当作网关,直接路由原始的封包
将vxlan切换成host-gw的模式,重建之后可以看到路由表发生变化,切换的时候也会对网络进行影响,一般是在夜深人静的时候去做

之前的路由表都是通过flannel.1去转发到设备上,也就是使用host-gw,flannel.1这个设备就不用了,所以就不会用vxlan进行去封包了
当你设置flannel使用host-gw模式,flanneld会在宿主机上创建节点的路由表:

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 192.168.31.63 dev ens33
10.244.2.0/24 via 192.168.31.61 dev ens33
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 当中。

小结:
如果想追求性能的话,二层可以通信,那么就可以选择host-gw,那么如果两个节点之间是不能通过二层通信,那么可能需要路由的转发,那么可能在不同的vlan中,那么使用vxlan是最好的,因为可以满足这样的一个需求。

原文地址:https://blog.51cto.com/14143894/2462379

时间: 2024-11-07 14:53:09

Kubernetes网络组件之Flannel策略实践(vxlan、host-gw)的相关文章

Kubernetes网络组件之Calico策略实践初探(BGP、RR、IPIP)

Kubernetes网络方案之 Calico策略实践 案例:由于k8s集群部署之前的方案是flannel网络策略,所以这里将flannel策略切换成calico网络策略 Calico是一个纯三层的数据中心网络方案,Calico支持广泛的平台,包括Kubernetes.OpenStack等. Calico 在每一个计算节点利用 Linux Kernel 实现了一个高效的虚拟路由器( vRouter) 来负责数据转发,而每个 vRouter 通过 BGP 协议负责把自己上运行的 workload 的

kubernetes 网络组件简介

链接地址:https://blog.csdn.net/kjh2007abc/article/details/86751730 k8s的网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中.这是因为k8s出自Google,而在GCE里面是提供了网络模型作为基础设施的,所以k8s就假定这个网络已经存在.而在大家私有的平台设施里搭建k8s集群,就不能假定这种网络已经存在了.我们需要自己实现这个网络,将不同节点上的Docker容器之间的互相访问先打通,然后运行k8s. 目前已经有多个开源组件支

从零开始入门 K8s | Kubernetes 网络概念及策略控制

作者 |?阿里巴巴高级技术专家? 叶磊 一.Kubernetes 基本网络模型 本文来介绍一下 Kubernetes 对网络模型的一些想法.大家知道 Kubernetes 对于网络具体实现方案,没有什么限制,也没有给出特别好的参考案例.Kubernetes 对一个容器网络是否合格做出了限制,也就是 Kubernetes 的容器网络模型.可以把它归结为约法三章和四大目标. 约法三章的意思是:在评价一个容器网络或者设计容器网络的时候,它的准入条件.它需要满足哪三条? 才能认为它是一个合格的网络方案.

Flannel网络组件部署

在部署K8S之前,需要在集群服务器上部署CNI容器网络组件,从而实现集群的网络互联互通.目前可选的组件比较多,例如flannel.calico.weave等,各容器网络组件对比可参考文档:http://dockone.io/article/2599 本文介绍flannel网络组件的部署,配置环境在完成前文etcd集群和tls认证配置后.一.生成flannel证书文件 # mkdir flanneld # cd flanneld # cat flanneld-csr.json { "CN"

Calico网络策略实践

因为Kubernetes官方用的flannel无法实现多租户环境下的网络隔离,建立起来的pod之间实际可以相互访问,而Calico可以实现,因此周末找个时间试了一下大概的过程. 前面的kubernetes安装掠过 Calico安装 下载yaml文件 http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/hosted/calico.yaml http://docs.projectcalico.org/v

Kubernetes应用部署策略实践

几个概念: Pod:是Kubernetes最基本的部署调度单元,可以包含container,逻辑上表示某种应用的一个实例.比如一个web站点应用由前端.后端及数据库构建而成,这三个组件将运行在各自的容器中,那么我们可以创建包含三个container的pod. node: 是 Kubernetes的worker节点,通常也称作为Minion node.除了运行一些kubernetes的组件以外(kubelet, kube-proxy等),还承担着运行容器服务的重任. ReplicationCont

Kubernetes网络方案的三大类别和六个场景

欢迎访问网易云社区,了解更多网易技术产品运营经验. 本文章根据网易云资深解决方案架构师 王必成在云原生用户大会上的分享整理. 今天我将分享个人对于网络方案的理解,以及网易云在交付 Kubernetes 场景时的一些网络实践. 本文分为两部分: 第一部分:常见容器网络方案: 第二部分:网易云基于 VPC 深度集成的 Kubernetes 网络实践. 常见容器网络方案 常见容器网络方案分类   常见的容器网络方案可以从协议栈层级.穿越形态.隔离方式这三种形式进行划分. 协议栈层级: 第一种:协议栈二

超长干货丨Kubernetes网络快速入门完全指南

Kubernetes网络一直是一个非常复杂的主题.本文将介绍Kubernetes实际如何创建网络以及如何为Kubernetes集群设置网络. 本文不包括如何设置Kubernetes集群.这篇文章中的所有例子都将使用Rancher 2.0集群(其他平台也同样适用).即使你打算使用其他的公有云管理Kubernetes服务,也希望你对Kubernetes网络的工作原理有更好的了解. 如何使用Kubernetes网络  许多Kubernetes部署指南中包含了在K8S部署中部署Kubernetes网络C

盘点Kubernetes网络问题的4种解决方案

由于在企业中部署私有云的场景会更普遍,所以在私有云中运行Kubernetes + Docker集群之前,就需要自己搭建符合Kubernetes要求的网络环境.现在的开源世界里,有很多开源组件可以帮助我们打通Docker容器和容器之间的网络,实现Kubernetes要求的网络模型.当然每种方案都有自己适合的场景,我们要根据自己的实际需要进行选择. 一.Kubernetes + Flannel Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中,这在GCE(Goog