KUbernetes Flannel:VXLAN模式

网友投稿 534 2022-09-07

KUbernetes Flannel:VXLAN模式

服务器网络架构

网络架构比较固定,都是大同小异。

K8s网络模型:Pod网络

Pod是K8s最小调度单元,一个Pod由一个容器或多个容器组成,当多个容器时,怎么都用这一个Pod IP?

实现:k8s会在每个Pod里先启动一个infra container小容器,然后让其他的容器连接进来这个网络命名空间,然后其他容器看到的网络就完全一样了。即网络设备、IP地址、Mac地址等。在Pod的IP地址就是infra container的IP地址。

K8s网络模型:Pod网络

在 Kubernetes 中,每一个 Pod 都有一个真实的 IP 地址,并且每一个 Pod 都可以使用此 IP 地址与 其他 Pod 通信。

Pod之间通信会有两种情况:

两个Pod在同一个Node上两个Pod在不同Node上

veth主要解决不同网络命名空间通信 docker0网桥主要解决同主机不同容器之间通信

引发的一些网络问题

1、谁来为每个节点分配一个网段,保障该节点上每个pod分配不一样的ip?

2、pod1怎么知道pod2在哪个节点?

3、知道了在哪个节点,怎么实现这个转发?

应对∶

1、提前规划好,做好记录

2、iptables、写静态路由

因此,为了实现容器跨主机通信需求,就需要部署网络组件,这些网络组件都必须满足如下要求:

一个Pod一个IP所有的 Pod 可以与任何其他 Pod 直接通信所有节点可以与所有 Pod 直接通信Pod 内部获取到的 IP 地址与其他 Pod 或节点与其通信时的 IP 地址是同一个

K8s网络模型: CNI(容器网络接口)

CNI(Container Network Interface,容器网络接口):是一个容器网络规范,Kubernetes网络采用的就是这个CNI规 范,负责初始化infra容器的网络设备。

CNI二进制程序默认路径:/opt/cni/bin/项目地址:Flannel 作为容器网络方案。

CNI配置文件默认路径:/etc/cni/net.d

当 kubelet 组件需要创建 Pod 的时候,先调用dockershim它先创建一个 Infra 容器。然后调用 CNI 插件为 Infra 容器配置网络。

这两个路径可在kubelet启动参数中定义:

--network-plugin=cni--cni-conf-dir=/etc/cni/net.d--cni-bin-dir=/opt/cni/bin

下面放置着CNI网络插件的二进制程序,通过这些程序完成与cni的对接

[root@k8s-master ~]# ls /opt/cni/bin/bandwidth dhcp flannel host-local loopback portmap sbr tuningbridge firewall host-device ipvlan macvlan ptp static vlan

CNI配置文件默认路径:/etc/cni/net.d

[root@k8s-master ~]# ls /etc/cni/net.d/10-flannel.conflist[root@k8s-master ~]# cat /etc/cni/net.d/10-flannel.conflist { "name": "cbr0", "cniVersion": "0.3.1", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": { "portMappings": true } } ]}

这里面就包含了配置内容

所以cni参数都是在kubelet上面配置的,以为它负责创建容器并且为其配置容器网络

CNI的配置是有下面三个参数,第一个就是启用cni网络插件,也就是k8s要使用cni就必须启用

简单说cni就是网络组件的接口,好让第三方的网络都能接入到k8s网络里面来

--network-plugin=cni--cni-conf-dir=/etc/cni/net.d--cni-bin-dir=/opt/cni/bin

Flannel

Flannel是由CoreOS开发的项目,是CNI插件早期的入门产品,简单易用。

Flannel使用Kubernetes集群的现有etcd集群来存储其状态信息,从而不必提供专用的数据存储,只需要在每个节点上运行flanneld来守护进程。

每个节点都被分配一个子网,为该节点上的Pod分配IP地址。

同一主机内的Pod可以使用网桥进行通信,而不同主机上的Pod将通过flanneld将其流量封装在UDP数据包中,以路由到适当的目的地。

封装方式默认和推荐的方法是使用VxLAN,因为它具有良好的性能,并且比其他选项要少些人为干预。虽然使用VxLAN之类的技术封装的解决方案效果很好,但缺点就是该过程使流量跟踪变得困难。

vxlan:如果一个数据包过来,要发出去,比如你是TCP的请求,这个请求要往外发,在你原始的数据包发出去之前,在你的包之上再加上一层udp的包头,所谓的flannel就是这样一个插件。

运行在每个节点,由container runtime去调用,flanneld会在每个节点上创建vxlan的设备,所有要去转发的包都需要经过vxlan的设备去做封装,会在原始的TCP的包头上面再加上udp的包,那么这个包就变为了vxlan的包。

加的最外层udp的包原始地址和目标地址就会是容器运行主机的这个地址,也就是宿主机的地址。那么外层包变为了主机的地址,那么就可以在不同节点传输了。

