Kubernetes 网络简析之一:Pods

前言

Kubernetes确实是复杂的,单是阅读官方的文档仍然不足以让我们深入理解其内部的原理。所以我尝试通过搜索网上对kubernetes的解读文章来加深对kubernetes内部机制的理解。幸运的是虽然废了一番功夫,但是总算是找到了一些很有意义的解读文章。
个人经验而言最好的学习和记忆方式就是针对一个主题一遍一遍重复地阅读,理解,分析和总结。每一遍都会对每一个点有新的理解。

Kubernetes 网络

当面对yaml文件中的众多配置有时候经常是一头雾水。特别是在配置kubernetes内部的pod,service,ingress时,对于配置项作用也仅限于记忆而非理解。所以从本篇文章始,通过对精华文章的翻译、解读以及丰富来记录自己对kuberenetes内部原理的学习过程。

本文参考文章为:Understanding kubernetes networking: pods

Kubernetes Pod

作为Kubernetes里面最小的操作单位,Pod内部的所有container是共享网络堆栈和存储卷的。共享网络堆栈的好处就是container之间可以通过localhost的方式来进行通信,而不用考虑相互之间的IP是否一致了。但为什么Pod内部可以按照这种方式进行通信?它的原理是怎么样的?接下来让我们从docker container的基础模型一步步进行阐述:

独立的docker container模型

Kubernetes 网络简析之一:Pods_第1张图片
如上图所示,在宿主机上有一个物理网卡eth0,docker 给container 分配了一个虚拟网卡veth0。而它们之间通过网桥docker0进行交互。我们可以看到docker0和veth0在同一网段上,docker0 IP为172.17.0.1作为veth0的默认网关。
这种模式在一个container的情况下可能还没有什么感觉。接下来让我们看看两个container的情况:
Kubernetes 网络简析之一:Pods_第2张图片
这里我们可以更直观地看到docker0作为网关的作用。container2也被分配了一个虚拟网卡veth1,而且还和docker0以及veth0在同一网段,这样container之间就可以通过docker0进行通信。

共享网络的docker container模型

虽然独立的container能够通过docker0网桥进行通信,但是他们的IP终究不一样。这样就带来一个问题,由于IP是动态分配的,所以一个container内部的服务如果想访问另外一个container内部的服务,它最大的障碍就在于需要知道对端container当前的IP是多少。有没有一种方式能够让container之间忽略掉IP的限制,直接让container之间通过localhost来进行通信呢?答案是有的:通过配置 –network=“container: 就可以达到共享网络的效果。
Kubernetes 网络简析之一:Pods_第3张图片
如上所示,当我们对container2配置了**–network=“container:container1”**时,container2就合container1共用一个虚拟网卡。这样两个container就共用IP地址以及端口。相互之间就能通过localhost就行通信了。
那么Pod内部是不是就是基于这样的配置来实现container之间共用网络的呢?答案是YES!
Kubernetes 网络简析之一:Pods_第4张图片
Pod内部很巧妙地通过配置一个启动就执行pause命令的container,它唯一的作用就是为其他container提供网络接口veth0。这样其他的container都绑定到同一个网卡上,从而实现了共享网络。而pause container在启动后就会一直处于挂起睡眠的状态,直到kubernetes给它发送SIGTERM信号。

kubernetes Cluster

以上我们对k8s pod的网络模型进行了分析。但是k8s真正的精髓是它让我们可以忽略物理机的网络限制,让两个即使在不同物理机上但在同一cluster的pod也能够无需额外的网络配置完成自由通信。接下来让我们进一步对cluster的网络模型进行分析。

node网络模型

Kubernetes 网络简析之一:Pods_第5张图片
如上所示,node即为pod的宿主机,它们可以是物理主机也可以是虚拟主机。我们只需要在其上配置docker、k8s运行环境以及主机之间的网络连接即可在这些主机上配置我们的k8s cluster环境。如上所示两个主机都各自有网卡eth0和网关相连。
假如我们直接将pod的网络模型分别放到两个node上会有什么效果?
Kubernetes 网络简析之一:Pods_第6张图片
从上图我们可以看到,我们分别在两个nodes上创建了两个pod。pod内部和我们上面描述得一样,能够通过veth0进行相互通信。也能通过网桥docker0和外部通信。但是假如我们想让一个pod去访问另外一个node上面的pod的话,问题就来了:当前pod根本无法知道对端node的网络情况,从而也无法知晓想访问的pod的IP。

cluster网络模型

Kubernetes 网络简析之一:Pods_第7张图片
面对上面说到的不同node的pod之间的通信问题,k8s给出的解决方案是:

  1. k8s给每个node上面的网桥cbrx(k8s这里并没有使用docker的网桥,而是custom的网桥)分配了统一的网段,这里以10.0.0.0/14 (255.252.0.0)为例
  2. k8s在node之间的网关(10.100.0.1)上维护了一份路由表来表示各个网桥cbrx所对应的宿主机(即物理网卡eth0)信息
    如上图所示k8s给两个nodes上的docker环境分别分配了两个cbr0网桥(10.0.1.1)和(10.0.2.1),同时在网关10.100.0.1上维护了如下一份路由表:
目标网段 下一跳IP
10.0.1.0/24 10.100.0.2
10.0.2.0/24 10.100.0.3

当我们分别在两个nodes上面创建两个pod的时候,其中两个pod被分配的地址是分别为10.0.1.2和10.0.2.2。
这个时候如果我们想让pod1(10.0.1.2)访问pod2(10.0.2.2)的时候,pod1会先尝试在自己的网关cbr0上尝试路由到目标IP,而cbr0找不到则会上升到eth0,然后上升到网关(10.100.0.1)。这个时候网关(10.100.0.1)会根据上述的路由表将连接路由到另外一个node的eth0(10.100.0.3),最后再通过cbr0(10.0.2.1)路由到pod2。
这样不同node上面的pod就可以进行通信了。

下一篇 Kubernetes网络简析之二:services, 我们会对k8s的service模型进行分析。

你可能感兴趣的:(kubernetes)