【Docker】vxlan的原理与实验

VXLAN(Virtual eXtensible Local Area Network,虚拟可扩展局域网),是一种虚拟化隧道通信技术。它是一种Overlay(覆盖网络)技术,通过三层的网络来搭建虚拟的二层网络。

VXLAN介绍

VXLAN是在底层物理网络(underlay)之上使用隧道技术,借助UDP层构建的Overlay的逻辑网络,使逻辑网络与物理网络解耦,实现灵活的组网需求。它对原有的网络架构几乎没有影响,不需要对原网络做任何改动,即可架设一层新的网络。也正是因为这个特性,很多容器的网络才会选择VXLAN作为通信网络。

VXLAN不仅支持一对一,也支持一对多,一个VXLAN设备能通过像网桥一样的学习方式学习到其他对端的IP地址,还可以直接配置静态转发表。

VXLAN基本概念

  • VNI(VXLAN Network Identifier,VXLAN网络标识符):VXLAN通过VXLAN ID来标识,其长度为24比特。一般每个VNI对应一个租户,也就是说使用VXLAN理论上可以支撑千万级别的租户。

  • VTEP(VXLAN Tunnel End Point,VXLAN隧道端点):VXLAN网络的边缘设备,用来进行VXLAN报文的处理(封包和解包)。VXLAN的相关处理都在VTEP上进行,例如识别以太网数据帧所属的VXLAN、基于VXLAN对数据帧进行二层转发、封装/解封装报文等。VTEP可以是一台独立的物理设备,也可以是虚拟机所在服务器的虚拟交换机。

  • VXLAN Tunnel:两个VTEP之间点到点的逻辑隧道。VTEP为数据帧封装VXLAN头、UDP头、IP头后,通过VXLAN隧道将封装后的报文转发给远端VTEP,远端VTEP对其进行解封装。隧道是一个逻辑上的概念,在VXLAN模型中并没有具体的物理实体向对应。隧道可以看做是一种虚拟通道,VXLAN通信双方认为自己是在直接通信,并不知道底层网络的存在。从整体来说,每个VXLAN网络像是为通信的虚拟机搭建了一个单独的通信通道,也就是隧道。

    上图所示为VXLAN的工作模型,它创建在原来的IP网络(三层)上,只要是三层可达(能够通过IP相互通信)的网络就能部署 VXLAN。在VXLAN网络的每个端点都有一个VTEP设备,负责VXLAN协议报文的解包和封包,也就是在虚拟报文上封装VTEP通信的报文头部。

物理网络上可以创建多个VXLAN网络,可以将这些VXLAN网络看成一个隧道,不同节点上的虚拟机/容器能够通过隧道直连。通过VNI标识不同的VXLAN网络,使得不同的VXLAN可以相互隔离。

VXLAN的报文格式

VXLAN Header:在原始二层帧的前面增加8字节的VXLAN的头部,其中最主要的是VNID,占用3个字节(即24bit),类似VLAN ID,可以具有2^24个网段。

UDP Header:在VXLAN和原始二层帧的前面使用8字节UDP头部进行封装(MAC IN UDP),目的端口号缺省使用4789,源端口按流随机分配(通过MAC,IP,四层端口号进行hash操作),这样可以更好的做ECMP。

在上面添加的二层封装之后,再添加底层网络的IP头部(20 字节)和MAC头部(14 字节),这里的IP和MAC是宿主机的IP地址和 MAC地址。

VXLAN通讯过程

总的来说,VXLAN报文的转发过程就是:原始报文经过VTEP,被VTEP添加上VXLAN头部以及外层的UDP头部,再发送出去,对端 VTEP接收到VXLAN报文后拆除外层UDP头部,并根据VXLAN头部的VNI把原始报文发送到目的服务器。但这里有一个问题,第一次通信前双方如何知道所有的通信信息?这些信息包括:

  • 哪些VTEP需要加到一个相同的VNI组?
  • 发送方虚拟机怎么知道对方的MAC地址?
  • VTEP怎么知道目的虚拟机在哪一台宿主机上?

这三个问题可以归结为同一个问题:VXLAN网络怎么感知彼此的存在并选择正确的路径传输报文?

