文章目录

  • 前言
  • 容器间网络
  • Pod间网络
  • 同节点Pod通信
  • 不同节点Pod通信
  • Pod与Service间网络


前言

本文介绍了IPVS模式结合calico网络插件,在不同用例场景下流量是如何在kubernetes集群中流转的。

kubernetes的代理模式选择了IPVS模式,它可以将到达cluster ip的流量转发到真实的服务上。

而calico使用的是vxlan模式,帮助实现Pod跨节点通信。

本文主要简述了以下三种场景的网络通信:

  • 容器间网络
  • Pod间网络
  • Pod与Service间网络

容器间网络

在同一个Pod中,容器间是可以直接通过localhost:port访问的。之所以能够这样操作,是因为Pod是由一组同一网络命名空间下的docker容器组成。网络命名空间为这组容器提供一个独立的网络栈,route,iptables规则以及网络设备对于这些容器都是全新的,不受其他网络命名空间空间影响。而容器,本质上是一组受到资源限制,彼此间相互隔离的进程。那么我们可以把Pod看作一台服务器,容器间的通信就是这台服务器中的两个应用在通信。

Pod间网络

Pod间的网络可分为同节点Pod通信和不同节点Pod通信。同节点的Pod通信实现起来比较简单,既可以通过Linux Bridge把同节点的Pod关联起来,也可以通过route将流量转发到指定Pod。而不同节点的Pod通信相对要复杂一些,需要借助于vxlan或IPIP等技术来实现。

同节点Pod通信

kubernetes 网络基础 kubernetes的网络方案_kubernetes

如上图所示,pod1的eth0与root命名空间的veth0相连,pod2的eth0与root 命名空间的veth1相连,每个pod都会分配一个IP。

路由表内容如下:

$ route
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         host-192-168-18 0.0.0.0         UG    0      0        0 eth0
169.254.169.254 host-192-168-18 255.255.255.255 UGH   0      0        0 eth0
172.16.44.195   0.0.0.0         255.255.255.255 UH    0      0        0 veth0
172.16.44.197   0.0.0.0         255.255.255.255 UH    0      0        0 veth1

当我们在pod1中向pod2发送请求时,

1、 请求报文直接从eth0发送到veth0。

2、接着报文从veth0网卡进入协议栈,通过查询路由表可知,报文会被转发到veth1,

3、将报文发送到pod2中,出现在eth0网卡。

在每个pod内都设置了相同的网卡及路由,因此pod只和本地的eth0通讯。而pod内的路由表如下:

$ route
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         gateway         0.0.0.0         UG    0      0        0 eth0
gateway         0.0.0.0         255.255.255.255 UH    0      0        0 eth0

pod内部的报文会匹配到默认路由,然后从eth0发出。

不同节点Pod通信

kubernetes 网络基础 kubernetes的网络方案_Pod_02

如上图所示,pod1和pod2分属node1和node2两个节点,这两个pod的IP属于同一个CIDR。而在本文中,这两个pod的通信是基于vxlan技术实现的,因此在两个节点上会有vxlan的接口。

pod1发送请求到pod2大致流程如下:

1、pod1中的报文经pod内部的eth0直接发送到calia7dc8ff0932;

2、报文经calia7dc8ff0932进入协议栈,查询路由后,目的IP匹配到网关IP(172.16.154.192),然后转发到vxlan.calico接口;

路由表如下:

$ route
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         host-192-168-18 0.0.0.0         UG    0      0        0 eth0
169.254.169.254 host-192-168-18 255.255.255.255 UGH   0      0        0 eth0
172.16.154.192  172.16.154.192  255.255.255.192 UG    0      0        0 vxlan.calico
172.16.235.192  0.0.0.0         255.255.255.192 U     0      0        0 *
172.16.235.193  0.0.0.0         255.255.255.255 UH    0      0        0 calia7dc8ff0932
192.168.186.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0

3、vxlan.calico是vxlan类型接口,可以将进入的报文封装成UDP报文,端口号4789,然后再次将报文送入协议栈;

通过转发表可以获取到对端vxlan.calico所在节点的IP。

$ bridge fdb
33:33:00:00:00:01 dev eth0 self permanent
01:00:5e:00:00:01 dev eth0 self permanent
33:33:ff:38:55:04 dev eth0 self permanent
33:33:00:00:02:02 dev eth0 self permanent
66:0f:78:83:d5:e1 dev vxlan.calico dst 192.168.186.202 self permanent
33:33:00:00:00:01 dev calia7dc8ff0932 self permanent
01:00:5e:00:00:01 dev calia7dc8ff0932 self permanent
33:33:ff:ee:ee:ee dev calia7dc8ff0932 self permanent

至于目的MAC地址,我们可以通过ip neigh命令查看。因为报文要发送到对端vxlan.calico上,可以通过以下信息获取对应MAC地址。

$ ip neigh
172.16.154.192 dev vxlan.calico lladdr 66:0f:78:83:d5:e1 PERMANENT

4、UDP报文经node1的eth0网卡发出,经物理网络到达node2;

5、node2监听端口为4789的报文,将报文转发到vxlan.calico;

6、报文经过vxlan.calico网卡进行解封,获取真实报文,然后根据路由表,将报文发送到cali5132a054307进入pod2。

Pod与Service间网络

在kubernetes中,pod并不是一直稳定存在,一旦重新创建pod,那么pod IP也会随之改变。因此kubernetes提出service的概念,通过service为后端服务提供一个稳定的虚拟IP,发送到此虚拟IP的请求会被转发到后端真实服务上。而service有三种代理模式,分别是userspace模式、iptables模式和IPVS模式,这里笔者采用的是IPVS模式。

IPVS作为Linux内核的一部分,基于netfilter实现了传输层的负载均衡。基于TCP或UPD的请求,将请求转发到真实服务上。

采用IPVS模式,kubernetes会创建dummy网卡。每当kubernetes创建service时,会将该服务的vip绑定到这张网卡。

pod到service代理的服务请求流程大致如下:

1、目的IP为Service IP的请求通过pod内的eth0设备发出到达对端veth;

2、在宿主机端无法找到Service IP的路由,根据默认路由进行转发。

3、在经过iptables的postrouting链时,IPVS会根据指定的负载均衡算法选择一个Pod,并进行DNAT,将目的IP改为Pod IP。iptables还会利用Linux内核的conntrack工具记录所选的Pod。

4、请求被正确修改后发送到指定的Pod;

5、Pod处理请求后,响应数据通过veth pair到达宿主机,经过iptables时根据conntrack记录的信息将响应方的IP修改为Service IP。

6、根据路由将响应数据转发到指定Pod。