前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >容器网络的跨宿主机通信

容器网络的跨宿主机通信

原创
作者头像
智零办法就是多
修改2022-11-02 09:29:18
1.6K0
修改2022-11-02 09:29:18
举报
文章被收录于专栏:技术私享会技术私享会

容器的跨宿主机通信

通过第一章容器网络基础的学习,我们已经实现了单机容器间的互通、容器访问外部网络及容器对外提供服务。 在实际的应用场景中,为了保证业务的高可用性,我们的容器多是跨宿主机部署的,并且部署在不同宿主机上的容器会进行大量的网络通信。那么,怎么实现容器的跨宿主机通信呢?

如果熟悉网络的同学,那么一定知道解决这个问题的思路:

  1. 思路1:通过配置宿主机和容器集群的路由,实现underlay网络的打通。
  2. 思路2:把所有的容器连接在虚拟网络上,通过overlay方案实现互通。

方案1 underlay网络方案

方案2 voerlay网络方案

在社区中,用于解决跨主机通信的方案主要有以下几种:

  1. Docker 原生的overlay 和 macvlan。可参考:https://docs.docker.com/network/
  2. 第三方方案,比较常见的有flannel和calico。

1 Flannel+Docker部署及配置

我们通过Flannel项目来探讨容器的跨主机网络通信原理。Flannel项目是CoreOS公司主推的overlay容器网络方案。事实上,Flannel项目本身只是一个框架,真正为我们提供网络功能的,是Flannel的后端实现。目前,主要支持四种后端,分别是:

  1. UDP。仅限于调试,诞生时间比较早,当时linux内核不支持VXLAN。因性能差,现在已经被淘汰。
  2. VXLAN。社区推荐的选择。
  3. host-gw。对于网络有极高性能要求时,基础设施能支撑,且有丰富经验的使用者,推荐使用host-gw。(在云中无法使用)。
  4. 其他后端,如知名云平台。

为了便于理解原理,我们先用2台host搭建一个Docker+Flannel。具体可参考:https://www.cnblogs.com/hukey/p/14296710.html

我们自己环境信息如下

host1,OS:centos 7.9,IP:10.0.70.44,作为master节点。

host2,OS:centos 7.9,IP:10.0.70.36。

注:配置flannel时,我们为容器设置的是172.18.0.0/16的网段,选用的type是vxlan。

2. Flannel VxLAN原理浅析

我们在两台宿主机host1和host2上,分别运行busybox容器,命名为container-1,container-2.

代码语言:javascript
复制
#host1
$ docker run -d -it --name container-1 busybox /bin/sh
#host2
$ docker run -d -it --name container-2 busybox /bin/sh

接下来,我们在container-1来访问container-2的IP地址,发现2个容器的网络已经连通,这正是由部署在宿主机上的flannel进程帮我们做到的。

代码语言:javascript
复制
# host1 
$ docker exec -it container-1 /bin/sh
$ ping 172.18.28.2

我们通过上图对container1访问container2的流程进行分析。

container-1到docker0

当container-1访问container-2时,container-1的进程发起请求,container-1的源IP地址为172.18.57.2,目的地址为container-2的IP地址172.18.28.2。由于目的IP地址172.18.28.2并不在host1的docker0网桥的网段(172.18.57.0/24)里,所以这个IP包会被转发给默认路由规则,通过容器的网关docker0网桥(如果是同一台宿主机上的容器间通信,走的是直连规则,见上一章节),从而出现在宿主机上。

docker0到flannel.1

这个时候,这个IP包的下一个目的地,就取决于宿主机上的路由规则了,查看宿主机host1路由规则。通过最长匹配原则可知,前往目的地172.18.28.2的IP包,进入了一个叫flannel.1的设备。

实际上,flannel.1是一个VTEP设备。VTEP是什么?

我们首先来看一下VXLAN协议,VXLAN是Virtual eXtensible Local Area Network的缩写,RFC 7348的标题“A Framework for Overlaying Virtualized Layer 2 Networks over Layer 3 Networks”,说明了VXLAN是一个在传统Layer 3网络上架设出来的Layer 2 overlay网络