第一个问题简单,VTEP通常由网络管理员来配置。要回答后面两个问题,还得回到VXLAN协议的报文上,看看一个完整的VXLAN报文需要哪些信息:

  • 内层报文:通信双方的IP地址已经明确,只需要VXLAN填充对方的MAC地址,因此需要一个机制来实现ARP功能。
  • VXLAN头部:只需要知道VNI。一般直接配置在VTEP上,要么提前规划,要么根据内层报文自动生成。
  • UDP头部:需要知道源端口和目的端口,源端口由系统自动生成,目的端口默认是4789。
  • IP头部:需要知道对端VTEP的IP地址,这个是最关键的部分。

实际上,VTEP也会有自己的转发表,转发表通过泛洪和学习机制来维护,对于目标MAC地址在转发表中不存在的未知单播,广播流量,都会被泛洪给除源VTEP外所有的VTEP,目标VTEP响应数据包后,源VTEP会从数据包中学习到MAC,VNI和VTEP的映射关系,并添加到转发表中,后续当再有数据包转发到这个MAC地址时,VTEP会从转发表中直接获取到目标VTEP地址,从而发送单播数据到目标VTEP。

点对点的VXLAN通信

点对点的VXLAN通信,在这个实验中使用两台虚拟机构成一个VXLAN网络,每台机器的网卡作为vtep,通过设置的ip互相通信。

主机规划:

  • node1:172.20.160.13/20
  • node2:172.20.161.221/20

实验结构图如下图所示。

对于,两台主机的网卡之间的通信,如果不使用vxlan,就需要设置路由表,此时两个网卡的ip不能是同一个网段。接下来,进行点对点的vxlan的通信。

在node1上创建一个名字为vxlan-ethd,类型为vxlan的网卡,后面是vxlan-ethd网卡需要的参数:

  • id 1:指定VNI的值,这个值可以在1到2^24之间
  • dstport:vtep通信的端口
  • remote 172.20.161.221:对方vtep的地址,类似于点对点协议
  • local 172.20.160.13:当前节点vtep要使用的IP地址
shell 复制代码
$ sudo ip link add vxlan-ethd type vxlan id 1 dstport 4789 remote 172.20.161.221 local 172.20.160.13

启动vxlan-ethd网卡并为其分配IP;

shell 复制代码
$ sudo ip link set vxlan-ethd up
$ sudo ip addr add 10.0.1.1/24 dev vxlan-ethd

在node2上也进行同样的操作:

shell 复制代码
$ sudo ip link add vxlan-ethd type vxlan id 1 dstport 4789 remote 172.20.160.13 local 172.20.161.221
$ sudo ip link set vxlan-ethd up
$ sudo ip addr add 10.0.1.2/24 dev vxlan-ethd

接下来,这两个位于不同虚拟机上的网卡就可以通过vxlan隧道进行通信了,在node1中尝试访问node2的10.0.1.2

shell 复制代码
$ ping -I 10.0.1.1 10.0.1.2 -c 3
PING 10.0.1.2 (10.0.1.2) from 10.0.1.1 : 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=0.899 ms
64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=0.934 ms
64 bytes from 10.0.1.2: icmp_seq=3 ttl=64 time=1.53 ms

--- 10.0.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2022ms
rtt min/avg/max/mdev = 0.899/1.124/1.539/0.293 ms

跨主机的容器通信

上面最简单的点对点VXLAN实验只是个简单的演示,没有太多实际工程意义,本节用容器通信来演示一个更加完整的场景。

场景描述:在node1和node2上各部署一个docker容器,默认情况下,一个容器宿主机上的容器能够直接用私网IP地址通信,因为它们利用一个网桥接在一起。而不同宿主机上的容器无法直接用私网IP地址通信。使用自建的vxlan网络接口,来打通不同宿主机上容器,让它们可以直接利用内网IP通信。

准备容器

在node1上创建app1容器,指定IP为172.18.0.2:

shell 复制代码
$ sudo docker network create --subnet 172.18.0.0/16 my-network
04a3be456f01099cb18818fa50804cc69a359ee77ba8d8d3e3bb12cf06e52434

$ sudo docker container run -d --rm --name app1 --network my-network --ip 172.18.0.2 busybox ping 8.8.8.8
c7fbfe06fb871d88d3fc9224636c25da78d61cf8aaa98b87df65403e771437be

在node2上创建app2容器,指定IP为172.18.0.3:

