目录

Kubernetes Network 中的 IP 地址类型

Kubernetes 网络中涉及以下几种类型的 IP 地址:

  1. Node IP:宿主机 IP 地址。

  2. Pod IP:Pod 是 Kubernetes 的最小部署单元,Pod 下可以包含若干个 Containers,但是 Container 没有独立的 IP 地址,它们共享 Pod 的 IP 地址和 Ports 区间。

  3. Cluster IP:这里所述 Cluster 并非 Kubernetes Cluster,而是 Kubernetes Service 的 IP 地址。外部网络是无法访问该地址的,只有 Kubernetes Cluster 内部才能访问。因为 Cluster IP 是一个虚拟的 IP 地址,即:没有网络设备为这个 IP 地址负责。在 Kubernetes 内部使用了 IPtables 规则来重定向到其本地端口,再均衡到后端的 Pods;

  4. Public IP:因为 Cluster IP 能在 Kubernetes Cluster Internal 访问,属于应用程序内部的层级。如果希望将这个 Service 为 Kubernetes Cluster External 的客户端提供访问,就需要为这个 Service 提供一个 Public IP。

Kubernetes 的网络流量模型

同 Pod 内部的 Containers 间的通信(Container 模式)

Pod 内部的 Containers 通过 localhost 进行通信,它们使用了同一个 Network Namespace。对 Container 而言,hostname 就是 Pod 的名称。

Pod 内部的 Containers 共享同一个 IP 地址和端口区间,所以要为每个可以建立连接的 Container 分配不同的 Port 号。也就是说,Pod 中的 “应用” 需要自己协调端口号的分配和使用。

  • 例如:创建一个 Pod ,包含两个 Containers。
    Kubernetes — 网络流量模型_其他
    Kubernetes — 网络流量模型_其他_02

Kubernetes — 网络流量模型_原力计划_03

Kubernetes — 网络流量模型_原力计划_04

可以看到同一个 Pod 下属的两个 Containers 共享了 IP 地址。

Kubernetes — 网络流量模型_Kubernetes 云原生_05
Kubernetes — 网络流量模型_Kubernetes 云原生_06

可以看见,同一个 Pod 下属的两个 Containers 不能占有同一个 Port 号,因为 Port 区间也是共享的。

所以,我们可以将 Pod 理解为一个小型的 “操作系统沙盒”,两个进程可以使用同一个操作系统 IP 地址,自然也就不可以使用同一个 Port 号了。

实现原理:同一个 Pod 内的 Containers 处于同一个 Network Namespace,因此使用了相同的 IP 地址和 Port 区间。该 Namespace 是由一个名为 Pause Container 实现的,每当一个 Pod 被创建,首先会创建一个 Pause Container。

Kubernetes — 网络流量模型_原力计划_07

后续所有新的普通 Containers 都通过过共享 Pause Container 的网络栈,实现与外部 Pod 进行通信。因此,对于同 Pod 下属的 Containers 而言,它们看到的网络视图是一样的。上述我们在 Container 中看的 IP 地址,实际就是 Pause Container 的 IP 地址,通过控制 Pause Container 的网络协议栈就可以影响所有同属 Pod 下的 Container 的网络协议栈了。

这种新创建的容器和已经存在的一个容器(Pause)共享一个 Network Namespace(而不是和宿主机共享)的模式,就是常说的 Container 模式。

Kubernetes — 网络流量模型_Kubernetes 云原生_08

同 Node 内部的 Pods 间的通信(Host Virtual Network 模式)

每个 Node 上的每个 Pod 都有自己专属的 Network Namespace,由此实现 Container 模型网络的隔离。而两个 Pod 之间,即:两个 Network Namespace 之间希望进行通信的话,就需要使用到 Linux 操作系统的网络虚拟化技术 —— Veth Pair(虚拟网线)了。

但是,如果有多个 Pod 都需要两两建立 Veth Pair 的话,扩展性就会非常的差,假如:有 N 个 Pod,就需要创建 n(n-1)/2 个 Veth Pair。可见,除了 Veth Pair(虚拟网线)之外,我们还需要一个二层的 “集线” 设备 —— Linux Bridge(虚拟交换机)。

Kubernetes — 网络流量模型_其他_09

举个例子:创建位于同一个 Node 下属的 Pod1 和 Pod2,IP 地址分别为:10.244.1.16、10.244.1.18。

Kubernetes — 网络流量模型_原力计划_10

查看 Node 下的 Network Namespace:

Kubernetes — 网络流量模型_原力计划_11
Kubernetes — 网络流量模型_其他_12

分别查询两个 Network Namespace 下的 Network Interfaces:

Kubernetes — 网络流量模型_Kubernetes 云原生_13
可见,Pod1、Pod2 内部的 Veth Pair 的一端分别是 3: eth0@if73: eth0@if9;另一端则位于 default Network Namespace,分别为 7: veth3b416eb2@if39: veth88cfc816@if3。注意:interface ID 和 ifID 刚刚好是两端对称的,以此来进行辨识。当然了,Bridge 也同样存在于 default Network Namespace。

Kubernetes — 网络流量模型_原力计划_14

这种借助于 Linux 操作系统原生的网络虚拟化技术实现的两个本地 Pods 之间的网络通信方式,称为 Host Virtual Network 模式。

跨 Nodes 间的 Pods 间的通信(SDN 模式)

总的来说,跨主机通信无非两种方式:

  • Overlay 隧道互通:Nodes 之间通过 Over the Physical 网络互通,e.g. OvS、Flannel 和 Weave。
  • Underlay 直接互通:Nodes 之间通过物理网络互通,e.g. Calico 的 Direct 模式、macvlan。

从网络角度对 Flannel 和 Calico 进行简单对比。可见,对性能敏感、策略需求较高时偏向于 Calico 方案。否则,采用 Flannel 会是更好的选择;

Kubernetes — 网络流量模型_其他_15

Service 的 Cluster IP 和外部网络间的通信

Service 之于集群内部 Pods 之间的通信

Pod 间可以直接通过 IP 地址通信,但前提是 Pod 知道对方的 IP。在 Kubernetes Cluster 中,Pod 可能会频繁地销毁和创建,也就是说 Pod 的 IP 不是固定的。为了解决这个问题,Kubernetes Service 作为访问 Pod 的上层抽象。无论后端的 Pod 如何变化,Service 都作为稳定的前端对外提供服务。同时,Service 还提供了高可用和负载均衡功能,负责将请求转发给正确的 Pod。

Service 之于集群外部与 Pod 的通信

无论是 Pod IP 还是 Service 的 Cluster IP,它们都是只能在 Kubernetes Cluster 内部可见的私有 IP 地址。Kubernetes 提供了两种方式可以让外部网络访问 Service 的 Cluster IP,继而与 Pod 进行通信:

  1. NodePort:Service 通过 Node 的静态端口对外提供服务,外部网络可以通过 NodeIP:NodePort 访问 Service,根据不同的 NodePort 可以访问不同的 Service。

  2. LoadBalancer:Service 利用自建的负载均衡器(反向代理)将流量导向 Service,例如:Nginx、OpenStack Octavia、Cloud Provider(GCP、AWS、 Azure)等。