10.1 端点分片
kubernetes从1.19版本开始,EndpointSplice机制以及EndpointSliceProxying
是默认开启的:
通过设置
kube-apiserver
和kube-proxy
服务的启动参数--feature-gates=“EndpointSlice=true“
进行启用。kube-proxy默认仍然使用Endpoint对象,为了提高性能,可以设置 kube-proxy启动参数--feature-gates-=“EndpointSliceProxying=true“
让kube-proxy 使用EndpointSlice,这样可以减少kube-proxy与master之间的网络通信并提高性能。
以一个3副本的webapp服务为例,Pod列表如下:
服务和Endpoint的信息如下:
查看EndpointSlice,可以看到系统自动创建了一个名称前缀为“webapp-
”的EndpointSlice:
查看其详情信息,可以看到3个Endpoint的IP地址和端口信息,同时为Endpoint设置了Topology相关信息:
10.1.1 参数
默认情况下,在由EndpointSlice控制器创建的EndpointSlice中最多包含100个Endpoint,如需修改,则可以通过kube-controller-manager服务的启动参数-- max-endpoints-per-slice
设置,但上限不能超过1000。
EndpointSlice的关键信息如下:
配置项 | 描述 |
关联的服务名称 | 将EndpointSlice与Service的关联信息设置为一个标签kubernetes.io/service-name=webapp ,该标签标明了服务名称 |
地址类型AddressType | 包括以下3种取值类型: IPv4:IPv4格式的IP地址 IPv6:Pv6格式的IP地址 FQDN:全限定域名. |
每个Endpoint的信息 | 在Endpoints列表中列出的每个Endpoint的信息: Addresses:Endpoint的IP地址; Conditions:Endpoint状态信息,作为EndpointSlice的查询条件; Hostname:在Endpoint中设置的主机名nostname; TargetRef:Endpoint对应的Pod名称; Topology:拓扑信息,为基于拓扑感知的服务路由提供数据。 目前EndpointSlice控制器自动设置的拓扑信息如下: —— kubernetes.io/hostname:Endpoint所在Node的名称; —— topology.kubernetes.io/zone:Endpoint所在的Zone信息,使用Node标签topology.kubernetes.io/zone的值,例如上例中的Node拥有 topology.kubernetes.io/zone:north"标签。 —— topology.kubernetes.io/region:Endpoint所在的Region信息,使用Node标签topology.kubernetes.io/region的值。 在大规模集群中,管理员应对不同地域或不同区域的Node设置相关的 topology标签,用于为Node设置拓扑信息. |
EndpointSlice的管理控制器 | 通过endpointslice.kubernetes.io/managed-by 标签进行设置,用于存在多个管理控制器的应用场景中,例如某个Service Mesh 管理工具也可以对EndpointSlice 进行管理。为了支持多个管理工具对EndpointSlice 同时进行管理并且互不干扰,可以通过endpointslice.kubernetes.io/managed--by 标签设置管理控制器的名称,Kubernetes内置的EndpointSlice控制器自动设置该标签的值为endpointslice-controller.k8s.io ,其他管理控制器应设置唯一名称用于标识. |
10.1.2 复制功能
EndpointSlice复制(Mirroring)功能:应用程序有时可能会创建自定义的Endpoint资源,为了避免应用程序在创建Endpoint资源时再去创建EndpointSlice资源,Kubernetes控制平面会 自动完成 将Endpoint资源复制为EndpointSlice资源的操作。
以下几种情况下,不会执行自动复制操作:
- Endpoint资源设置了Label:endpointslice.kubernetes.io/skip-mirror=true;
- Endpoint资源设置了Annotation:control-plane.alpha.kubernetes.io/leader;
- Endpoint资源对应的Service资源不存在;
- Endpoint:资源对应的Service资源设置了非空的Selector;
一个Endpoint资源同时存在IPv4和IPv6地址类型时,会被复制为多个EndpointSlice资源,每种地址类型最多会被复制为1000个EndpointSlice资源。
10.1.3 数据分布管理机制
如上例所示,我们可以看到每个EndpointSlice资源都包含一组作用于全部Endpoint的端口号(Ports)。如果Service定义中的端口号使用了字符串名称,则对于相同name的端口号,目标Pod 的targetPort可能是不同的,结果是EndpointSlice资源将会不同。这与Endpoint 资源设置子集(subset)的逻辑是相同的。
Kubernetes控制平面对于EndpointSlice中数据的管理机制是尽可能填满,但不会在多个EndpointSlice数据不均衡衡的情况下主动执行重新平衡(rebalance)操作,其背后的逻辑也很简单,步骤如下:
- 遍历当前所有EndpointSlice资源,删除其中不再需要的Endpoint,更新已更改的匹配Endpoint;
- 遍历第1步中已更新的EndpointSlice资源,将需要添加的新Endpoint填充进去;
- 如果还有新的待添加Endpoint,则尝试将其放入之前未更新的EndpointSlice中,或者尝试创建新的EndpointSlicez并添加。
重要的是,第3步优先考虑创建新的EndpointSlice而不是更新原EndpointSlice。例如,如果要添加l0个新的Endpoint,则当前有两个EndpointSlice各有5个剩余空间可用于填充,系统也会创建一个新的EndpointSlice用来填充这10个新Endpoint。换句话说,单个EndpointSlice的创建优于对多个EndpointSlice的更新。
以上主要是由于在每个节点上运行的kube-proxy都会持续监控EndpointSlice的变化,对EndpointSlice每次更新成本都很高,因为每次更新都需要Master
将更新数据发送到每个kube-proxy
。
上述管理机制旨在限制需要发送到每个节点的更新数据量,即使可能导致最终有许多EndpointSlice资源未能填满。实际上,这种不太理想的数据分布情况应该是罕见的。
Master的EndpointSlice控制器处理的大多数更新所带来的数据量都足够小,使得对已存在 (仍有空余空间)EndpointSlice的数据填充都没有问题,如果实在无法填充,则无论如何都需要创建新的EndpointSlice资源。
此外,对Deployment执行滚动升级操作时,由于后端Pod列表和相关Endpoint列表全部会发生变化,所以也会很自然地对EndpointSlice资源的内容全部进行更新。
10.2 服务拓扑
在默认情况下,发送到一个Service的流量会被均匀转发到每个后端Endpoint,但无法根据更复杂的拓扑信息设置复杂的路由策略。服务拓扑机制的引入就是为了实现基于Node拓扑的服务路由,允许Service创建者根据来源Node和目标Node的标签来定义流量路由策略。
通过对来源Node和目标Node标签的匹配,用户可以根据业务需求对Node进行分组,设置有意义的指标值来标识 “较近” 或者 “较远” 的属性:
例如:对于公有云环境来说,通常有区域(Zone或Region)的划分,云平台倾向于把服务流量限制在同一个区域内,这通常是因为跨区域网络流量会收取额外的费用。另一个例子是把流量路由到由DaemonSet管理的当前Node的Pod 上。又如希望把流量保持在相同机架内的Node上,以获得更低的网络延时。
10.2.1 配置
服务拓扑机制需要通过设置kube-apiserver
和kube-proxy
服务的启动参数--feature-gates-=“ServiceTopology=true,EndpointSlice=true“
进行启用(需要同时启用EndpointSlice
功能),然后就可以在Service
资源对象上通过定义 topologyKeys
字段来控制到Service的流量路由了。
对于需要使用服务拓扑机制的集群,管理员需要为Node设置相应的拓扑标签,包括kubernetes.io/hostname
、topology.kubernetes.io/zone
和topology.kubernetes.io/region
。
然后为Service设置topologyKeys的值,就可以实现如下流量路由策略:
- 配置为[“kubernetes.io/hostname“]:流量只会被路由到相同Node的
Endpoint上,如果Node的Endpoint不存在,则将请求丢弃。 - 配置为[“kubernetes.io/hostname" "topology.kubernetes.io/zone“ “topology.kubernetes.io/region“]:流量优先被路由到相同Node的Endpoint上, 如果Node没有Endpoint,流量则被路由到同zone的Endpoint,如果在zone中没有Endpoint,流量则被路由到通region中的Endpoint上。
- 配置为[“topology.kubernetes.io/zone“,“
*
“]:流量优先被路由到同zone 的Endpoint上,如果在zone中没有可用的Endpoint,流量则被路由到任意可用的
Endpoint上。
目前使用服务拓扑有以下几个约束条件:
- 服务拓扑和externalTrafficPolicy=Local是不兼容的,所以一个Service不能同时使用这两种特性。在同一个Kubernetes集群中,启用服务拓扑的Service和设置externalTrafficPolicy=Local特性的Service:是可以同时存在的。
- topologyKeys目前可以设置的标签只有3个:kubernetes.io/hostname、topology.kubernetes.io/zone和topology.kubernetes.io/region,未来会增加更多 的标签。
- topologyKeys必须是有效的标签格式,并且最多定义16个。
- 如需使用通配符“*”,则它必须是最后一个值。
10.2.2 举例
下面通过Service的YAML文件对几种常见的服务拓扑应用实例进行说明。
① 只将流量路由到相同Node的Endpoint上,如果Node没有可用的Endpoint,则将请求丢弃:
apiVersion: v1 kind: Service metadata: name: webapp spec: selector: app: webapp ports: - port: 8080 topologykeys: - "kubernetes.io/hostname"
② 优先将流量路由到相同Node的Endpoint上,如果Node没有可用的Endpoint,则将请求路由到任意可用的Endpoint:
apiVersion: v1 kind: Service metadata: name: webapp spec: selector: app: webapp ports: - port:8080 topologyKeys: - "kubernetes.io/hostname" - "*"
③ 只将流量路由到相同zone或同region的Endpoint上,如果没有可用的Endpoint,则将请求丢弃:
apiVersion: v1 kind: Service metadata: name: webapp spec: selector: app: webapp ports: - port:8080 topologyKeys: - "topology.kubernetes.io/zone" - "topology.kubernetes.io/region"
④ 按同Node、同zone、同region的优先级顺序路由流量,如果Node、 zone、region都没有可用的Endpoint,则将请求路由到集群内任意可用的Endpoint.上:
apiVersion: v1 kind: Service metadata: name: webapp spec: selector: app: webapp ports: - port:8080 topologyKeys: - "kubernetes.io/hostname" - "topology.kubernetes.io/zone" - "topology.kubernetes.io/region" - "*"