一、前言
k8s对Pods之间如何进行组网通信提出了要求,k8s对集群的网络有以下要求:
所有的Pods之间可以在不使用NAT网络地址转换的情况下相互通信
所有的Nodes之间可以在不使用NAT网络地址转换的情况下相互通信
每个Pod自己看到的自己的ip和其他Pod看到的一致
k8s网络模型设计基础原则:每个Pod都拥有一个独立的 IP地址,而且 假定所有 Pod 都在一个可以直接连通的、扁平的网络空间中 。 所以不管它们是否运行在同 一 个 Node (宿主机)中,都要求它们可以直接通过对方的 IP 进行访问。设计这个原则的原因 是,用户不需要额外考虑如何建立 Pod 之间的连接,也不需要考虑将容器端口映射到主机端口等问题。
由于 Kubemetes 的网络模型假设 Pod 之间访问时使用的是对方 Pod 的实际地址,所以一个 Pod 内部的应用程序看到的自己的 IP 地址和端口与集群内其他 Pod 看到的一样。它们都是 Pod 实际分配的IP地址 (从dockerO上分配的)。将IP地址和端口在Pod内部和外部都保持一致, 我们可以不使用 NAT 来进行转换,地址空间也自然是平的。
鉴于上面这些要求,我们需要解决四个不同的网络问题::
Docker容器和Docker容器之间的网络
Pod与Pod之间的网络
Pod与Service之间的网络
Internet与Service之间的网络
下面我们一一进行讨论每种网络问题,以及如何解决。
二、容器和容器之间的网络
在k8s中每个Pod中管理着一组Docker容器,这些Docker容器共享同一个网络命名空间。
Pod中的每个Docker容器拥有与Pod相同的IP和port地址空间,并且由于他们在同一个网络命名空间,他们之间可以通过localhost相互访问。 什么机制让同一个Pod内的多个docker容器相互通信那?其实是使用Docker的一种网络模型:–net=container
container模式指定新创建的Docker容器和已经存在的一个容器共享一个网络命名空间,而不是和宿主机共享。新创建的Docker容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等
每个Pod容器有有一个pause容器其有独立的网络命名空间,在Pod内启动Docker容器时候使用 –net=container就可以让当前Docker容器加入到Pod容器拥有的网络命名空间(pause容器)
三、Pod与Pod之间的网络
k8s中,每个Pod拥有一个ip地址,不同的Pod之间可以直接使用改ip与彼此进行通讯
在同一个Node上,从Pod的视角看,它存在于自己的网络命名空间中,并且需要与该Node上的其他网络命名空间上的Pod进行通信。
那么是如何做到的?这多亏了使用linux虚拟以太网设备或者说是由两个虚拟接口组成的veth对使不同的网络命名空间链接起来,这些虚拟接口分布在多个网络命名空间上(这里是指多个Pod上)。
为了让多个Pod的网络命名空间链接起来,我们可以让veth对的一端链接到root网络命名空间(宿主机的),另一端链接到Pod的网络命名空间。
每对Veth就像一根接插电缆,连接两侧并允许流量在它们之间流动;这种veth对可以推广到同一个Node上任意多的Pod上,如上图这里展示使用veth对链接每个Pod到虚拟机的root网络命名空间。
下面我们看如何使用网桥设备来让通过veth对链接到root命名空间的多个Pod进行通信。
linux以太网桥(Linux Ethernet bridge)是一个虚拟的2层网络设备,目的是把多个以太网段链接起来,网桥维护了一个转发表,通过检查转发表通过它传输的数据包的目的地并决定是否将数据包传递到连接到网桥的其他网段,网桥代码通过查看网络中每个以太网设备特有的MAC地址来决定是传输数据还是丢弃数据。
网桥实现了ARP协议用来根据给定的ip地址找到对应机器的数据链路层的mac地址,一开始转发表为空,当一个数据帧被网桥接受后,网桥会广播该帧到所有的链接设备(除了发送方设备),并且把响应这个广播的设备记录到转发表;随后发往相同ip地址的流量会直接从转发表查找正确的mac地址,然后转发包到对应的设备。
如上图显示了两个Pod通过veth对链接到root网络命名空间,并且通过网桥进行通信
3.1 同一个Node中的Pod之间的一次通信
鉴于每个Pod有自己独立的网络命名空间,我们使用虚拟以太网设备把多个Pod的命名空间链接到了root命名空间,并且使用网桥让多个Pod之间进行通信,下面我们看如何在两个pod之间进行通信:
通过网桥这里把veth0和veth1组成为一个以太网,他们直接是可以直接通信的,另外这里通过ve