一、同一宿主机的两个容器间通信

通过 Veth Pair 设备 + 宿主机网桥的方式,实现了跟同一宿主机上其他容器通信。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

访问流程:当容器1想要跟容器2通信时,IP包会被转发到容器1的eth0这个网卡上,通过二层网络直接发往目的地,但是二层交换设备需要MAC地址进行转发(这个 eth0 网卡,是一个 Veth Pair,一段在容器内一段在docker0网桥上,此时该虚拟网卡是docker0的一个从设备)。因此发送ARP数据包,docker0把 ARP 广播转发到其他被“插”在 docker0 上的虚拟网卡上,找到容器2的mac地址,然后docker0将mac地址返回给容器1,docker0根据mac地址,在它的 CAM 表(即交换机通过 MAC 地址学习维护的端口和 MAC 地址的对应表)里查到对应的端口(Port),然后将数据包转发到该端口上,此时数据包流入容器2的eth0上(容器2的网卡也是Veth Pair)

k8s网络 随笔 第1张

 

二、跟其他宿主机通信

当跟容器外的宿主机通信时,首先经过 docker0 网桥出现在宿主机上(类似上面的分析)。然后根据宿主机的路由表里的直连路由规则,对 10.168.0.3 的访问请求就会交给宿主机的 eth0去处理,然后将这个数据包转发到10.168.0.3宿主机的eth0上。

k8s网络 随笔 第2张

 

三、容器跨主机通信

Overlay Network(覆盖网络):通过软件的方式,创建一个整个集群公用的网桥,将所有容器连在这个网桥上。每个宿主机上都有一个特殊的网桥,能将数据包发到正确的宿主机上。

k8s网络 随笔 第3张

 

Flannel 

目前,Flannel 支持三种后端实现,分别是:

1、VXLAN;

2、host-gw;

3、UDP。

3、1 flannel UDP模式

当容器1和容器2通信时。容器1发起ip包,源地址为容器1的ip地址,目的地址为容器2的ip地址。而容器2的地址并不在docker0的网桥上,因此由默认路由规则处理,然后出现在宿主机

上。宿主机跟剧路由规则,将IP包转发到flannel0上,flannel0将这个ip包交给flannel进程也就是flanneld(flannel0是一个tunnel设备,这里内核态变为用户态)。flanneld将这个ip包封装成一个UDP包,UDP包的源地址为Node1的ip地址,目的地址为Node2的ip地址,每台宿主机上的 flanneld,都监听着一个 8285 端口,所以 flanneld 只要把 UDP 包发往 Node 2的8235端口即可。Node2的flanneld从UDP包里解析出容器1发给容器2的IP包,flanneld 会直接把这个 IP 包发送给它所管理的TUN 设备,即 flannel0 设备。Linux 内核网络栈就会负责处理这个 IP 包,具体的处理方法,就是通过本机的路由表来寻找这个 IP 包的下一步流向。Linux 内核就会按照这条路由规则,把这个 IP 包转发给docker0网桥,docker0 网桥会扮演二层交换机的角色,将数据包发送给正确的端口,进而通过 Veth Pair设备进入到容器2 的 Network Namespace 里。

这里如何知道UDP包的目的IP地址呢?

在flannel管理的网络里面,每个宿主机上的容器都属于分配给这个宿主机的子网。而这些子网和宿主机的对应关系存放在etcd数据库里面,所以,flanneld 进程在处理由 flannel0 传入ip包时,可以根据目的地址找到对应的子网,从而找到对应的宿主机,在etcd中找到对应宿主机的ip地址。

k8s网络 随笔 第4张

 k8s网络 随笔 第5张

 UDP 模式有严重的性能问题:

相比于两台主机直接通信,flannel UDP多了一个步骤,flanneld的处理过程。由于使用了flannel0这个tunnel设备,仅在发送IP包的过程,就经历了三次内核态和用户态的数据拷贝。如下图:

 k8s网络 随笔 第6张

3、2 flannel VXLAN模式

VXLAN 可以完全在内核态实现上述封装和解封装的工作,从而通过与前面相似的“隧道”机制,构建出覆盖网络(Overlay Network)。

而为了能够在二层网络上打通“隧道”,XLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备就叫作 VTEP,即:VXLAN Tunnel End Point。

而 VTEP 设备的作用,其实跟前面的 flanneld 进程非常相似。只不过,它进行封装和解封装的对象,是二层数据帧(Ethernet frame);而且这个工作的执行流程,全部是在内核里完成的(因为 VXLAN 本身就是 Linux 内核中的一个模块)。

 k8s网络 随笔 第7张

与前面UDP模式类似,当容器1发出请求后,这个目的地址是容器2的ip地址,首先会出现在docker0网桥上,然后被路由到本机flannel.1设备进行处理,也就是来到了隧道的入口,我们把这个ip称为“原始ip包”。

为了能将原始ip包封装并发送到正确的宿主机,VXLAN就需要找到这条隧道的出口,即目的宿主机的VTEP设备。这个设备就是每台宿主机上的flanneld进程负责维护的。

比如,当 Node 2 启动并加入 Flannel 网络之后,在 Node 1(以及所有其他节点)上,flanneld 就会添加一条如下所示的路由规则:凡是发往 10.1.16.0/24 网段的 IP 包,都需要经过 flannel.1 设备发出,并且,它最后被发往的网关地址是:10.1.16.0。

k8s网络 随笔 第8张

然后根据ARP表(flanneld进程在Node2节点启动时,自动加在Node1上的),找到目的VTEP设备的ip地址对应的MAC地址。

 有了目的VTEP设备的MAC地址,Linux内核将原始ip包封装成“内部数据帧”,二层帧格式如下:

k8s网络 随笔 第9张

然后,Linux 内核会把这个数据帧封装进一个UDP 包里发出去。

此时,flannel.1扮演一个网桥的角色,在二层网络进行UDP包的转发。而在 Linux 内核里面,“网桥”设备进行转发的依据,来自于一个叫作 FDB(ForwardingDatabase)的转发数据库。这个 flannel.1“网桥”对应的 FDB 信息,也是 flanneld 进程负责维护的。它的内容可以通过 bridge fdb 命令查看到发往我们前面提到的“目的 VTEP 设备”的二层数据帧,应该通过 flannel.1 设备,发往 IP 地址为 10.168.0.3 的主机。显然,这台主机正是 Node 2,UDP 包要发往的目的地(目的宿主机ip)就找到了。

所以接下来的流程,就是一个正常的、宿主机网络上的封包工作。

k8s网络 随笔 第10张

Node2接收到数据帧后,内核网会发现这个数据帧有络栈里面有VXLAN Header,并且VNI=1.所以Linux内核会对它进行拆包,拿到内部数据帧,然后根据VIN的值,把它交给Node2上的flannel.1设备。flannel.1会进一步拆包,取出原始ip包。接下来回到上面讲的单机容器网络处理流程,最终ip包到容器2的network namespace中。

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