4

Kubernetes网络模型的核心要求之一是每个Pod应该获得自己的IP地址,并且集群中的每个Pod应该能够使用该IP地址与其进行对话。有几种网络提供商(flannel, calico, canal等)实现此网络模型。

当我开始使用Kubernetes时,我还不清楚如何为每个Pod分配IP地址。我了解了各个组件如何独立工作,但是还不清楚这些组件如何组合在一起。例如,我了解了什么是CNI插件,但是我不知道它们是如何被调用的。因此,我想写这篇文章来分享我对各种网络组件的了解,以及如何将它们组合到kubernetes集群中,以便每个Pod都能接收IP地址。
在kubernetes中有多种设置网络的方法,以及容器运行时的各种选项。在这篇文章中,我将使用Flannel作为网络提供者,并使用Containered作为容器运行时。另外,我将假定您知道容器网络的工作原理,并且仅在上下文中分享一个非常简短的概述。

一些背景概念

容器网络概述

有一些非常好的博客解释了容器网络的工作方式。就上下文而言,我将在这里通过涉及Linux网桥网络和数据包封装的单一方法在一个非常高级的概述中进行介绍。

同一主机上的容器

在同一主机上运行的容器可以通过其IP地址相互通信的方法之一是通过linux bridge。在kubernetes(和docker)世界中,创建了veth(虚拟以太网)设备来实现此目的。此veth设备的一端插入容器网络名称空间,另一端连接到主机网络上的linux bridge。同一主机上的所有容器都将veth对的一端连接到linux网桥,并且它们可以通过网桥使用其IP地址相互通信。 linux网桥也被分配了一个IP地址,它充当从目的地到不同节点的Pod流出流量的网关。

不同主机上的容器

在不同主机上运行的容器可以通过其IP地址相互通信的方式之一是使用数据包封装。 Flannel通过vxlan支持此功能,vxlan将原始数据包包装在UDP数据包中并将其发送到目标。
在kubernetes集群中,Flannel在每个节点上创建一个vxlan设备和一些路由表条目。每个发往不同主机上的容器的数据包都会通过vxlan设备,并封装在UDP数据包中。在目标位置,检索封装的数据包,然后将数据包路由到目的地的pod。

注意:这只是可以配置容器之间的网络的方法之一。

什么是 CRI?

CRI(容器运行时接口)是一个插件接口,允许kubelet使用不同的容器运行时。各种容器运行时都实现了CRI API,这使用户可以在kubernetes安装中使用他们选择的容器运行时。

什么是 CNI?

CNI项目包含一个规范,可为Linux容器提供基于通用插件的联网解决方案。它还由各种插件组成,这些插件在配置Pod网络时执行不同的功能。 CNI插件是遵循CNI规范的可执行文件,我们将在下面的文章中讨论一些插件。

为节点分配Pod IP地址的子网

如果要求所有Pod具有IP地址,那么确保整个集群中的所有Pod具有唯一的IP地址非常重要。这是通过为每个节点分配一个唯一的子网来实现的,从该子网中为Pod分配了该节点上的IP地址。

Node IPAM Controller

nodeipam作为选项传递给kube-controller-manager--controllers命令行标志时,它将为每个节点分配来自集群CIDR(集群网络的IP范围)的专用子网(podCIDR)。由于这些podCIDR是不相交的子网,因此它允许为每个Pod分配一个唯一的IP地址。
当Kubernetes节点首次向集群注册时,会为其分配一个podCIDR。要更改分配给集群中节点的podCIDR,需要先注销节点,然后使用首先应用于kubernetes控制平面的任何配置更改来重新注册节点。可以使用以下命令列出节点的podCIDR

$ kubectl get no <nodeName> -o json | jq '.spec.podCIDR'
10.244.0.0/24

Kubelet,容器运行时和CNI插件-如何将它们全部组合在一起

当在节点上调度Pod时,启动Pod会发生很多事情。在本节中,我将仅着重与为Pod配置网络有关的交互。
一旦在节点上调度了Pod,以下交互将导致配置网络并启动应用程序容器。

容器运行时与CNI插件之间的交互

每个网络提供商都有一个CNI插件,容器运行时会调用该插件,以在Pod启动时为其配置网络。使用容器化作为容器运行时,容器化CRI插件将调用CNI插件。每个网络提供商都在每个kubernetes节点上都安装了一个代理,以配置pod网络。安装了网络提供商代理后,它要么随CNI配置一起提供,要么在节点上创建一个,然后由CRI插件用来确定要调用哪个CNI插件。