vxlan是overlay的技术,就是在原始数据包上面再加一个包头,这个包传到对端要去做一次额外的解包,在内核处理这些数据包的时候,就多了额外的封包和解包的过程,那么它的整个效率就不会很高。

可能小型的网络,对这种性能要求不高的场景下面用的比较多,但是要追求性能的时候,用的就没有那么广泛了。

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

这句话体现的几点:守护进程使用存储etcd来pod子网和nodeip之前关系,使用ETCD存储子网提供全局的IP

项目地址: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan" }}

使用的是deamonset部署的

apiVersion: apps/v1kind: DaemonSetmetadata: name: kube-flannel-ds-amd64 namespace: kube-system

在部署之前需要做的事情

10.244.0.0/16 这是一个大的子网,会确保每个node都分配到独立的网段

• Network:指定Pod IP分配的网段,与controller-manager配置的保持一样

--allocate-node-cidrs=true--cluster-cidr=10.244.0.0/16

• kubeadm部署:/etc/kubernetes/manifests/kube-controller-manager.yaml

• 二进制部署:/opt/kubernetes/cfg/kube-controller-manager.conf

我这里部署集群默认是配置好了,就不需要修改了

[root@k8s-master ~]# vim /etc/kubernetes/manifests/kube-controller-manager.yaml - command: - kube-controller-manager - --allocate-node-cidrs=true - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf - --bind-address=127.0.0.1 - --client-ca-file=/etc/kubernetes/pki/ca.crt- --cluster-cidr=10.244.0.0/16[root@k8s-master ~]# cat /opt/kubernetes/cfg/kube-controller-manager.conf KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \--v=2 \--log-dir=/opt/kubernetes/logs \--leader-elect=true \--master=127.0.0.1:8080 \--bind-address=127.0.0.1 \--allocate-node-cidrs=true \--cluster-cidr=10.244.0.0/16 \--service-cluster-ip-range=10.0.0.0/24 \--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \--root-ca-file=/opt/kubernetes/ssl/ca.pem \--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \--experimental-cluster-signing-duration=87600h0m0s"

如果部署了calico那么先删除,在一个k8s网络当中只能使用一个网络组件

[root@k8s-master ~]# kubectl delete -f calico.yaml [root@k8s-master ~]# rm -f /etc/cni/net.d/10-calico.conflist /etc/cni/net.d/calico-kubeconfig [root@k8s-master ~]# kubectl apply -f kube-flannel.yml [root@k8s-master ~]# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGEkube-flannel-ds-amd64-lb6vm 1/1 Running 0 139dkube-flannel-ds-amd64-lxxdq 1/1 Running 0 139dkube-flannel-ds-amd64-vl4fn 1/1 Running 0 139d

K8s网络组件之Flannel:工作模式

Flannel支持多种工作模式:

UDP:最早支持的一种方式,由于性能最差,目前已经弃用。VXLAN:Overlay Network方案,源数据包封装在另一种网络包里面进行路由转发和通信 Host-GW:Flannel通过在各个节点上的Agent进程,将容器网络的路由信息写到主机的路由表上,这样一来所有的主机都有整个容器网络的路由数据了。Directrouting:同时支持VXLAN和Host-GW工作模式公有云VPC:ALIYUN,AWS

总结来说也就两种,一种路由方案(基于现有的宿主机作为路由器来使用,负责数据包的转发),一种隧道方案(overlay)。

K8s网络组件之Flannel:VXLAN模式

VXLAN介绍

VXLAN,即 Virtual Extensible LAN(虚拟可扩展局域网),是 Linux 内核本身就支持的一种网络虚似化技术。VXLAN 可以完全在内核态实现上述封装和解封装的工作,从而通过与前面相似的“隧道”机制,构建出覆盖网络(Overlay Network)。

VXLAN的覆盖网络设计思想:在现有的三层网络之上,覆盖一层二层网络,使得连接在这个VXLAN 二层网络上的主机之间,可以像在同一局域网里通信。为了能够在二层网络上打通“隧道”,VXLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备就叫作 VTEP,即:VXLAN Tunnel End Point(虚拟隧道端点)。

隧道模式内部自己实现了封装方式,VETP设备用于封包和解包

VTEP设备进行封装和解封装的对象是二层数据帧,这个工作是在Linux内核中完成的。

Flannel工作逻辑图如下:

