k8s网络
一、同一宿主机的两个容器间通信
通过 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)
二、跟其他宿主机通信
当跟容器外的宿主机通信时,首先经过 docker0 网桥出现在宿主机上(类似上面的分析)。然后根据宿主机的路由表里的直连路由规则,对 10.168.0.3 的访问请求就会交给宿主机的 eth0去处理,然后将这个数据包转发到10.168.0.3宿主机的eth0上。
三、容器跨主机通信
Overlay Network(覆盖网络):通过软件的方式,创建一个整个集群公用的网桥,将所有容器连在这个网桥上。每个宿主机上都有一个特殊的网桥,能将数据包发到正确的宿主机上。
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地址。
UDP 模式有严重的性能问题:
相比于两台主机直接通信,flannel UDP多了一个步骤,flanneld的处理过程。由于使用了flannel0这个tunnel设备,仅在发送IP包的过程,就经历了三次内核态和用户态的数据拷贝。如下图:
3、2 flannel VXLAN模式
VXLAN 可以完全在内核态实现上述封装和解封装的工作,从而通过与前面相似的“隧道”机制,构建出覆盖网络(Overlay Network)。
而为了能够在二层网络上打通“隧道”,XLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备就叫作 VTEP,即:VXLAN Tunnel End Point。
而 VTEP 设备的作用,其实跟前面的 flanneld 进程非常相似。只不过,它进行封装和解封装的对象,是二层数据帧(Ethernet frame);而且这个工作的执行流程,全部是在内核里完成的(因为 VXLAN 本身就是 Linux 内核中的一个模块)。
与前面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。
然后根据ARP表(flanneld进程在Node2节点启动时,自动加在Node1上的),找到目的VTEP设备的ip地址对应的MAC地址。
有了目的VTEP设备的MAC地址,Linux内核将原始ip包封装成“内部数据帧”,二层帧格式如下:
然后,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)就找到了。
所以接下来的流程,就是一个正常的、宿主机网络上的封包工作。
Node2接收到数据帧后,内核网会发现这个数据帧有络栈里面有VXLAN Header,并且VNI=1.所以Linux内核会对它进行拆包,拿到内部数据帧,然后根据VIN的值,把它交给Node2上的flannel.1设备。flannel.1会进一步拆包,取出原始ip包。接下来回到上面讲的单机容器网络处理流程,最终ip包到容器2的network namespace中。
