十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Karmada Cluster Accurate Scheduler Estimator 深度解析:基于 gRPC 的精确副本估算与节点约束调度

Karmada Cluster Accurate Scheduler Estimator 深度解析:基于 gRPC 的精确副本估算与节点约束调度 Karmada Cluster Accurate Scheduler Estimator 深度解析基于 gRPC 的精确副本估算与节点约束调度【免费下载链接】karmadaOpen, Multi-Cloud, Multi-Cluster Kubernetes Orchestration项目地址: https://gitcode.com/GitHub_Trending/ka/karmada导读在多集群场景下Karmada 调度器karmada-scheduler传统上只能依赖Cluster.Status中的NodeSummary与ResourceSummary感知成员集群的整体资源无法感知单个节点的空闲资源以及NodeSelector、NodeAffinity、Tolerations等节点级约束容易把副本过度投放到总量充足但单节点无法容纳的集群导致大量 Pod 长时间处于 Pending 状态。本文以 Karmada 官方设计提案 docs/proposals/scheduling/521-scheduler-estimator/README.mdKEP-521状态implemented为骨架结合当前仓库的源码实现深入讲解Karmada Cluster Accurate Scheduler Estimatorkarmada-scheduler-estimator的动机、架构设计、API 变更、gRPC 通信协议、服务端估算算法以及它如何与 Karmada Scheduler 协作实现按节点真实可用资源精确估算副本数的调度决策。读完本文你将掌握该组件的完整工作原理、启动参数、部署方式与源码级实现细节。一、背景与动机为何需要精确估算1.1 现有调度器的资源感知盲区在多集群中工作负载日益异构化不同工作负载的调度诉求差异很大有的要求节点带有特定标签NodeSelector有的要求节点亲和NodeAffinity有的需要容忍节点污点Tolerations。而 Karmada Scheduler 在此之前无法感知成员集群中每个节点的动态资源与 Pod 请求资源——它只能根据Cluster.Status中聚合的NodeSummary与ResourceSummary得知集群的整体资源情况。当工作负载带有副本资源声明Replica Resource Claim时调度器无法回答一个关键问题某个成员集群到底能放下多少个副本如果估算不准而投放了过多副本就会产生无法调度的 Pending Pod。1.2 两个典型用户故事KEP-521 用两个故事精确刻画了聚合资源估算的失真场景二者均假设ReplicaDivisionPreference为AggregatedStory 1单节点容量不足集群 A10 个节点每节点剩余 8 CPU集群 B2 个节点每节点剩余 16 CPU工作负载1 个副本请求 12 CPU。按总量估算集群 A 剩余 CPU80远多于集群 B32工作负载会被调度到集群 A——但由于 A 没有任何单节点能容纳 12 CPU 的请求Pod 将无法被调度。真正能容纳该工作负载的只有集群 B。Story 2NodeSelector 不匹配集群 A10 个节点每节点剩余 16 CPU集群 B2 个带标签keyvalue的节点每节点剩余 16 CPU工作负载1 个副本带NodeSelector: keyvalue请求 12 CPU。同样地集群 A 因总量更优而被选中但没有任何节点满足NodeSelector只有集群 B 能承载该工作负载。这两个故事的结论一致集群资源总量充足与节点能够实际容纳是两回事。这正是 Karmada Cluster Accurate Scheduler Estimator 要解决的问题。1.3 Goals 与 Non-GoalsKEP 明确划定了目标边界Goals让可用副本估算对调度决策更精确允许用户为多集群调度指定节点约束NodeAffinity、NodeSelector、Tolerations。Non-Goals不负责估算已调度失败Pending/Unschedulable的 Pod 数量用于重调度决策该能力后来由GetUnschedulableReplicasgRPC 方法在仓库中实现了见后文但 KEP 原始范围未包含它不负责 group/gang 调度一组成员必须同时可调度场景下的可用副本组估算。二、总体架构与设计思路2.1 新组件定位提案引入一个新组件Karmada Cluster Accurate Scheduler Estimator二进制名为karmada-scheduler-estimator它本质上是一个gRPC 服务端为 Karmada Scheduler 提供某个成员集群最多还能容纳多少副本的精确估算服务。核心设计决策体现在三方面估算结果对调度影响重大副本分配前Karmada Scheduler 会并发地向各候选集群对应的 Estimator 发起 gRPC 请求获得每个集群的可用副本上限再据此分配副本估算方式插件化原基于ResourceSummary估算的方法保留为默认实现general-estimator精确估算scheduler-estimator作为可切换的新实现加入在仓库当前实现中calAvailableReplicas会遍历注册表中的所有ReplicaEstimator并取各估算器结果的最小值见 pkg/scheduler/core/util.go 与mergeReplicaResults一个 Estimator 只服务一个成员集群与karmada-agent的部署模式一致每个成员集群对应一个karmada-scheduler-estimator实例。2.2 架构工作流上图展示了完整的数据流Karmada Scheduler 先通过 ClusterAffinity、APIInstalled、TaintToleration 等现有插件完成集群预选Select Clusters在 Assign Replicas 阶段进入Calculate Cluster Available Replicas原逻辑基于缓存的Resource Summary做估算启用后则通过gRPC client向每个候选成员集群的scheduler-estimator服务端发送请求携带 Pod 资源需求与Resource ClaimPodRequest、NodeAffinity、NodeSelector、Tolerations每个scheduler-estimator利用本地pod/node informer 缓存结合约束精确计算该集群可容纳的最大副本数并返回Karmada Scheduler 汇总各集群结果完成副本分配。三、API 变更NodeClaim 进入 ResourceBinding3.1 设计草案中的变更KEP 设计阶段提出两处关键 API 变更在ResourceBinding中增加NodeAffinity、NodeSelector、Tolerations与既有的ResourceRequest一起构成NodeClaim节点声明将原本位于ObjectReference中的ReplicaResourceRequirements与Replicas两个字段迁移到ResourceBindingSpec中。KEP 给出了如下 Go 结构定义// ResourceBindingSpec represents the expectation of ResourceBinding. type ResourceBindingSpec struct { // Resource represents the Kubernetes resource to be propagated. Resource ObjectReference json:resource // ReplicaRequirements represents the resource and scheduling requirements for each replica. // optional ReplicaRequirements *ReplicaRequirements json:replicaRequirements,omitempty // Replicas represents the replica number of the referencing resource. // optional Replicas int32 json:replicas,omitempty // Clusters represents target member clusters where the resource to be deployed. // optional Clusters []TargetCluster json:clusters,omitempty } // ReplicaRequirements represents the resource and scheduling requirements for each replica. type ReplicaRequirements struct { // NodeClaim represents the node claim HardNodeAffinity, NodeSelector and Tolerations required by each replica. // optional NodeClaim *NodeClaim json:nodeClaim,omitempty // ResourceRequest represents the resources required by each replica. // optional ResourceRequest corev1.ResourceList json:resourceRequest,omitempty } // NodeClaim represents the node claim HardNodeAffinity, NodeSelector and Tolerations required by each replica. type NodeClaim struct { // A node selector represents the union of the results of one or more label queries over a set of // nodes; that is, it represents the OR of the selectors represented by the node selector terms. // Note that only PodSpec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution // is included here because it has a hard limit on pod scheduling. // optional HardNodeAffinity *corev1.NodeSelector json:hardNodeAffinity,omitempty // NodeSelector is a selector which must be true for the pod to fit on a node. // Selector which must match a nodes labels for the pod to be scheduled on that node. // optional NodeSelector map[string]string json:nodeSelector,omitempty // If specified, the pods tolerations. // optional Tolerations []corev1.Toleration json:tolerations,omitempty }3.2 仓库中的落地实现该设计已在当前仓库完整落地于 pkg/apis/work/v1alpha2/binding_types.go。与草案相比落地版本还有几处演化ReplicaRequirements增加了Namespace与PriorityClassName字段——前者供配额感知估算使用后者用于ResourceQuota以优先级类为作用域的配额校验新增Component/ComponentReplicaRequirements用于多 Pod 模板multi-podtemplate工作负载的成组估算TargetCluster增加了可选的Components []TargetComponent用于记录多组件工作负载在每个集群内的按组件副本分配。一个值得注意的语义细节NodeClaim.HardNodeAffinity只覆盖PodSpec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution硬性必须满足的亲和约束因为只有它会对 Pod 调度形成硬性限制软性偏好preferred不影响能否放下故不纳入。四、gRPC 协议定义4.1 Service 定义服务定义位于 pkg/estimator/service/service.protoEstimatorservice 暴露三个 RPCservice Estimator { rpc MaxAvailableReplicas(pb.MaxAvailableReplicasRequest) returns (pb.MaxAvailableReplicasResponse) {} rpc MaxAvailableComponentSets(pb.MaxAvailableComponentSetsRequest) returns (pb.MaxAvailableComponentSetsResponse) {} rpc GetUnschedulableReplicas(pb.UnschedulableReplicasRequest) returns (pb.UnschedulableReplicasResponse) {} }MaxAvailableReplicas单 Pod 模板工作负载的可用副本估算对应 KEP 原始范围MaxAvailableComponentSets多组件工作负载完整组件集合数量的估算后续演化的能力GetUnschedulableReplicas统计某个工作负载在集群中处于 Unschedulable 状态的副本数对应 KEP Non-Goals 中不估算已调度失败副本的边界——它在仓库中已实现主要服务于重调度场景。请求与响应消息定义在 pkg/estimator/pb/estimator.proto。其中MaxAvailableReplicasRequest携带cluster目标集群名、ReplicaRequirements每副本资源与节点约束并可选携带AssumedWorkloads已分配但 Pod 尚未绑定到节点的在途工作负载用于防止连续调度轮次中的过度承诺。注意ComponentReplicaRequirements中早期使用mapstring, k8s Quantity的resourceRequest字段已被保留reserved替换为resourceRequestBytesproto 序列化的resource.Quantity以去掉对 K8s Quantity 类型的直接依赖。4.2 客户端实现客户端位于 pkg/estimator/client 目录核心要点估算器注册表replicaEstimators与unschedulableReplicaEstimators两个 map 保存注册的估算器GetReplicaEstimators()供调度器遍历使用见 pkg/estimator/client/interface.go两种内置估算器general-estimatorpkg/estimator/client/general.go基于cluster.Status.ResourceSummary的默认估算即available allocatable - allocated - allocating的聚合式算法可结合AllocatableModelings自定义集群资源模型细化scheduler-estimatorpkg/estimator/client/accurate.go通过 gRPC 调用远端karmada-scheduler-estimator的精确估算器。并发请求getClusterReplicasConcurrently对多个集群并行发起 gRPC 调用并附加对象信息到 gRPC metadata配合context.WithTimeout控制整体超时失败返回特殊值UnauthenticReplica -1调度器会丢弃该结果并回退依赖其他估算器的结果pkg/estimator/client/interface.go。调度器侧的调用链在 pkg/scheduler/core/util.gocalAvailableReplicas先为非工作负载如 ServiceAccount、ConfigMap 等spec.Replicas 0且无组件直接返回MaxInt32边界随后对每个注册估算器执行MaxAvailableReplicas通过mergeReplicaResults取各估算器结果的最小值作为最终可用副本数。五、服务端实现AccurateSchedulerEstimatorServer5.1 启动流程与缓存构建AccurateSchedulerEstimatorServer定义在 pkg/estimator/server/server.go。其启动流程Start方法清晰地印证了 KEP 的设计启动并等待SharedInformerFactory同步——Pod、Node、ReplicaSet 的 informer 作为本地缓存Pod informer 通过字段选择器status.phase!Succeeded,status.phase!Failed过滤掉终态 Pod启动SingleClusterInformerManager并等待同步——负责监听该成员集群内受支持的 GVR当前为apps/v1 deployments监听 TCP 端口默认10352并注册 gRPC 服务使用grpcconnection.ServerConfig配置 TLSgrpc-auth-cert-file/grpc-auth-key-file/grpc-client-ca-file构建估算框架estimate framework通过 pkg/estimator/server/framework/plugins/registry.go 注册内置插件NodeResourceEstimator与ResourceQuotaEstimator。服务端还内置了 Prometheus 指标pkg/estimator/server/metrics/metrics.go对三类 RPC 统计请求数与估算算法各步骤延迟。5.2 估算主流程EstimateReplicaspkg/estimator/server/estimate.go的流程如下基于本地缓存生成一个snapshotschedcache.NewEmptySnapshot()UpdateSnapshot用于并发读取而不影响缓存本身若 snapshot 中节点数为 0直接返回 0构造ReplicaEstimationContext包含 snapshot 与每副本需求在SchedulingOvercommitProtection特性开启时附加AssumedWorkloads交由估算框架执行估算插件返回maxAvailableReplicas。5.3 核心估算算法NodeResourceEstimator 插件KEP 描述的五步估算流程在 pkg/estimator/server/framework/plugins/noderesource/noderesource.go 中得到了完整实现解析请求约束从ReplicaRequirements.NodeClaim中解析出RequiredNodeAffinity、Tolerations与ResourceRequest收集节点可用资源getNodesAvailableResources克隆每个 NodeInfo并用node.Allocatable - node.Requested计算剩余资源同时把 Pod 数量作为一类资源处理AllowedPodNumber扣减当前节点上的 Pod 数getNodeAvailableResource即 KEP 中r2节点允许的最大剩余 Pod 数的来源节点过滤processNode中调用estimator.MatchNode(node, affinity, tolerations)——即按 label selector 列节点 → 按 node affinity 过滤 → 按 taints/tolerations 过滤可调度性亲和过滤见 pkg/estimator/server/nodes/filter.goGetRequiredNodeAffinity将 NodeClaim 组装成一个临时 PodSpec 再交给 Kubernetes 的nodeaffinity.GetRequiredNodeAffinity解析IsNodeAffinityMatched执行匹配污点容忍过滤见同文件IsTolerationMatched先检查节点Unschedulable标记再通过FindMatchingUntoleratedTaint找出无法容忍的 NoSchedule/NoExecute 污点逐节点估算对每个通过过滤的节点用node.Allocatable.MaxDivided(resourceRequest)计算该节点可切分的副本数KEP 中的r1并并行累加parallelizer.Until返回汇总最终可用副本数即节点级可容纳副本数与节点剩余 Pod 配额约束下的求和结果KEP 中记为min(r1, r2)的逐节点取值再求和。此外插件还在估算前通过SchedulingSimulator.SimulateScheduling将 AssumedWorkloads在途工作负载预先扣账避免连续调度轮次中重复承诺资源EstimateComponents则用同一模拟器以math.MaxInt32为上限求解可容纳的完整组件集合数。5.4 服务端 RPC 实现要点MaxAvailableReplicas的 gRPC 实现pkg/estimator/server/server.go会从 gRPC metadata 中取出对象标识用于日志与追踪校验请求中的Cluster字段必须等于本实例服务的集群名cluster name does not match确保一个 Estimator 只服务一个集群记录请求数、算法延迟等指标后调用EstimateReplicas并返回MaxAvailableReplicasResponse。GetUnschedulableReplicas则从单集群缓存中取回工作负载对象当前支持Deployment见 pkg/estimator/server/replica/replica.go通过 ReplicaSet 找到其下属 Pod统计PodScheduledFalse且 reason 为Unschedulable、且持续超过阈值的 Pod 数量——这正是 KEP Non-Goals 之外、仓库后续扩展出的能力。六、如何启用与部署6.1 调度器侧启用开关Karmada Scheduler 通过命令行参数控制是否启用精确估算cmd/scheduler/app/options/options.go参数默认值说明--enable-scheduler-estimatorfalse是否启用调用集群 scheduler estimator 来修正副本数需显式开启--disable-scheduler-estimator-in-pull-modefalse对 pull 模式集群禁用 estimator仅在--enable-scheduler-estimatortrue时生效--scheduler-estimator-timeout3s调用 estimator 服务的超时时间--scheduler-estimator-service-namespacekarmada-system发现 estimator Service 的命名空间--scheduler-estimator-service-prefixkarmada-scheduler-estimatorestimator Service 名称前缀--scheduler-estimator-port10352连接精确估算器的安全端口--scheduler-estimator-cert-file/--scheduler-estimator-key-file/--scheduler-estimator-ca-file空gRPC 通信的 TLS 证书、私钥与 CA 文件调度器侧通过 Service 名称发现命名空间 前缀 集群名找到每个集群对应的 estimator Service因此启用前必须先完成 estimator 的部署。6.2 Estimator 自身参数karmada-scheduler-estimator的命令行参数定义在 cmd/scheduler-estimator/app/options/options.go参数默认值说明--kubeconfig空成员集群 kubeconfig 路径Estimator 访问其服务的集群--cluster-name空本实例服务的成员集群名称必须与 Karmada 中注册的 Cluster 名一致--server-port10352gRPC 服务监听端口--grpc-auth-cert-file/--grpc-auth-key-file空gRPC TLS 证书与私钥--grpc-client-ca-file空校验 gRPC 客户端证书的 CA--insecure-skip-grpc-client-verifyfalse跳过客户端证书链与主机名校验未配置相关证书时不生效--parallelism16估算算法的并行度必须大于 0--metrics-bind-address:8080Prometheus 指标监听地址设为0可关闭--health-probe-bind-address:10351健康探针监听地址--kube-api-qps/--kube-api-burst20/30与成员集群 apiserver 通信的限流参数6.3 部署方式当前仓库提供了两种部署途径方式一Helm Chart生产推荐charts/karmada/templates/karmada-scheduler-estimator.yaml 为每个values.schedulerEstimator.memberClusters中的集群渲染一组资源Deployment名为karmada-scheduler-estimator-clusterName携带--kubeconfig/etc/clusterName-kubeconfig、--cluster-nameclusterName及 gRPC 证书参数配置存活探针/healthz端口 10351与就绪探针并注入POD_IP环境变量供指标与健康检查绑定Servicekarmada-scheduler-estimator-clusterName将端口10352暴露给调度器调度器据此 Service 名发现SecretclusterName-kubeconfig存放成员集群的 CA、客户端证书与 apiserver 地址可选PodDisruptionBudget支持replicaCount、strategy、tolerations、resources、priorityClassName等常规配置。方式二一键脚本本地/测试hack/deploy-scheduler-estimator.sh 提供命令行部署用法为hack/deploy-scheduler-estimator.sh HOST_CLUSTER_KUBECONFIG HOST_CLUSTER_NAME MEMBER_CLUSTER_KUBECONFIG MEMBER_CLUSTER_NAME例如hack/deploy-scheduler-estimator.sh ~/.kube/karmada.config karmada-host ~/.kube/members.config member1脚本会校验传入的 kubeconfig 与 context 是否存在并将该成员集群的 estimator 部署到 Karmada 控制面所在集群。6.4 配置示例声明 NodeClaim 的工作负载启用精确估算后用户即可通过工作负载的 PropagationPolicy/ResourceBinding 传递节点约束。参考仓库中 samples/nginx/deployment.yaml 与 samples/nginx/propagationpolicy.yaml 的编排方式可在ReplicaRequirements中声明每副本的资源与节点约束示意如下replicaRequirements: resourceRequest: cpu: 1 memory: 1Gi nodeClaim: nodeSelector: disktype: ssd hardNodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: [zone-a] tolerations: - key: dedicated operator: Equal value: gpu effect: NoSchedule估算器将据此过滤节点label selector → 硬亲和 → 污点容忍只在这些可容纳的节点上计算可用副本从而避免把副本投放到总量够但节点不满足约束的集群。七、测试与验证KEP 的 Test Plan 提出两层测试仓库均已落地单元测试客户端侧pkg/estimator/client/accurate_test.go 与 pkg/estimator/client/general_test.go 覆盖 gRPC 请求构造、并发估算与结果合并服务端侧pkg/estimator/server/framework/plugins/noderesource/noderesource_test.go 与 pkg/estimator/server/server_test.go 覆盖节点过滤与节点空闲资源计算调度器集成侧pkg/scheduler/core/estimation_test.go 通过 mock estimator 验证calAvailableReplicas的调用与合并逻辑pkg/scheduler/event_handler_test.go 覆盖enableSchedulerEstimator开关下的缓存与事件处理行为。E2E 测试部署karmada-scheduler-estimator为工作负载指定不同的 NodeClaim验证调度结果见 test/e2e 目录。八、总结Karmada Cluster Accurate Scheduler Estimator 是 Karmada 多集群调度从集群级聚合估算走向节点级精确估算的关键组件。它通过 gRPC 将副本估算从调度器中解耦为独立服务利用 informer 缓存 快照 插件化框架实现按真实节点资源、按 NodeClaim 约束的精确估算同时保留基于ResourceSummary的通用估算器作为兜底并在调度器侧通过多估算器取最小值 特殊值回退的策略保证健壮性。从 KEP-521 提案到 pkg/estimator 下的完整实现再到 Helm Chart 与部署脚本这一能力已形成设计—实现—部署—测试的完整闭环为异构多集群环境下的副本投放提供了可靠的决策依据。【免费下载链接】karmadaOpen, Multi-Cloud, Multi-Cluster Kubernetes Orchestration项目地址: https://gitcode.com/GitHub_Trending/ka/karmada创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表