Karmada 多集群调度污点容忍度(Taint Toleration)E2E 测试覆盖分析
2026/9/18 7:01:35 网站建设 项目流程

Karmada 多集群调度污点容忍度(Taint & Toleration)E2E 测试覆盖分析

【免费下载链接】karmadaOpen, Multi-Cloud, Multi-Cluster Kubernetes Orchestration项目地址: https://gitcode.com/GitHub_Trending/ka/karmada

导读

本文基于 Karmada 仓库中 test/e2e/suites/base/coverage_docs/tainttoleration_test.md 这份 E2E 测试覆盖分析文档,深入解读"基于污点与容忍度的调度(Schedule Based on Taints and Tolerations)"这一多集群调度特性。文章将串联该文档对应的端到端测试用例源码、调度器底层 TaintToleration 插件实现以及 API 定义,帮助读者理解:如何在成员集群上设置污点(Taint)、如何在 PropagationPolicy 的 Placement 中声明容忍度(Toleration)、调度器如何据此过滤候选集群,以及该特性在仓库中的测试验证闭环。读完本文,你将能够复现该 E2E 用例、读懂覆盖文档的追踪逻辑,并掌握在实际多集群场景下使用污点容忍度做调度管控的完整方法。

覆盖文档解读:一条测试用例如何对应一项调度能力

tainttoleration_test.md是 Karmada 测试套件中用于追踪 E2E 用例与用户功能文档对应关系的覆盖分析文档。其正文只有一张表格,却精确描述了一项核心调度能力的测试状态:

Test CaseE2E Describe TextComments
Test Deployment propagate with taint and tolerationdeployment with cluster tolerations testingSchedule Based on Taint Toleration

三个字段分别对应:

  • Test Case:面向用户的测试场景名称,即"携带污点与容忍度配置的 Deployment 传播";
  • E2E Describe Text:Ginkgo 测试框架中实际注册的It用例文本,用于在测试日志中快速定位;
  • Comments:该用例所验证的功能在官方用户指南中的主题——"基于污点与容忍度的调度",即调度器在选集群时会参考成员集群的污点与调度策略中声明的容忍度。

这类覆盖文档的作用是防止测试与文档脱节:开发者通过它核对"文档宣称的能力是否有对应测试守护"。它本身不是完整教程,而是追踪表;要完整理解该特性,需要结合仓库中对应的测试源码、调度插件与 API 定义,这正是本文接下来要展开的内容。

对应的 E2E 测试:tainttoleration_test.go全流程拆解

覆盖文档中的 "deployment with cluster tolerations testing" 用例实现在 test/e2e/suites/base/tainttoleration_test.go 中。测试以 Ginkgo 框架编写,外层使用framework.SerialDescribe("propagation with taint and toleration testing", ...)声明为串行执行——因为该用例会向所有成员集群添加污点,影响其他并发用例的调度结果,必须独占执行环境。

前置:为每个成员集群构造唯一的污点

BeforeEach中,测试会为所有成员集群打上NoSchedule污点,污点 key 固定为cluster-toleration.karmada.io,value 为各集群自身的名字:

taints := constructAddedTaints(tolerationKey, clusterName) // constructAddedTaints 生成: // corev1.Taint{Key: tolerationKey, Value: clusterName, Effect: corev1.TaintEffectNoSchedule} clusterObj.Spec.Taints = append(clusterObj.Spec.Taints, taints...) err = controlPlaneClient.Update(context.TODO(), clusterObj)

即每个集群最终携带形如cluster-toleration.karmada.io=member1:NoSchedule的污点。写入操作通过gomega.Eventually轮询完成,保证控制面更新成功后再继续。

核心:在 PropagationPolicy 中声明 ClusterTolerations

测试同时构造了一个指向所有成员集群的 PropagationPolicy,并在Placement.ClusterTolerations中声明一条只容忍第一个成员集群的容忍度:

tolerationKey = "cluster-toleration.karmada.io" tolerationValue = framework.ClusterNames()[0] clusterTolerations = []corev1.Toleration{ { Key: tolerationKey, Operator: corev1.TolerationOpEqual, Value: tolerationValue, Effect: corev1.TaintEffectNoSchedule, }, } policy = helper.NewPropagationPolicy(policyNamespace, policyName, []policyv1alpha1.ResourceSelector{...}, policyv1alpha1.Placement{ ClusterAffinity: &policyv1alpha1.ClusterAffinity{ ClusterNames: framework.ClusterNames(), }, ClusterTolerations: clusterTolerations, })