CNI配置文件的位置是可配置的,默认值为/etc/cni/net.d/<config-file>。集群管理员需要在每个节点上交付CNI插件。 CNI插件的位置也是可配置的,默认值为/opt/cni/ bin

如果使用容器作为容器运行时,则可以在容器配置的[plugins."io.containerd.grpc.v1.cri".cni]部分下指定CNI配置和CNI插件二进制文件的路径。

由于我们在这里将Flannel称为网络提供商,因此我将简要介绍Flannel的设置方式。 Flanneld是Flannel守护程序,通常作为守护程序安装在kubernetes集群上,并以install-cni作为初始化容器。 install-cni容器在每个节点上创建CNI配置文件-/etc/cni/net.d/10-flannel.conflist。 Flanneld创建一个vxlan设备,从apiserver获取网络元数据,并监视pod上的更新。创建Pod时,它将为整个集群中的所有Pod分配路由,这些路由允许Pod通过其IP地址相互连接。

容器式CRI插件和CNI插件之间的交互可以如下所示:

如上所述,kubelet调用Containered CRI插件以创建容器,而Containered CRI插件调用CNI插件为容器配置网络。网络提供商CNI插件调用其他基本CNI插件来配置网络。 CNI插件之间的交互如下所述。

CNI插件之间的交互

各种CNI插件可帮助配置主机上容器之间的网络。对于这篇文章,我们将参考3个插件。

Flannel CNI Plugin

当使用Flannel作为网络提供程序时,Containered CRI插件使用CNI配置文件/etc/cni/net.d/10-flannel.conflist调用Flannel CNI插件。

$ cat /etc/cni/net.d/10-flannel.conflist
{
  "name": "cni0",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
         "ipMasq": false,
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    }
  ]
}

Fannel CNI插件与Flanneld结合使用。当Flanneld启动时,它会从apiserver中获取podCIDR和其他与网络相关的详细信息,并将它们存储在文件-run/flannel/subnet.env中。

FLANNEL_NETWORK=10.244.0.0/16 
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450 
FLANNEL_IPMASQ=false

Flannel CNI插件使用/run/flannel/subnet.env中的信息来配置和调用网桥CNI插件。

Bridge CNI Plugin

Flannel CNI插件使用以下配置调用Bridge CNI插件:

{
  "name": "cni0",
  "type": "bridge",
  "mtu": 1450,
  "ipMasq": false,
  "isGateway": true,
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/24"
  }
}

首次调用Bridge CNI插件时,它将使用配置文件中指定的"name": "cni0"创建一个Linux网桥。然后,它为每个Pod创建veth对-该对的一端在容器的网络名称空间中,另一端连接到主机网络上的linux桥。使用Bridge CNI插件,主机上的所有容器都连接到主机网络上的linux网桥。

配置完veth对后,Bridge插件将调用主机本地IPAM CNI插件。可以在CNI config中配置要使用的IPAM插件,CRI插件用于调用Flannel CNI插件。

Host-local IPAM CNI 插件

Bridge CNI插件使用以下配置调用Host-local IPAM CNI插件:

{
  "name": "cni0",
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/24",
    "dataDir": "/var/lib/cni/networks"
  }
}

Host-local IPAM(IP地址管理)插件从子网返回容器的IP地址,并将分配的IP本地存储在主机上的dataDir-/var/lib/cni/networks/<network-name=cni0>/<ip>/var/lib /cni/networks/<网络名称=cni0>/<ip>文件包含IP分配给的容器ID。

调用时,Host-local IPAM插件返回以下有效负载:

{
  "ip4": {
    "ip": "10.244.4.2",
    "gateway": "10.244.4.3"
  },
  "dns": {}
}

总结

Kube-controller-manager为每个节点分配一个podCIDR。从podCIDR中的子网值中为节点上的Pod分配IP地址。由于所有节点上的podCIDR是不相交的子网,因此它允许为每个pod分配唯一的IP地址。
Kubernetes集群管理员可配置和安装kubelet,容器运行时,网络提供商代理,并在每个节点上分发CNI插件。网络提供商代理启动时,将生成CNI配置。在节点上调度Pod后,kubelet会调用CRI插件来创建Pod。如果是Containerd,则Containered CRI插件会调用CNI配置中指定的CNI插件来配置Pod网络。所有这些都会使Pod获得IP地址。

PS:本文属于翻译,原文


iyacontrol
1.4k 声望2.7k 粉丝

专注kubernetes,devops,aiops,service mesh。