专业的编程技术博客社区

网站首页 > 博客文章 正文

Docker 容器网络番外篇-VxLan(docker的网络)

baijin 2024-11-16 17:05:36 博客文章 3 ℃ 0 评论

前言

前面的文章里,我们从Flannel的UDP实现里,知道UDP 后端实现会存在用户态与内核态的几次切换,导致性能下降,那有什么优化方案呢?在Flannel的后端中,也提供了 VxLan 的后端实现。

VxLan 协议

VxLan协议是 virtural eXtensiable Local Area Network的缩写,称为 虚拟可扩展的局域网,是一种overlay 的技术,通过在三层网络来搭建虚拟的二层网络,在 UDP协议上进行扩展。

VxLan 的技术是为了解决什么问题呢?我们先来了解下VLan 技术的协议内容,如下

在VLan协议中,主要是在扩展了链路层的协议,在来源地址字段与类型字段之前增加了VLan的相关信息,主要关心VID字段,与子网网段有关系(而这是解决局域网内,广播帧分割的关键点,后面可以展开,这里只需要记住,VLan是为了数据帧只影响范围内的机器),从这里可以看到这个字段是12位,总共是可以分配4096-2 个,对于小型网络来说,VLan是完全没有问题的,但如果是对于 SAAS的环境,像阿里云这样的大型SAAS虚拟网络提供商,那这种架构很快会被使用完,所以需要有一种机制可以解决该问题。

VxLan 是采用UDP 封装形式,通过VTEP 来完成VxLan的内容封装与解封功能。同样的,与二层VLan技术相似,VxLan用VNI来表示一个二层网络,长度为24位,解决了VLan 4096的限制,大概的数据报文如下:

从上面的协议中,可知VxLan协议会比较原始报文多50字节的内容,会降低网络链路传输有效数据的比例。

上述的数据解析是通过一个特殊的设备进行装包和解包的,这个设备叫做 VTEP(虚拟隧道端点),这会在每个节点上创建对应的agent。而它的作用和前面文章提到的 Flanneld 进程是类似的,但它是作为二层数据帧的数据封装与解封。最关键的是这个流程是完全在内核里完成的,这样就不会存在像在 Flannel 中以UDP方式实现时频繁在用户态与内核态之前切换的过程。

docker容器使用vxLan

Docker网络这样理解会更简单(二),我们在创建etcd中配置的Flannel 配置信息如下

etcdctl --endpoints http://192.168.136.128:2379 put /coreos.com/network/config '{"Network":"10.2.0.0/16","SubnetLen":24,"SubnetMin":"10.2.1.0","SubnetMax":"10.2.20.0","Backend":{"Type":"UDP"}}'

创建的是UDP后端,设备名称是 flannel0,这次我们来尝试创建一个后端类型为 VxLan的设备

etcdctl --endpoints http://192.168.136.128:2379 put /coreos.com/network/config '{"Network":"10.2.0.0/16","SubnetLen":24,"SubnetMin":"10.2.1.0","SubnetMax":"10.2.20.0","Backend":{"Type":"vxlan"}}'

启动 Flannel后,查看会多一个网络设备 flannel.1的路由

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         gateway         0.0.0.0         UG    100    0        0 ens33
10.2.5.0        0.0.0.0         255.255.255.0   U     0      0        0 docker0
10.2.14.0       10.2.14.0       255.255.255.0   UG    0      0        0 flannel.1
192.168.136.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33

现在在节点 NodeA 上的容器(10.2.5.2) 中访问 NodeB 上的容器 (10.2.14.2)

和前端UDP的流程类似,当访问 10.2.14.2 时,会先出现在 docker0 网桥,然后路由到本机的 flannel.1 设备进行处理。每当主机在启动 Flannel 网络之后,就会有多一条上面的路由信息,发住 10.2.14.0/24的 包,都会经过 flannel.1 设备出去,并会被发往 10.2.14.0 网关。而 10.2.14.0 正是 NodeB上的 VTEP 设备。

而这些VTEP 设备是要组成一个虚拟二层网络,通过二层数据帧进行通信的。

这里就需要获得目的 VTEP 设备的MAC地址,这时需要通过 ARP 表来获取MAC地址,而这个记录是 Flannel 进程在启动时,会将NodeB的数据自动添加到Node1上

[root@master flannel]# ip neigh show dev flannel.1
10.2.14.0 lladdr 1a:74:66:b8:f5:fb PERMANENT

说明 10.2.14.0 对应的 MAC地址是 1a:74:66:b8:f5:fb,这时候就会封装原始的二层包数据,但这个数据包在宿主机的网络里并不能进行传输,数据包如下:

所以,接下来还需要将以上数据再进行封装成宿主机可以处理的数据帧,再通过 eth0 进行传输。在拿到这些数据后,linux 内核会在上面的数据前面加上一个特殊的VxLan头部信息,而从上面的VxLan的协议里,可以知道有一个重要的字段叫做 VNI,它是VTEP设备识别某个数据帧是不是应该归该设备进行处理的依据。在Flannel里,VNI的值默认为1,所以在宿主机上的VTEP 设备都叫作 flannel.1 的原因了,之后 Linux内核把这个数据帧封装在UDP包里发出去。

从上面的分析中可以看出,flannel.1 在这里扮演的是网桥的角色,在二层网络进行UDP包的转发,在 linux中,网桥的转发信息,在 Forwarding Database中进行存储,可以通过 bridge fdb 进行查看,可以明确宿主机UDP包是要发往 NodeB了

[root@master flannel]# bridge fdb show flannel.1 | grep 1a:74:66:b8:f5:fb
1a:74:66:b8:f5:fb dev flannel.1 dst 192.168.136.128 self permanent

数据封包如下:UDP是一个四层数据包,需要在前面增加一个IP头,再在前面加上二层数据帧,即将NodeB的Mac地址进行填充(通过NodeA ARP学习)

数据拆包:在 Node2的 eth0 网卡拿到数据后,会发现数据帧里有 VxLan 头且VNI 是 1,则 Linux内核会进行对它拆包,根据 VNI的值,把它交给 NodeB 中的 flannel.1 设备,flannel.1 会取出对应的目的ip包,再通过 Node2上的网络栈,最后会进入到 NodeB的容器中

整个过程如下:

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表