在下面的场景中,有2台服务器Server 1和Server 2,由3层网络连接。这2台服务器可能不在一个机架,甚至间隔很远的数据中心。有条个VXLAN隧道,标识分别是VNI 22, 34, 74,98。 注意看Server 1的 VM1-1和Server 2 VM2-4这2台机器,他们属于同一个VxLAN隧道,标识为VNI 22,两台机器可以互通,也就是我们常说的,他们处于同一个大二层网络中。事实上,对于linux机器来讲,他并不知道overlay网络,也不知道VXLAN报文的封装和解封装过程,因为这些过程都是由VTEP来完成。

所以,VTEP的功能就是负责VXLAN的封装和解封装。值得一提的是,VTEP的工作过程,全部是在内核态完成的。(这有什么好处?稍后会介绍)

flannel.1处理流程

介绍完VxLAN的基本原理和概念,我们来继续分析一下container-1访问container-2的整个流程。

前面我们介绍,container-1访问container-2的路由,经过docker0网桥,来到了VTEP设备 flannel.1,也就是VxLAN隧道的入口。

VTEP设备对原始报文进行封装,为了能够将原始报文发送到正确的宿主机,VXLAN需要知道对端VTEP设备(也就是宿主机2的VTEP设备flannel.1)信息,正是在每台机器上的flanneld进程负责维护。在host2启动并加入Flannel网络之后,在host1上,通过ip route查看路由规则会发现,flanneld添加了如下一条规则:172.18.0.0/16 dev flannel.1.

这条规则的意思是:凡是发往172.18.0.0/16网段的数据包,都要经过flannel.1设备发出。回想VXLAN原理,在3层网络上假设出来的2层网络,那就意味着,我们需要知道目的端VTEP设备的MAC地址

根据前面的路由信息,我们已经知道了目的端VTEP的IP地址,可以通过ARP(Address Resolution Protocol)根据3层IP地址来查询对应的2层MAC地址。而这里用到的ARP记录,是flanneld进程在host2节点启动时,自动添加到host1上的。我们可以通过ip命令查看,可以看到172.18.28.0对应的MAC地址为56:63:6a:db:6c:b1。

那么问题又来了,目的端VTEP的IP地址host1是如何知道的?

这里,就用到了Flannel项目非常重要的概念:子网(Subnet)。大家应该记得,我们在安装Flannel时,有设置过子网,我们设置的子网范围为172.18.0.0/16网段。在我们的例子中,分配给host1的子网为172.18.57.0/24,分配给host2的子网为172.18.28.0/24.在flannel管理的容器网络中,一台宿主机的所有容器,都属于该宿主机被分配的一个子网。在我们的环境中,可以通过如下命令查看

代码语言:javascript
复制
$ etcdctl ls /atomic.io/networks/subnets

综上所述,flanneld进程在处理由flannel.1传入的IP包时,就根据目的IP地址(172.18.28.2)匹配到对应子网(172.18.28.0/24),从etcd中找到这个子网对应的宿主机IP地址,10.0.70.36.可通过执行如下命令查看。

代码语言:javascript
复制
$ etcdctl get /atomic.io/network/subnets/172.18.28.0-24

而对于 flanneld 来说,只要 host1 和 host2 是互通的,那么 flanneld 作为 host1 上的一个普通进程,就一定可以通过上述 IP 地址(10.0.70.36)访问到 host2.

好了,我们继续前面的话题。有了目的VTEP的MAC地址后,linux内核就开始封装2层报文了,将目的VTEP的MAC地址填入inner Ethernet Header字段,目的容器的地址,填入Inner IP Header字段,依然是container-2的IP地址,即172.18.28.2,这个二层桢(为了方便,我们叫它vxlan数据帧)的格式如下:

需要注意的是,这些VTEP设备的MAC地址,对于宿主机并没有实在意义,也不能在宿主机的二层网络里传输。所以接下来,宿主机内核会把前面的vxlan数据帧进一步封装成为一个宿主机网络里的一个普通数据帧,好让他载着vxlan数据帧,通过宿主机的eth0网卡进行传输。

