11.4 跨pod网络

11.4 跨pod网络

现在,你知道每个pod有自己唯一的IP地址,可以通过一个扁平的、非 NAT网络和其他pod通信。Kubernetes是如何做到这一点的?简单来说,Kubernetes不负责这块。网络是由系统管理员或者Container Network Interface(CNI)插件建立的,而非Kubernetes本身。

其他参考:

Linux 虚拟网络设备 veth-pair 详解,看这一篇就够了

11.4.1 网络应该是什么样的

Kubernetes并不会要求你使用特定的网络技术,但是授权pod(或者更准确地说,其容器)不论是否运行在同一个工作节点上,可以互相通信。pod用于通信的网络必须是:pod自己认为的IP地址一定和所有其他节点认为该pod拥有的IP地址一致。

查看图 11.14。当pod A连接(发送网络包)到pod B时,pod B获取到的源IP地址必须和pod A自己认为的IP地址一致。其间应该没有网络地址转换(NAT)操作——pod A发送到pod B的包必须保持源和目的地址不变。

这很重要,保证运行在pod内部的应用网络的简洁性,就像运行在同一个网关机上一样。pod没有NAT使得运行在其中的应用可以自己注册在其他pod中。

img

image

图11.14 Kubernetes规定pod必须通过非NAT网络进行连接

例如,有客户端pod X和pod Y,为所有通过它们注册的pod提供通知服务。pod X连接到pod Y并且告诉pod Y,“你好,我是pod X,IP地址为1.2.3.4,请把更新发送到这个IP地址”。提供服务的pod可以通过收到的IP地址连接第一个pod。

pod到节点及节点到pod通信也应用了无NAT通信。但是当pod和internet上的服务通信时,pod发送包的源IP不需要改变,因为pod的IP是私有的。向外发送包的源IP地址会被改成主机工作节点的IP地址。

构建一个像样的Kubernetes集群包含按照这些要求建立网络。有不同的方法和技术来建立,在给定场景中它们都有其优点和缺点。因此,我们不会深入探究特定的技术,会阐述跨pod网络通用的工作原理。

11.4.2 深入了解网络工作原理

在 11.3 节,我们看到创建了pod的IP地址以及网络命名空间,由基础设施容器(暂停容器)来保存这些信息,然后pod容器就可以使用网络命名空间了。pod网络接口就是生成在基础设施容器的一些东西。让我们看一下接口是如何被创建的,以及如何连接到其他pod的接口,如图 11.15 所示。

[图片上传失败...(image-d2fcf3-1627950575030)]

图11.15 同一节点上pod通过虚拟Ethernet接口对连接到同一个桥接

同节点pod通信

基础设施容器启动之前,会为容器创建一个虚拟Ethernet接口对(一个veth pair),其中一个对的接口保留在主机的命名空间中(在节点上运行ifconfig命令时可以看到vethXXX的条目),而其他的对被移入容器网络命名空间,并重命名为eth0。两个虚拟接口就像管道的两端(或者说像Ethernet电缆连接的两个网络设备)——从一端进入,另一端出来,等等。

主机网络命名空间的接口会绑定到容器运行时配置使用的网络桥接上。从网桥的地址段中取IP地址赋值给容器内的eth0 接口。应用的任何运行在容器内部的程序都会发送数据到eth0 网络接口(在容器命名空间中的那一个),数据从主机命名空间的另一个veth接口出来,然后发送给网桥。这意味着任何连接到网桥的网络接口都可以接收该数据。

如果pod A发送网络包到pod B,报文首先会经过pod A的veth对到网桥然后经过pod B的veth对。所有节点上的容器都会连接到同一个网桥,意味着它们都能够互相通信。但是要让运行在不同节点上的容器之间能够通信,这些节点的网桥需要以某种方式连接起来。

不同节点上的pod通信

有多种连接不同节点上的网桥的方式。可以通过overlay或underlay网络,或者常规的三层路由,我们会在后面看到。

跨整个集群的pod的IP地址必须是唯一的,所以跨节点的网桥必须使用非重叠地址段,防止不同节点上的pod拿到同一个IP。如图 11.16 所示的例子,节点A上的网桥使用 10.1.1.0/24 IP段,节点B上的网桥使用 10.1.2.0/24 IP段,确保没有IP地址冲突的可能性。

图 11.16 显示了通过三层网络支持跨两个节点pod通信,节点的物理网络接口也需要连接到网桥。节点 A的路由表需要被配置成图中所示,这样所有目的地为 10.1.2.0/24 的报文会被路由到节点B,同时节点B的路由表需要被配置成图中所示,这样发送到 10.1.1.0/24 的包会被发送到节点A。

img

图11.16 为了让不同节点上的pod能够通信,网桥需要以某种方式连接

按照该配置,当报文从一个节点上容器发送到其他节点上的容器,报文先通过veth pair,通过网桥到节点物理适配器,然后通过网线传到其他节点的物理适配器,再通过其他节点的网桥,最终经过veth pair到达目标容器。

仅当节点连接到相同网关、之间没有任何路由时上述方案有效。否则,路由器会扔包因为它们所涉及的pod IP是私有的。当然,也可以配置路由使其在节点间能够路由报文,但是随着节点数量增加,配置会变得更困难,也更容易出错。因此,使用SDN(软件定义网络)技术可以简化问题,SDN可以让节点忽略底层网络拓扑,无论多复杂,结果就像连接到同一个网关上。从pod发出的报文会被封装,通过网络发送给运行其他pod的网络,然后被解封装、以原始格式传递给pod。

11.4.3 引入容器网络接口

为了让连接容器到网络更加方便,启动一个项目容器网络接口(CNI)。CNI允许Kubernetes可配置使用任何CNI插件。这些插件包含

  • Calico
  • Flannel
  • Romana
  • Weave Net
  • 其他

我们不会去深入探究这些插件的细节,如果想要了解更多,可以参考https://kubernetes.io/docs/concepts/cluster-administration/addons/。

安装一个网络插件并不难,只需要部署一个包含DaemonSet以及其他支持资源的YAML。每个插件项目首页都会提供这样一个YAML文件。如你所想,DaemonSet用于往所有集群节点部署一个网络代理,然后会绑定CNI接口到节点。但是,注意Kubetlet需要用 --network-plugin=cni 命令启动才能使用CNI。

你可能感兴趣的:(11.4 跨pod网络)