【博客542】k8s使用EndpointSlices扩展大规模service后端服务数量
端点切片(EndpointSlices) 提供了一种简单的方法来跟踪 Kubernetes 集群中的网络端点(network endpoints)。它们为 Endpoints 提供了一种可扩缩和可拓展的替代方案。
k8s使用EndpointSlices扩展大规模service后端服务数量
EndpointSlices
端点切片(EndpointSlices) 提供了一种简单的方法来跟踪 Kubernetes 集群中的网络端点(network endpoints)。 它们为 Endpoints 提供了一种可扩缩和可拓展的替代方案。
出现背景:Endpoint API在大规模service后端的情况下存在较大限制
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。
EndpointSlice API 拆分 Endpoint
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优势
EndpointSlice API 大大提高了网络的可伸缩性:
因为现在添加或删除 Pod 时,只需更新 1 个小的 EndpointSlice。尤其是成百上千个 Pod 支持单个 Service 时,差异将非常明显。更重要的是,既然 Service 的所有 Pod IP 都不需要存储在单个资源中,那么我们就不必担心 etcd 中存储对象的大小限制。EndpointSlice 可以用于扩展到超过 10 万个网络端点的 Service。
EndpointSlice 相关新功能
- Dual-stack Service:是一项与 EndpointSlice 一起开发的新功能。它们利用 IPv4 和 IPv6 地址提供 Service,并依靠 EndpointSlice 上的 addressType 字段按 IP 系列跟踪这些地址。
- Topology aware routing: 会更新 kube-proxy 以 prefer 同一区域或区域内的路由请求。这使用了为 EndpointSlice 端点存储的拓扑字段。另外,目前还在探索 endpoint subsetting 的潜力,未来 kube-proxy 将只允许观察 EndpointSlice 的子集。这可以与 topology aware routing 结合使用,这样 kube-proxy 只需要监控包含同一区域内端点的 EndpointSlice,这将提供另一个非常显着的可伸缩性改进。
属主关系
在大多数场合下,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 的客户端访问会优先路由到该端点上。
示例:为nginx service生成endpointslice,包含三个后端pod,带有hostname的topo键
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 的决策依据。
更多推荐
所有评论(0)