宿主机先给vxlan数据帧加一个特殊的VXLAN头,表明该数据帧是VXLAN要是用的数据帧,里面有一个重要的标志是VNI。在Flannel中,VNI默认值是1,所以宿主机上的VTEP设备叫做flannel.1,这里的1就是VNI的值。

然后,宿主机会把报文封装进一个UDP的包里面发出去。在宿主机看来,会认为是自己的flannel.1设备向另一台宿主机的falnnel.1设备发起的一次普通的UDP连接。

源端flannel.1知道了目的端flannel.1的MAC地址,却不知道目的端宿主机IP地址,那么这个UDP的数据包发往哪台宿主机呢?在linux内核里,网桥的转发的依据来自于FDB(Forwarding DataBase)。flannel.1对应的FDB信息,这是由flanneld进程负责维护,可以通过以下命令查看。

代码语言:javascript
复制
$ bridge fdb show flannel.1 | grep 56:63:6a:db:6c:b1

可以看到,发往目的VTEP(56:63:6a:db:6c:b1)的数据帧,经过flannel.1设备发给10.0.70.36的宿主机,这台宿主机正是host2.

接下来,是宿主机上一个正常的封包流程,只不过宿主机没想到里面包含了这么多内容。至此,封包完成。然后经由宿主机host1的eth0端口将报文发送出去,发送给宿主机host2.

宿主机host2接到报文后,发现里面VNI标识为1.linux内核会对它拆包,根据VNI=1,将报文交给flannel.1处理。flannel会进一步拆包,对报文进行处理,这时就回到了单机容器网络通信的流程,最终达到container-2的network namespace。

重新简述一遍container-1访问container-2的流程:

  1. container-1发起访问container-2的请求,网络流量进入docker0网桥。(从内核态向用户态的转变)。
  2. docker0查看宿主机路由表,根据最长路由匹配原则,下一跳交给flannel.1(VTEP设备)进行处理。
  3. flannel.1对报文进行封装,然后将报文发给VxLAN隧道,通过UDP进行转发。
  4. UDP是4层报文,linux内核会进行普通报文的封装,加上三层目的IP地址和2层目的MAC地址,然后由网卡eth0将流量转发出去,送往host2.
  5. host2接到报文后,是一个逆向处理的过程。

3. Flannel UDP原理

理解了Flannel VxLAN的网络通信原理后,理解UDP通信原理就非常容易。UDP也是一个三层的Overlay方案,类似于VxLAN,它首先对报文进行UDP封装,而不是VxLAN封装,其原理如下:

这次,报文从docker0网桥来到了flannel0。flannel0是一个linux的TUN设备,功能主要是在操作系统内核和用户应用程序之间传递IP包。

所以,flannel0在接到报文之后,会将报文交给flnenld进程进行处理。这是一个由内核态向用户态转换的过程。

flanneld在看到这个IP报文的目的地是172.18.28.2,就将报文封装在UDP内,转发给了host2.为什么知道要发给host2呢?就是利用了前面介绍的flannel的子网的概念。

UDP之所以被弃用,主要是因为性能问题,而性能的损耗主要源自用户态和内核态之间的

转换。我们看下面这张图,由于使用了flannel0这个TUN设备,仅在发出报文的过程就经历了3次内核态和用户态之间的转换。

第一次,用户态的容器进程发出的 IP 包经过 docker0 网桥进入内核态;

第二次,IP 包根据路由表进入 TUN(flannel0)设备,从而回到用户态的 flanneld 进程;

第三次,flanneld 进行 UDP 封包之后重新进入内核态,将 UDP 包通过宿主机的 eth0 发出去。

此外,我们还可以看到,Flannel 进行 UDP 封装和解封装的过程,也都是在用户态完成的。在 Linux 操作系统中,上述这些上下文切换和用户态操作的代价其实是比较高的,这也正是造成 Flannel UDP 模式性能不好的主要原因。这就是为什么,Flannel 后来支持的VXLAN 模式,逐渐成为了主流的容器网络方案的原因。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 容器的跨宿主机通信
  • 1 Flannel+Docker部署及配置
  • 2. Flannel VxLAN原理浅析
  • 3. Flannel UDP原理
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档