Kubernetes 网络插图指南(系列一)

853 阅读5分钟

无论你已经将大量服务部署在Kubernetes中并从中受益,还是你即将使用Kubernetes。即便有大量可用于启动和管理Kubernetes集群的工具,我觉得你一定对Kubenetes背后的原理很好奇。如果Kubernetes集群出现故障,你将如何处理?

Kubernetes的使用是非常简单的,但是我们必须明确Kubernetes背后原理是非常复杂的,它是由大量模块和插件组成的。如果你要想在使用过程中从容面对突如其来的问题,了解这些模块的各自职责和插件的作用是非常有必要的。在Kubernetes的模块中最复杂也是最重要的是网络部分。

为了准确理解Kubernetes的网络是如何工作的,我阅读了大量的文档、参加线下话题的讨论、甚至阅读了大量的源码。下面是我对Kubernetes网络的一些总结:

Kubernetes网络模块

Kubernetes网络有一个重要的设计原则:每一个Pod都有一个独特的IP地址

这个Pod的IP地址对于Pod内的其它容器都是公开的,对于同节点内的其它Pod是可路由的。你是否注意到在Kubernetes集群节点上的Pause容器?它的工作是存储和持有Pod内容器的共享网络空间(netns),也叫作“sandbox containers”。这也就是说容器无故死亡并且新的替代容器被创建后,Pod的ip地址并不会发生改变。更多关于Sandbox Containers参见 IP-Per-Pod的另一个好处是不用担心宿主机上Pod的IP地址和PORT的冲突的问题,我们也不用关系应用使用的IP地址和PORT。

简要概括来说,不管Pod运行在哪台宿主机上,Kubernetes仅需要Pod的IP地址可被其它Pod路由和访问到。

节点内通信

首先要保证同节点内的Pod可以相互通信,这也是接下来讨论跨节点的Pod间通信和Pod内容器访问外部网路的基础。

在一定意义上,我们可以将Kubernetes节点认为是拥有root网路命名空间(root是根用户并不是超级用户)的linux机器。

Linux机器的网络接口eth0就是root netns。

相似的,每一个Pod也都有自己的netns并通过虚拟的ethernet pair跟宿主机的root netns相互通信。pipe-pair的一端在宿主机的root netns上,另一端在pod的netns,从而相互通信。

我们将pipe-pair在pod端的ethernet netns称为eth0,pod端并不知道宿主机的ethernet netns,宿主机默认开启root netns。pipe-pair在宿主机端的网络设备命令为vethxxx,使用ifconfig和ip命令查看宿主机所有的网络设备。

上面已经很好的阐释Pods和宿主机之间的通信。对于宿主机内不同Pod的相互通信可以使用网桥设备cbr0。Docker使用相似的网桥设备叫docker0,使用brctl show命令列出所有的的网桥。

假设网络包通过pod1去往pod2:

  1. 网络包通过pod1的eth0离开pod1,通过vethxxx进入宿主机的root netns
  2. 在cbr0网桥上通过ARP请求(“谁是目的ip地址”)发现目的地址
  3. vethyyy回复ARP请求说自己知道目的地址,于是cbr0将网络包发往vethyyyy
  4. 网络包到达vethyyyy后通过pipe-pair最终到达pod2的netns

这就是Kubernetes中不同pod内容器相互通信的原理。当然也有其它一些通信方案,但是这种无疑是最简单的。

跨节点间通信

如我前文所说,Pods也需要跨节点通信。因此我们可以使用L2(跨节点的ARP请求)、L3(跨节点的IP路由 如:云服务商提供的route表)、overlay网络或者carrier pigeons,只要网络包可以到达指定的节点,Kubernetes并不关心跨节点的pod如何通信。每一个节点都会从指定的IP地址范围(CIDR block)中分配一个ip地址,即每一个pod都具有一个唯一的ip地址,因此我们也不用担心不同节点地址重复的问题。

在多数情况下(特别是在云环境下),云服务商提供route表来保证网络包到达目的地址。除此之外,社区还提供大量的网络插件都是通过在节点配置相应的路由实现相同功能。

诸如在上文的例子那样,每一个node都有许多network空间、network接口以及一个网桥。

假设网络包由pod1到pod4(不同节点之间)

  1. 网络包从pod1的eth0设备离开,通过vethxxx进入root netns中
  2. 网络包到达cbr0网桥设备,网桥通过ARP请求寻找目的地址
  3. 由于在节点上没有收到关于ARP请求的应答,网络包通过宿主机eth0网络接口进入主干网络中
  4. 网络包离开node1节点后通过主干网络进入服务商的路由器中
  5. 配置CIDR IP(Pod的IP地址)的节点都会将相关信息注册到route表中,因此可以通过路由表发现运行着pod4IP地址的节点
  6. 最后网络包通过网络接口eth0进入到node2节点中,尽管pod4的ip地址并不是相应的eth0网络接口地址,由于节点已经做好相应路由跳转配置,网络包依旧可以跳转到网桥上。节点路由表过滤符合pod4 ip地址的路由信息,发现去往的节点CIDR IP目的地址需要经过网桥cbr0。你可以通过命令 route -n列出cbr0的路由信息如下图:

7.网络收到网络包,通过ARP请求发现目的IP地址属于网络接口vethyyy

8.最后网络包到达pod4🏠

以上就是pipe-pair的全过程,这也是Kubernetes网络的基础内容。接下来我们将探讨Overlay网络的工作原理如何从Pod中抽象Service以及出栈和入栈网络的工作流

文章翻译自An illustrated guide to Kubernetes Networking [Part 1],是略有删减