[root@k8s-master ~]# ifconfigcni0: flags=4163 mtu 1450 inet 10.244.0.1 netmask 255.255.255.0 broadcast 10.244.0.255 inet6 fe80::ec98:8bff:fea1:554d prefixlen 64 scopeid 0x20 ether ee:98:8b:a1:55:4d txqueuelen 1000 (Ethernet) RX packets 35973 bytes 9023583 (8.6 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 40472 bytes 28071561 (26.7 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0docker0: flags=4099 mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:b9:2e:09:e2 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0ens33: flags=4163 mtu 1500 inet 192.168.179.99 netmask 255.255.255.0 broadcast 192.168.179.255 inet6 fe80::54c7:3ae8:3659:6b97 prefixlen 64 scopeid 0x20 ether 00:0c:29:b4:88:32 txqueuelen 1000 (Ethernet) RX packets 5674009 bytes 2565682866 (2.3 GiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 6213197 bytes 4945068979 (4.6 GiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0flannel.1: flags=4163 mtu 1450 inet 10.244.0.0 netmask 255.255.255.255 broadcast 0.0.0.0 inet6 fe80::2027:5aff:fef0:9316 prefixlen 64 scopeid 0x20 ether 22:27:5a:f0:93:16 txqueuelen 0 (Ethernet) RX packets 3604 bytes 2986402 (2.8 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 2830 bytes 585691 (571.9 KiB) TX errors 1 dropped 8 overruns 0 carrier 1 collisions 0vethf5cad454: flags=4163 mtu 1450 inet6 fe80::6401:bbff:fe31:76bd prefixlen 64 scopeid 0x20 ether 66:01:bb:31:76:bd txqueuelen 0 (Ethernet) RX packets 6 bytes 509 (509.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 13 bytes 1000 (1000.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

[root@k8s-master ~]# ip route10.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.10,那么就会走这个路由表10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink 这个路由表的下一条是 10.244.1.0 flannel.1: flags=4163 mtu 1450 inet 10.244.0.0

K8s网络组件之Flannel

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

项目地址: 数据包已经到达了宿主机上面,宿主机上面的网络协议栈可以看到这个数据包的,所以会根据路由表转发到flannel.1这张虚拟网卡,也即是来到了隧道的入口

[root@k8s-master ~]# ip route10.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.10,那么就会走这个路由表10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink 这个路由表的下一条是 10.244.1.0 flannel.1: flags=4163 mtu 1450 inet 10.244.0.0

这样数据包来到宿主机查看宿主机上面的路由表发到下一跳即flannel.1设备

flannel.1设备这个设备是完成vetp这个设备封装的,就相当于隧道的入口,之后就要使用xvlan对其进行封装,封装之后再走宿主机上面的网络,这里数据的封包是二层的

封装包必须要有目标的mac地址

flannel.1就是vetp设备,基于二层去封装,那么必须知道目标mac地址是谁,这里源IP目标IP都知道

查看这个网卡的arp信息,这两个就是地址就是另外两台机器上面的 flannel.1 mac地址

[root@k8s-master ~]# kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESkubia-859d757f8c-74g6s 1/1 Running 0 124d 10.244.2.4 k8s-node2 kubia-859d757f8c-97znt 1/1 Running 0 124d 10.244.0.14 k8s-master kubia-859d757f8c-9mjf9 1/1 Running 0 124d 10.244.1.5 k8s-node1 [root@k8s-master ~]# ifconfig flannel.1: flags=4163 mtu 1450 inet 10.244.0.0[root@k8s-node1 ~]# ifconfig flannel.1: flags=4163 mtu 1450 inet 10.244.1.0[root@k8s-node2 ~]# ifconfigflannel.1: flags=4163 mtu 1450 inet 10.244.2.0其实在flanneld进程启动后,就会自动添加其他节点ARP记录,可以通过ip neigh show dev flannel.1命令查看[root@k8s-master ~]# ip neigh show dev flannel.110.244.2.0 lladdr 4a:5a:f0:f5:19:5e PERMANENT10.244.1.0 lladdr b6:68:f7:5e:af:9c PERMANENT这个走的是二层的[root@k8s-master ~]# bridge fdb show dev flannel.1b6:68:f7:5e:af:9c dst 192.168.179.100 self permanent4a:5a:f0:f5:19:5e dst 192.168.179.101 self permanent

找到宿主机的IP就可以向这个宿主机发送UDP的数据包

K8s网络组件之Flannel:VXLAN模式

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

1.容器路由: 容器根据路由表,将数据包发送下一跳10.244.0.1,从eth0网卡出。可以使用ip route命令查看路由表

[root@k8s-master ~]# kubectl exec -it dns-test sh/ # ip routedefault via 10.244.0.1 dev eth0 10.244.0.0/24 dev eth0 scope link src 10.244.0.17 10.244.0.0/16 via 10.244.0.1 dev eth0

2.主机路由:数据包进入到宿主机虚拟网卡cni0,根据路由表转发到flannel.1虚拟网卡,也就是来到了隧道的入口。

10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink # 凡是发往10.244.2.0/24网段的数据包,都需要经过flannel.1设备发出,并且下一跳是10.244.2.0,即Node2 VTEP设备flannel.1。