这里的容忍度语义与 Kubernetes Pod 的 Toleration 完全一致:Operator=EqualKey/Value精确匹配、Effect=NoSchedule,表示"容忍 key 为cluster-toleration.karmada.io、value 为首个集群名、效果为 NoSchedule 的污点"。

断言:Deployment 只会被调度到被容忍的集群

调度器同步集群污点变更后(测试预留了 1 秒等待窗口),用例通过framework.ExtractTargetClustersFromRB从 ResourceBinding 中提取实际调度目标集群,并断言:

gomega.Eventually(func(g gomega.Gomega) { targetClusterNames := framework.ExtractTargetClustersFromRB( controlPlaneClient, deployment.Kind, deployment.Namespace, deployment.Name) g.Expect(len(targetClusterNames)).Should(gomega.Equal(1)) g.Expect(targetClusterNames[0]).Should(gomega.Equal(tolerationValue)) }, pollTimeout, pollInterval).Should(gomega.Succeed())

验证结论:尽管 ClusterAffinity 将全部成员集群都列为候选,但只有被容忍的那个集群进入最终调度结果,其余携带不可容忍污点的集群全部被过滤。这正对应覆盖文档中 "Test Deployment propagate with taint and toleration" 的语义。

清理:恢复集群原始状态

AfterEach中通过removeTargetFromSource将测试添加的污点从集群Spec.Taints中剔除,避免污染后续用例:

clusterObj.Spec.Taints = removeTargetFromSource(clusterObj.Spec.Taints, constructAddedTaints(tolerationKey, clusterName))

其中removeTargetFromSource使用corev1.Taint.MatchTaint做匹配,逐个移除与目标污点等价的条目。

底层原理:TaintToleration 调度插件如何过滤集群

E2E 用例验证的调度行为,在源码层面由调度器的TaintToleration插件实现,位于 pkg/scheduler/framework/plugins/tainttoleration/taint_toleration.go。该插件实现了framework.FilterPlugin接口,是调度框架的过滤环节之一,并注册在插件注册表中(见 pkg/scheduler/framework/plugins/registry.go 中的tainttoleration.Name: tainttoleration.New)。

其核心过滤逻辑Filter分三步:

  1. 已调度集群豁免:如果集群已经出现在 ResourceBinding 的调度结果bindingSpec.TargetContains(cluster.Name)中,直接返回 Success。源码注释说明原因:此时若工作负载无法容忍该污点,将由 taint-manager 在宽限期后驱逐,而非由调度器干预。
  2. 只关注两类 effectfilterPredicate仅匹配TaintEffectNoScheduleTaintEffectNoExecute两种效果的污点(PreferNoSchedule不参与硬性过滤)。
  3. 匹配不可容忍污点:调用v1helper.FindMatchingUntoleratedTaint,用bindingSpec.Placement.ClusterTolerations逐一匹配集群的污点。存在不可容忍污点则返回framework.Unschedulable,附带原因字符串"cluster(s) had untolerated taint {%s}";否则放行。

需要特别留意的是,源码中还注释了一个版本相关的实现细节:Kubernetes v1.35 为容忍度引入了LtGt比较运算符,但 Karmada 当前通过enableComparisonOperators=false显式关闭该能力,以维持向后兼容行为。也就是说,当前版本的 Karmada 集群级容忍度只支持 Kubernetes 原有的运算符语义Equal/Exists)。

该插件的单元测试位于 pkg/scheduler/framework/plugins/tainttoleration/taint_toleration_test.go,覆盖四种典型场景,可作为理解插件行为的快速参考:

测试场景输入要点期望结果
cluster already in target clusters集群已在调度结果中Success(豁免)
no taints集群无污点Success
tolerated taint容忍度与污点 Key/Value/Effect 完全匹配Success
untolerated taint集群有污点但无对应容忍度Unschedulable,原因包含cluster(s) had untolerated taint {key1=value1:NoSchedule}