shell 复制代码
$ sudo docker network create --subnet 172.18.0.0/16 my-network
09fb688212d956ebbb5e775f8d8847d9cf2705c7ed96127dc411648383ba839f

$ sudo docker container run -d --rm --name app2 --network my-network --ip 172.18.0.3 busybox ping 8.8.8.8
745c98439680ecc9ef97b02aabda3dcc8fb19bd76f73b2e79d9134f858b17fbd

在node1中的容器app1上访问node2中的容器app2,和预期一致,是无法ping通的:

shell 复制代码
$ sudo docker container exec -it app1 ping -c 3 172.18.0.3
PING 172.18.0.3 (172.18.0.3): 56 data bytes

--- 172.18.0.3 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

创建VXLAN接口接入docker网桥

在两个容器宿主机上各创建一个VXLAN接口,并且将VXLAN接口接入docker网桥的端口上,如下图:

有了VXLAN接口的连接后,从node1上容器app1发出的包到达docker网桥后,可以从网桥的VXLAN接口出去,从而报文在VETP(VXLAN接口)处被封装成VXLAN报文,再从物理网络上到达对端VETP所在的主机node2。对端VTEP能正确解包VXLAN报文的话,随后即可将报文通过node2上的docker网桥送到上层的docker容器app2中。

在node1上配置如下:

shell 复制代码
$ sudo ip link add vxlan_docker type vxlan id 200 remote 172.20.161.221 dstport 4789 dev eth0

$ sudo ip link set vxlan_docker up

$ sudo brctl addif br-04a3be456f01 vxlan_docker

在node2上配置如下:

shell 复制代码
$ sudo ip link add vxlan_docker type vxlan id 200 remote 172.20.160.13 dstport 4789 dev eth0

$ sudo ip link set vxlan_docker up

$ sudo brctl addif br-09fb688212d9 vxlan_docker

此时再在node1中的容器app1上访问node2中的容器app2,结果如下,ping可以通。

shell 复制代码
$ sudo docker container exec -it app1 ping -c 3 172.18.0.3
PING 172.18.0.3 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=1.841 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.562 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=1.615 ms

--- 172.18.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.562/1.339/1.841 ms

FDB表

FDB(Forwarding Database entry,即转发表)是Linux网桥维护的一个二层转发表,用于保存远端虚拟机/容器的MAC地址,远端VTEP IP,以及VNI的映射关系,可以通过bridge fdb命令来对FDB表进行操作:

shell 复制代码
$ sudo bridge fdb
02:42:ac:12:00:03 dev vxlan_docker master br-e4fbde69f952
ca:d7:ea:37:0a:b2 dev vxlan_docker vlan 1 master br-e4fbde69f952 permanent
ca:d7:ea:37:0a:b2 dev vxlan_docker master br-e4fbde69f952 permanent
00:00:00:00:00:00 dev vxlan_docker dst 172.20.161.221 via eth0 self permanent
02:42:ac:12:00:03 dev vxlan_docker dst 172.20.161.221 self
33:33:00:00:00:01 dev br-e4fbde69f952 self permanent
01:00:5e:00:00:01 dev br-e4fbde69f952 self permanent
02:42:f7:03:fb:17 dev br-e4fbde69f952 vlan 1 master br-e4fbde69f952 permanent
02:42:f7:03:fb:17 dev br-e4fbde69f952 master br-e4fbde69f952 permanent
相关推荐
问简3 小时前
docker 镜像相关
运维·docker·容器
Benszen4 小时前
Docker容器化技术实战指南
运维·docker·容器
Hommy884 小时前
【开源剪映小助手】Docker 部署
docker·容器·开源·github·aigc
斯普信云原生组6 小时前
Prometheus 环境监控虚机 Redis 方案(生产实操版)
运维·docker·容器
喵了几个咪6 小时前
如何在 Superset Docker 容器中安装 MySQL 驱动
mysql·docker·容器·superset
工具罗某人6 小时前
docker compose部署kafka集群搭建
docker·容器·kafka
开心码农1号8 小时前
k8s中service和ingress的区别和使用
云原生·容器·kubernetes
L1624769 小时前
Kubernetes 完整学习手册(1 主多从 + 纯 YAML 部署 + 访问原理)
学习·容器·kubernetes
TE-茶叶蛋9 小时前
ThinkPHP入门
php