
端点切片(EndpointSLIces)
FEATURESTATE:Kubernetesv1.21[stable]
端点切片(EndpointSlices)提供了一种简单的方法来跟踪Kubernetes集群中的网络端点(networkendpoints)。它们为Endpoints提供了一种可伸缩和可拓展的替代方案。
动机
EndpointsAPI提供了在Kubernetes跟踪网络端点的一种简单而直接的方法。不幸的是,随着Kubernetes集群和服务逐渐开始为更多的后端Pods处理和发送请求,原来的API的局限性变得越来越明显。最重要的是那些因为要处理大量网络端点而带来的挑战。
由于任一服务的所有网络端点都保存在同一个Endpoints资源中,这类资源可能变得非常巨大,而这一变化会影响到Kubernetes组件(比如主控组件)的性能,并在Endpoints变化时产生大量的网络流量和额外的处理。EndpointSlice能够帮助你缓解这一问题,还能为一些诸如拓扑路由这类的额外功能提供一个可扩展的平台。
EndpointSlice资源
在Kubernetes中,
EndpointSlice
包含对一组网络端点的引用。指定选择器后控制面会自动为设置了选择算符的Kubernetes服务创建EndpointSlice。这些EndpointSlice将包含对与服务选择算符匹配的所有Pod的引用。EndpointSlice通过唯一的协议、端口号和服务名称将网络端点组织在一起。EndpointSlice的名称必须是合法的DNS子域名。
例如,下面是Kubernetes服务的EndpointSlice资源示例。
apiVersion: discovery.k8s.io/v1kind: EndpointSlicemetadata:name: example-abclabels:kubernetes.io/service-name: exampleaddressType: IPv4ports:- name: httpprotocol: TCPport: 80endpoints:- addresses:- "10.1.2.3"conditions:ready: truehostname: pod-1nodeName: node-1zone: us-west2-a
默认情况下,控制面创建和管理的EndpointSlice将包含不超过100个端点。你可以使用kube-controller-Manager的
--max-endpoints-per-slice
标志设置此值,最大值为1000。
当涉及如何路由内部流量时,EndpointSlice可以充当kube-proxy的决策依据。启用该功能后,在服务的端点数量庞大时会有可观的性能提升。
地址类型
EndpointSlice支持三种地址类型:
状况
EndpointSliceAPI存储了可能对使用者有用的、有关端点的状况。这三个状况分别是、和
terminating
。
Ready(就绪)
状况是映射Pod的状况的。处于运行中的Pod,它的状况被设置为,应该将此EndpointSlice状况也设置为。出于兼容性原因,当Pod处于终止过程中,永远不会为。消费者应参考状况来检查处于终止中的Pod的就绪情况。该规则的唯一例外是将
spec.publishNotReadyAddresses
设置为的服务。这些服务(Service)的端点将始终将状况设置为。
Serving(服务中)
FEATURESTATE:Kubernetesv1.20[alpha]
状况与状况相同,不同之处在于它不考虑终止状态。如果EndpointSliceAPI的使用者关心Pod终止时的就绪情况,就应检查此状况。
Terminating(终止中)
FEATURESTATE:Kubernetesv1.20[alpha]
Terminating
是表示端点是否处于终止中的状况。对于Pod来说,这是设置了删除时间戳的Pod。
拓扑信息
EndpointSlice中的每个端点都可以包含一定的拓扑信息。拓扑信息包括端点的位置,对应节点、可用区的信息。这些信息体现为EndpointSlices的如下端点字段:
管理
通常,控制面(尤其是端点切片的控制器)会创建和管理EndpointSlice对象。EndpointSlice对象还有一些其他使用场景,例如作为服务网格(ServiceMesh)的实现。这些场景都会导致有其他实体或者控制器负责管理额外的EndpointSlice集合。
为了确保多个实体可以管理EndpointSlice而且不会相互产生干扰,Kubernetes定义了标签
endpointslice.kubernetes.io/managed-by
,用来标明哪个实体在管理某个EndpointSlice。端点切片控制器会在自己所管理的所有EndpointSlice上将该标签值设置为
endpointslice-controller.k8s.io
。管理EndpointSlice的其他实体也应该为此标签设置一个唯一值。
属主关系
在大多数场合下,EndpointSlice都由某个Service所有,(因为)该端点切片正是为该服务跟踪记录其端点。这一属主关系是通过为每个EndpointSlice设置一个属主(owner)引用,同时设置
kubernetes.io/service-name
标签来标明的,目的是方便查找隶属于某服务的所有EndpointSlice。
EndpointSlice镜像
在某些场合,应用会创建定制的Endpoints资源。为了保证这些应用不需要并发的更改Endpoints和EndpointSlice资源,集群的控制面将大多数Endpoints映射到对应的EndpointSlice之上。
控制面对Endpoints资源进行映射的例外情况有:
每个Endpoints资源可能会被翻译到多个EndpointSlices中去。当Endpoints资源中包含多个子网或者包含多个IP地址族(IPv4和IPv6)的端点时,就有可能发生这种状况。每个子网最多有1000个地址会被镜像到EndpointSlice中。
EndpointSlices的分布问题
每个EndpointSlice都有一组端口值,适用于资源内的所有端点。当为服务使用命名端口时,Pod可能会就同一命名端口获得不同的端口号,因而需要不同的EndpointSlice。这有点像Endpoints用来对子网进行分组的逻辑。
控制面尝试尽量将EndpointSlice填满,不过不会主动地在若干EndpointSlice之间执行再平衡操作。这里的逻辑也是相对直接的:
这里比较重要的是,与在EndpointSlice之间完成最佳的分布相比,第三步中更看重限制EndpointSlice更新的操作次数。例如,如果有10个端点待添加,有两个EndpointSlice中各有5个空位,上述方法会创建一个新的EndpointSlice而不是将现有的两个EndpointSlice都填满。换言之,与执行多个EndpointSlice更新操作相比较,方法会优先考虑执行一个EndpointSlice创建操作。
由于kube-proxy在每个节点上运行并监视EndpointSlice状态,EndpointSlice的每次变更都变得相对代价较高,因为这些状态变化要传递到集群中每个节点上。这一方法尝试限制要发送到所有节点上的变更消息个数,即使这样做可能会导致有多个EndpointSlice没有被填满。
在实践中,上面这种并非最理想的分布是很少出现的。大多数被EndpointSlice控制器处理的变更都是足够小的,可以添加到某已有EndpointSlice中去的。并且,假使无法添加到已有的切片中,不管怎样都会快就会需要一个新的EndpointSlice对象。Deployment的滚动更新为重新为EndpointSlice打包提供了一个自然的机会,所有Pod及其对应的端点在这一期间都会被替换掉。
重复的端点
由于EndpointSlice变化的自身特点,端点可能会同时出现在不止一个EndpointSlice中。鉴于不同的EndpointSlice对象在不同时刻到达Kubernetes的监视/缓存中,这种情况的出现是很自然的。使用EndpointSlice的实现必须能够处理端点出现在多个切片中的状况。关于如何执行端点去重(deduplication)的参考实现,你可以在
kube-proxy
的
EndpointSlice
实现中找到。
发表评论