带你搞懂Kubernetes Pod 如何获取 IP 地址

科技   2024-05-15 09:48   四川  

Kubernetes 网络模型的核心要求之一是每个 Pod 都应该有自己的 IP 地址,并且集群中的每个 Pod 都应该能够使用这个 IP 地址与其进行通信。有多个网络提供商(flannel、calico、canal 等)实现了这种网络模型。

在 kubernetes 中设置网络有多种方法,容器运行时也有多种选项。在这篇文章中,我将使用 Flannel作为网络提供程序, 使用 Containerd作为容器运行时。

背景概念

容器网络:非常简短的概述

有一些非常好的帖子解释了容器网络的工作原理。对于上下文,我将在这里使用涉及 Linux 桥接网络和数据包封装的单一方法进行非常高层次的概述。在这里跳过细节。

同一主机上的容器

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

image

不同主机上的容器

在不同主机上运行的容器可以通过其 IP 地址相互通信的方法之一是使用数据包封装。Flannel 通过 vxlan支持此功能,它将原始数据包包装在 UDP 数据包中并将其发送到目的地。

在 kubernetes 集群中,flannel 在每个节点上创建一个 vxlan 设备和一些路由表条目。发往不同主机上的容器的每个数据包都会经过 vxlan 设备并封装在 UDP 数据包中。在目的地,检索封装的数据包并将数据包路由到目标 Pod。

image

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

什么是 CRI?

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

什么是CNI?

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

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

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

节点 IPAM 控制器

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 后,以下交互将导致配置网络并启动应用程序容器。

image

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

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

CNI 配置文件的位置是可配置的,默认值为/etc/cni/net.d/. CNI 插件需要由集群管理员发送到每个节点上。CNI 插件的位置也是可配置的,默认值为/opt/cni/bin。

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

由于我们在这里将 Flannel 称为网络提供商,因此我将稍微讨论一下 Flannel 的设置方式。Flanneld 是 Flannel 守护进程,通常install-cni作为 守护进程集和init 容器安装在 kubernetes 集群上。容器在每个节点上install-cni创建 CNI 配置文件。/etc/cni/net.d/10-flannel.conflistFlaneld 创建一个 vxlan 设备,从 apiserver 获取网络元数据并监视 Pod 上的更新。创建 Pod 时,它会为整个集群中的所有 Pod 分配路由,这些路由允许 Pod 通过其 IP 地址相互连接。有关Flannel工作原理的详细信息,推荐参考官方描述。

Containerd CRI Plugin 和 CNI 插件之间的交互可以可视化如下:

image

如上所述,kubelet 调用 Containerd CRI 插件来创建 pod,Containerd CRI 插件调用 CNI 插件为 pod 配置网络。网络提供商 CNI 插件调用其他基础 CNI 插件来配置网络。CNI 插件之间的交互如下所述。

CNI 插件之间的交互

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

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

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

Fannel CNI 插件与 Flanneld 结合使用。当 Flaneld 启动时,它会从 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 插件。

桥接 CNI 插件

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 插件。使用哪个 IPAM 插件可以在 CNI 配置中配置 CRI 插件用于调用 flannel CNI 插件。

主机本地 IPAM CNI 插件

Bridge CNI 插件 使用以下配置调用主机本地 IPAM CNI 插件:

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

主机本地 IPAM(IP 地址管理)插件从 - 中返回容器的 IP 地址,并将subnet分配的 IP 存储在主机上本地指定的目录下。文件包含分配了 IP 的容器 ID。dataDir/var/lib/cni/networks/<network-name=cni0>/<ip>/var/lib/cni/networks/<network-name=cni0>/<ip>

调用时,主机本地 IPAM 插件返回以下有效负载

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

小结

Kube-controller-manager为每个节点分配一个podCIDR。节点上的 Pod 会根据 podCIDR 中的子网值分配一个 IP 地址。由于所有节点上的 podCIDR 都是不相交的子网,因此它允许为每个 pod 分配唯一的 IP 地址。

Kubernetes 集群管理员配置并安装 kubelet、容器运行时、网络提供商代理并在每个节点上分发 CNI 插件。当网络提供商代理启动时,它会生成 CNI 配置。当 pod 被调度到节点上时,kubelet 会调用 CRI 插件来创建 pod。在containerd的情况下,Containerd CRI插件然后调用CNI配置中指定的CNI插件来配置pod网络。所有这些都会导致 Pod 获得 IP 地址。

参考:https://ronaknathani.com/blog/2020/08/how-a-kubernetes-pod-gets-an-ip-address/



运维开发故事
由一群志同道合的小伙伴共同维护,有运维也有开发,内容不限于Linux运维,devops工具链,k8s容器化技术,监控,日志收集,网络安全,Python或GO开发,团队成员有乔克、wanger、冬哥、素心、华仔、郑哥、夏老师
 最新文章