Kubernetes Pod 如何获取 IP 地址?

笔记。 翻译。:这篇文章由 LinkedIn 的 SRE 工程师撰写,详细介绍了 Kubernetes 的内在魔力 - 更准确地说,是 CRI、CNI 和 kube-apiserver 的交互 - 当下一个 pod 需要分配 IP 地址时会发生这种交互。

基本要求之一 Kubernetes 网络模型 每个 Pod 必须有自己的 IP 地址,并且集群中的任何其他 Pod 都必须能够通过该地址联系它。 有许多网络“提​​供者”(Flannel、Calico、Canal 等)可以帮助实现这种网络模型。

当我第一次开始使用 Kubernetes 时,我并不完全清楚 Pod 到底是如何获取其 IP 地址的。 即使了解各个组件的工作原理,也很难想象它们协同工作。 例如,我知道 CNI 插件的用途,但不知道它们到底是如何调用的。 因此,我决定写这篇文章来分享有关各种网络组件以及它们如何在 Kubernetes 集群中协同工作的知识,这允许每个 pod 获得自己唯一的 IP 地址。

在 Kubernetes 中组织网络有不同的方法,就像容器有不同的运行时选项一样。 本出版物将使用 绒布 在集群中组织网络并作为可执行环境 - 容器化。 我还假设您知道容器之间的网络是如何工作的,因此我将简要介绍一下它,仅供参考。

一些基本概念

容器和网络:简要概述

互联网上有很多优秀的出版物解释容器如何通过网络相互通信。 因此,我只会对基本概念进行一般性概述,并仅限于一种方法,即创建 Linux 桥和封装包。 详细信息被省略,因为容器网络主题本身值得单独撰写一篇文章。 下面将提供一些特别有洞察力和教育性出版物的链接。

一台主机上的容器

在同一主机上运行的容器之间通过 IP 地址组织通信的一种方法是创建 Linux 桥。 为此,在 Kubernetes(和 Docker)中创建虚拟设备 veth(虚拟以太网)。 veth 设备的一端连接到容器的网络命名空间,另一端连接到 Linux桥 在主机网络上。

同一主机上的所有容器都有 veth 的一端连接到网桥,通过网桥它们可以通过 IP 地址相互通信。 Linux 桥还有一个 IP 地址,并充当从 pod 发往其他节点的出口流量的网关。

Kubernetes Pod 如何获取 IP 地址?

不同主机上的容器

数据包封装是一种允许不同节点上的容器使用 IP 地址相互通信的方法。 在 Flannel,技术为这个机会负责。 虚拟局域网,它将原始数据包“打包”成UDP数据包,然后将其发送到目的地。

在 Kubernetes 集群中,Flannel 创建一个 vxlan 设备并相应地更新每个节点上的路由表。 每个发往不同主机上的容器的数据包都会经过 vxlan 设备并封装在 UDP 数据包中。 在目的地,嵌套数据包被提取并转发到所需的 Pod。

Kubernetes Pod 如何获取 IP 地址?
注意:这只是组织容器之间网络通信的一种方法。

什么是 CRI?

CRI(容器运行时接口) 是一个允许 kubelet 使用不同容器运行时环境的插件。 CRI API 内置于各种运行时中,因此用户可以选择自己喜欢的运行时。

什么是CNI?

CNI项目 它代表 规格 为 Linux 容器组织通用网络解决方案。 此外,它还包括 外挂程式,负责设置 Pod 网络时的各种功能。 CNI插件是一个符合规范的可执行文件(我们将在下面讨论一些插件)。

为节点分配子网,以便为 Pod 分配 IP 地址

由于集群中的每个 Pod 都必须有一个 IP 地址,因此确保该地址的唯一性非常重要。 这是通过为每个节点分配一个唯一的子网来实现的,然后从该子网为该节点上的 Pod 分配 IP 地址。

节点 IPAM 控制器

何时 nodeipam 作为标志参数传递 --controllers kube 控制器管理器,它从集群 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 调度到某个节点会触发以下事件链:

