端点切片(EndpointSlices) 提供了一种简单的方法来跟踪 Kubernetes 集群中的网络端点(network endpoints)。 它们为 Endpoints 提供了一种可扩缩和可拓展的替代方案。
Endpoint API 可伸缩性限制:
如果使用 Endpoint API,Service 只有一个 Endpoint 资源。这意味着它需要为 Service 的每个 Pod 都存储好 IP 地址和端口(网络端点),这需要大量的 API 资源。另外,kube-proxy 会在每个节点上运行,并监控 Endpoint 资源的任何更新。如果 Endpoint 资源中有一个端口发生更改,那么整个对象都会分发到 kube-proxy 的每个实例。
Endpoint API 另一个局限:
它会限制跟踪 Service 的网络端点数量。一般存储在 etcd 中的对象默认大小限制为 1.5MB。在某些情况下,它会将 Endpoint 资源限制为 5000 个 Pod IP。对于大多数用户而言,这没什么关系,但是对于接近这个大小的 Service 而言,就有大问题了。
举例:
如果一个 Service 有 5000 个 Pod,它如果有 1.5MB 的 Endpoint 资源。当该列表中的某个网络端点发生了变化,那么就要将完整的 Endpoint 资源分发给集群中的每个节点。在具有 3000 个节点的大型集群中,这会是个很大的问题。每次更新将跨集群发送 4.5GB 的数据(1.5MB3000,即 Endpoint 大小 节点个数),并且每次端点更新都要发送这么多数据。想象一下,如果进行一次滚动更新,共有 5000 个 Pod 全部被替换,那么传输的数据量将超过 22 TB。
ndpointSlice API 旨在通过类似于分片的方法来解决该问题。我们不跟踪 Service Pod IP 的单个 Endpoint 资源,而是将它们拆分为多个较小的 EndpointSlice。
举个例子,现在有 15 个 Pod 在支持一个 Service,那么就有跟踪这些的一个 Endpoint 资源。如果将 EndpointSlice 配置为每个 EndpointSlice 存储 5 个端点,就得到了 3 个不同的 EndpointSlice:默认情况下,EndpointSlice 每个存储能多达 100 个端点,我们可以使用 kube-controller-manager 的 --max-endpoints-per-slice 标签进行配置。
EndpointSlice API 大大提高了网络的可伸缩性:
因为现在添加或删除 Pod 时,只需更新 1 个小的 EndpointSlice。尤其是成百上千个 Pod 支持单个 Service 时,差异将非常明显。更重要的是,既然 Service 的所有 Pod IP 都不需要存储在单个资源中,那么我们就不必担心 etcd 中存储对象的大小限制。EndpointSlice 可以用于扩展到超过 10 万个网络端点的 Service。
在大多数场合下,EndpointSlice 都由某个 Service 所有, (因为)该端点切片正是为该服务跟踪记录其端点。这一属主关系是通过为每个 EndpointSlice 设置一个属主(owner)引用,同时设置 kubernetes.io/service-name 标签来标明的, 目的是方便查找隶属于某 Service 的所有 EndpointSlice。
控制面(尤其是端点切片的控制器) 会创建和管理 EndpointSlice 对象。EndpointSlice 对象还有一些其他使用场景, 例如作为服务网格(Service Mesh)的实现。这些场景都会导致有其他实体 或者控制器负责管理额外的 EndpointSlice 集合。
为了确保多个实体可以管理 EndpointSlice 而且不会相互产生干扰,Kubernetes 定义了标签 endpointslice.kubernetes.io/managed-by,用来标明哪个实体在管理某个 EndpointSlice。端点切片控制器会在自己所管理的所有 EndpointSlice 上将该标签值设置 为 endpointslice-controller.k8s.io。 管理 EndpointSlice 的其他实体也应该为此标签设置一个唯一值。
EndpointSlice 中的每个端点都可以包含一定的拓扑信息。 拓扑信息包括端点的位置,对应节点、可用区的信息。 这些信息体现为 EndpointSlices 的如下端点字段:
nodeName - 端点所在的 Node 名称;
zone - 端点所处的可用区。
这些拓扑信息可以成为流量转发时的优先匹配依据,也成为了kube-proxy组件生成流量转发拓扑的iptables的依据
我们知道 Endpoint 通常情况下是由 Service 资源自动创建和管理的,但是随着 Kubernetes 集群的规模越来越大和管理的服务越来越多,Endpoint API 的局限性变得越来越明显。 端点切片(EndpointSlices)提供了一种简单的方法来跟踪 Kubernetes 集群中的网络端点。它们为 Endpoint 提供了一种可伸缩和可拓展的替代方案,同时还可以被用到拓扑感知路由中。
EndpointSlices 示例如下:
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: example-hints
labels:
kubernetes.io/service-name: example-svc
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 80
endpoints:
- addresses:
- "10.127.2.3"
conditions:
ready: true
hostname: pod-1
nodename: node-a
zone: zone-a
EndpointSlice 中的每个端点都可以包含一定的拓扑信息。 拓扑信息包括端点的位置,对应节点、可用区的信息。 这些信息体现为 EndpointSlices 的如下端点字段:
nodeName - 端点所在的 Node 名称
zone - 端点所处的可用区
hostname - 端点的 pod 名称
启用 kube-apiserver、kube-controller-manager、和 kube-proxy 的特性门控 TopologyAwareHints。通过把 Service 中的注解 service.kubernetes.io/topology-aware-hints 的值设置为 auto, 来激活服务的拓扑感知提示功能。 这告诉 EndpointSlice 控制器在它认为安全的时候来设置拓扑提示。kube-proxy 组件依据 EndpointSlice 控制器设置的提示,过滤由它负责路由的端点。
由 EndpointSlice 控制器提供提示信息后 EndpointSlice 的示例如下:
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: example-hints
labels:
kubernetes.io/service-name: example-svc
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 80
endpoints:
- addresses:
- "10.1.2.3"
conditions:
ready: true
hostname: pod-1
zone: zone-a
hints:
forZones:
- name: "zone-a"
我们看到其中已注入了 hints 信息,对于上面这个示例,zone-a 的客户端访问会优先路由到该端点上。
addressType: IPv4
apiVersion: discovery.k8s.io/v1beta1
endpoints:
- addresses:
- 10.244.1.45
conditions:
ready: true
targetRef:
kind: Pod
name: nginx-deployment-pdhhz
namespace: default
topology:
kubernetes.io/hostname: 10.1.2.20
- addresses:
- 10.244.2.51
conditions:
ready: true
targetRef:
kind: Pod
name: nginx-deployment-j5wfx
namespace: default
resourceVersion: "15352701"
uid: 67b97b7a-7829-420b-b5e3-2182c2ebd785
topology:
kubernetes.io/hostname: 10.1.2.21
- addresses:
- 10.244.5.70
conditions:
ready: true
targetRef:
kind: Pod
name: nginx-deployment-x2fgf
namespace: default
resourceVersion: "15352705"
uid: 7332ace0-c080-4570-8f8e-c8e114aad287
topology:
kubernetes.io/hostname: 10.1.2.22
kind: EndpointSlice
metadata:
labels:
app: nginx
endpointslice.kubernetes.io/managed-by: endpointslice-controller.k8s.io
kubernetes.io/service-name: nginx
name: nginx-ncf2b
namespace: default
ownerReferences:
- apiVersion: v1
blockOwnerDeletion: true
controller: true
kind: Service
name: nginx
ports:
- name: ""
port: 80
protocol: TCP
默认情况下,控制面创建和管理的 EndpointSlice 将包含不超过 100 个端点。 你可以使用 kube-controller-manager 的 --max-endpoints-per-slice 标志设置此值,最大值为 1000。
当涉及如何路由内部流量时,EndpointSlice 可以充当 kube-proxy 的决策依据。