API 定义:污点写在哪里,容忍度声明在哪里

该特性涉及两处 API 字段,均可从仓库源码确认:

1. 集群污点:Cluster.Spec.Taints

成员集群的污点定义在 Cluster API 中,见 pkg/apis/cluster/v1alpha1/types.go:

// Taints are attached to the member cluster. // Taints on the cluster have the "effect" on // any resource that does not tolerate the Taint. // +optional Taints []corev1.Taint `json:"taints,omitempty"`

字段直接复用 Kubernetes 标准corev1.Taint类型,可通过kubectl edit cluster <name>或直接 patch 该字段的方式为成员集群打污点。E2E 测试正是通过控制面客户端修改此字段来模拟真实污点。

2. 策略容忍度:Placement.ClusterTolerations

调度策略侧在PropagationPolicy/ClusterPropagationPolicy共用的Placement结构中声明容忍度,见 pkg/apis/policy/v1alpha1/propagation_types.go:

// ClusterTolerations represents the tolerations. // +optional ClusterTolerations []corev1.Toleration `json:"clusterTolerations,omitempty"`

一个可复制的完整 PropagationPolicy 示例(等价于 E2E 用例的声明式写法):

apiVersion: policy.karmada.io/v1alpha1 kind: PropagationPolicy metadata: name: nginx-taint-toleration spec: resourceSelectors: - apiVersion: apps/v1 kind: Deployment name: nginx placement: clusterAffinity: clusterNames: - member1 - member2 clusterTolerations: - key: cluster-toleration.karmada.io operator: Equal value: member1 effect: NoSchedule

调度时,Placement.ClusterTolerations会被携带进 ResourceBinding 的Placement字段,供 TaintToleration 插件在过滤阶段读取使用。

关联能力:ClusterTaintPolicy 自动打污点

污点不仅支持手工维护,Karmada 还提供ClusterTaintPolicy根据集群条件自动增删污点。虽然覆盖文档tainttoleration_test.md本身未提及,但其姊妹用例 test/e2e/suites/base/clustertaintpolicy_test.go 与之形成完整闭环:当集群的NetworkReadyStorageReady等条件变为False/Unknown时自动添加NoSchedule/NoExecute污点,条件恢复True后自动移除,并产生TaintClusterSucceed事件。

两者配合的典型运维场景是:先由 ClusterTaintPolicy 根据集群健康状态自动打污点,再由调度策略中的 ClusterTolerations 决定哪些工作负载可以"容忍"异常集群,从而在多集群环境中实现精细化、声明式的调度准入控制。

如何在本地运行该 E2E 测试

该用例属于基础套件(base suites),随 Karmada E2E 测试框架整体运行。仓库提供了完整的本地拉起环境脚本:

  1. 通过 hack/local-up-karmada.sh 搭建包含控制面与若干成员集群的测试环境;
  2. 运行基础套件 E2E(含本用例),或以 Ginkgo focus 方式只运行污点容忍度用例:
# 运行全部 base 套件(其中包含本用例,串行执行) go test ./test/e2e/suites/base/... # 只运行污点容忍度相关用例 go test ./test/e2e/suites/base/... -ginkgo.focus="propagation with taint and toleration"

测试日志中可通过deployment with cluster tolerations testing定位本用例(与覆盖文档的 E2E Describe Text 字段一致),并通过日志中的update taints(...) of cluster(...)观察污点的添加与清理过程。

小结

tainttoleration_test.md虽然只有一行表格,却是一条连接"用户文档、E2E 用例、调度实现"三者的索引。通过本文的展开可以看到完整链路:E2E 用例 tainttoleration_test.go 验证"声明容忍度后,Deployment 只调度到被容忍的集群";调度器侧 TaintToleration 插件 taint_toleration.go 是过滤逻辑的真正执行者;而 propagation_types.go 与 types.go 分别定义了容忍度与污点的 API 承载。三者对照阅读,即可完整掌握 Karmada 基于污点与容忍度的多集群调度机制。

【免费下载链接】karmadaOpen, Multi-Cloud, Multi-Cluster Kubernetes Orchestration项目地址: https://gitcode.com/GitHub_Trending/ka/karmada

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询