Kubernetes Pod 如何获取 IP 地址?

常见问题解答: Containerd CRI 插件的架构.

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

每个网络提供商都有自己的 CNI 插件。 容器的运行时运行它来在 pod 启动时配置网络。 以containerd为例,CNI插件是由插件启动的 容器 CRI.

此外,每个提供商都有自己的代理。 它安装在所有 Kubernetes 节点上,负责 pod 的网络配置。 该代理要么包含在 CNI 配置中,要么在节点上独立创建。 该配置帮助 CRI 插件设置要调用的 CNI 插件。

CNI配置的位置可以自定义; 默认情况下它位于 /etc/cni/net.d/<config-file>。 集群管理员还负责在每个集群节点上安装 CNI 插件。 它们的位置也是可定制的; 默认目录 - /opt/cni/bin.

使用containerd时,可以在 部分中设置插件配置和二进制文件的路径 [plugins.«io.containerd.grpc.v1.cri».cni] в 容器配置文件.

由于我们使用 Flannel 作为我们的网络提供商,我们来谈谈如何设置它:

  • Flanneld(Flannel 的守护进程)通常作为 DaemonSet 安装在集群中 install-cni初始化容器.
  • Install-cni 创建 CNI配置文件 (/etc/cni/net.d/10-flannel.conflist)在每个节点上。
  • Flaneld 创建一个 vxlan 设备,从 API 服务器检索网络元数据,并监控 pod 更新。 创建它们时,它将路由分发到整个集群中的所有 Pod。
  • 这些路由允许 Pod 通过 IP 地址相互通信。

有关 Flannel 工作的更多详细信息,我建议使用文章末尾的链接。

下面是 Containerd CRI 插件和 CNI 插件之间的交互图:

Kubernetes Pod 如何获取 IP 地址?

如上所示,kubelet 调用 Containerd CRI 插件来创建 pod,然后调用 CNI 插件来配置 pod 的网络。 在此过程中,网络提供商的 CNI 插件会调用其他核心 CNI 插件来配置网络的各个方面。

CNI插件之间的交互

有各种 CNI 插件,其作用是帮助在主机上的容器之间建立网络通信。 本文将讨论其中的三个。

CNI 插件 Flannel

当使用 Flannel 作为网络提供者时,Containerd CRI 组件调用 CNI 插件 Flannel使用 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
      }
    }
  ]
}

Flannel CNI 插件与 Flanneld 配合使用。 在启动过程中,Flanneld 从 API 服务器检索 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 插件桥

使用以下配置调用该插件:

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

第一次调用时,它会创建一个 Linux 桥 «name»: «cni0»,这在配置中指出。 然后为每个 pod 创建一个 veth 对。 它的一端连接到容器的网络命名空间,另一端包含在主机网络上的 Linux 桥中。 CNI 插件桥 将所有主机容器连接到主机网络上的 Linux 桥。

完成 veth 对的设置后,Bridge 插件将调用主机本地 IPAM CNI 插件。 IPAM 插件类型可以在 CRI 插件用来调用 Flannel CNI 插件的 CNI 配置中进行配置。

主机本地 IPAM CNI 插件

桥接 CNI 呼叫 主机本地 IPAM 插件 CNI 具有以下配置:

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

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

当调用主机本地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 插件来创建它。 接下来,如果使用containerd,Containerd CRI插件会调用CNI配置中指定的CNI插件来配置pod的网络。 结果,Pod 收到一个 IP 地址。

我花了一些时间才理解所有这些互动的复杂性和细微差别。 我希望这次经历能够帮助您更好地理解 Kubernetes 的工作原理。 如果我有任何错误,请与我联系 Twitter 或在地址 [电子邮件保护]。 如果您想讨论本文的某些方面或其他任何内容,请随时与我们联系。 我很想和你聊天!

引用

容器和网络

法兰绒的工作原理是什么?

CRI 和 CNI

译者PS

另请阅读我们的博客:

来源: habr.com

添加评论