[root@k8s-master ~]# ip routedefault via 192.168.111.2 dev eno16777736 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 neigh show dev flannel.1命令查看。

[root@k8s-master ~]# ip neigh show dev flannel.110.244.1.0 lladdr aa:f8:47:ae:13:4b PERMANENT10.244.2.0 lladdr ae:30:2e:1a:b3:72 PERMANENT

4.二次封包:知道了目的MAC地址,Linux内核就可以进行二层封包了。但是,对于宿主机网络来说这个二层帧并不能在宿主机二层网络里传输。所以接下来,Linux内核还要把这个数据帧进一步封装成为宿主机网络的一个普通数据帧,好让它载着内部数据帧,通过宿主机的eth0网卡进行传输。 数据格式如下图:

5.封装到UDP包发出去:在封装成宿主机网络可传输的数据帧时,还缺少目标宿主机MAC地址,也就是说这个UDP包该发给哪台宿主机呢?flanneld进程也维护着一个叫做FDB的转发数据库,可以通过bridge fdb show dev flannel.1命令查看。可以看到,上面用的对方flannel.1的MAC地址对应宿主机IP,也就是UDP要发往的目的地。所以使用这个目的IP与MAC地址进行封装。

6.数据包到达目的宿主机: 接下来,就是宿主机与宿主机之间通信了, 数据包从Node1的eth0网卡发出去,Node2接收到数据包,解封装发现是VXLAN数据包,把它交给flannel.1设备。flannel.1设备则会进一步拆包,取出原始IP包(源容器IP和目标容器IP),通过cni0网桥二层转发给容器。

可以看到在flannel vetp设备里面看到的是原始的数据包

[root@k8s-master ~]# kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESdns-test 1/1 Running 5 118d 10.244.0.17 k8s-master nginx 1/1 Running 0 3m 10.244.2.8 k8s-node2 / # ping 10.244.2.8PING 10.244.2.8 (10.244.2.8): 56 data bytes64 bytes from 10.244.2.8: seq=0 ttl=62 time=0.924 ms64 bytes from 10.244.2.8: seq=1 ttl=62 time=2.803 ms64 bytes from 10.244.2.8: seq=2 ttl=62 time=0.693 ms^C--- 10.244.2.8 ping statistics ---3 packets transmitted, 3 packets received, 0% packet lossround-trip min/avg/max = 0.693/1.473/2.803 ms[root@k8s-node2 ~]# tcpdump -i flannel.1 -nntcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on flannel.1, link-type EN10MB (Ethernet), capture size 262144 bytes09:55:59.936783 IP 10.244.0.17 > 10.244.2.8: ICMP echo request, id 6656, seq 0, length 6409:55:59.936832 IP 10.244.2.8 > 10.244.0.17: ICMP echo reply, id 6656, seq 0, length 6409:56:00.941898 IP 10.244.0.17 > 10.244.2.8: ICMP echo request, id 6656, seq 1, length 6409:56:00.941966 IP 10.244.2.8 > 10.244.0.17: ICMP echo reply, id 6656, seq 1, length 6409:56:01.942700 IP 10.244.0.17 > 10.244.2.8: ICMP echo request, id 6656, seq 2, length 6409:56:01.942767 IP 10.244.2.8 > 10.244.0.17: ICMP echo reply, id 6656, seq 2, length 64

可以看到是overylay的网络,可以看到宿主机的IP,内部IP也即是容器IP,并且是overylay的网络。

[root@k8s-node2 ~]# tcpdump udp -i eno16777736 -nntcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes10:00:34.073167 IP 192.168.111.3.53527 > 192.168.111.5.8472: OTV, flags [I] (0x08), overlay 0, instance 1IP 10.244.0.17 > 10.244.2.8: ICMP echo request, id 6912, seq 0, length 6410:00:34.073255 IP 192.168.111.5.42769 > 192.168.111.3.8472: OTV, flags [I] (0x08), overlay 0, instance 1IP 10.244.2.8 > 10.244.0.17: ICMP echo reply, id 6912, seq 0, length 6410:00:35.083230 IP 192.168.111.3.53527 > 192.168.111.5.8472: OTV, flags [I] (0x08), overlay 0, instance 1IP 10.244.0.17 > 10.244.2.8: ICMP echo request, id 6912, seq 1, length 6410:00:35.083503 IP 192.168.111.5.42769 > 192.168.111.3.8472: OTV, flags [I] (0x08), overlay 0, instance 1IP 10.244.2.8 > 10.244.0.17: ICMP echo reply, id 6912, seq 1, length 64

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:广告情报局:OPPO同学录,好好说再见!
下一篇:Kubernetes 组件安全 CIS基准以及kube-beach使用
相关文章

 发表评论

暂时没有评论,来抢沙发吧~