Kubernetes SIG Scheduling 贡献指南:从提交首个 PR 到深入 kube-scheduler 源码
2026/9/16 18:48:53 网站建设 项目流程

Kubernetes SIG Scheduling 贡献指南:从提交首个 PR 到深入 kube-scheduler 源码

【免费下载链接】communityKubernetes Community Documentation项目地址: https://gitcode.com/GitHub_Trending/com/community

SIG Scheduling 是 Kubernetes 社区中负责 Pod 放置(Pod placement)决策的核心特别兴趣小组,kube-scheduler 正是该小组的代表性成果。本文以仓库中的 sig-scheduling/CONTRIBUTING.md 为主体,系统梳理贡献者从入门到进阶的完整路径:如何找到第一个可认领的 Issue、如何按社区规范提交与审查 PR、调度器代码的技术与风格红线、四层测试体系,并结合仓库内的 SIG 章程、调度器架构文档 与 插件配置开发指南,带你掌握向 Kubernetes 调度器提交高质量代码的实战方法论。

SIG Scheduling 的使命与职责范围

在动手提交代码之前,先明确这个小组"管什么、不管什么"。根据 SIG Scheduling Charter 的定义:

SIG Scheduling is responsible for the components that make Pod placement decisions.

即:SIG Scheduling 负责所有做出 Pod 放置决策的组件。小组构建 Kubernetes 调度器及调度特性,设计并实现允许用户自定义 Pod 在集群节点上放置方式的功能,包括提升工作负载可靠性、提高集群资源利用率、以及强制放置策略等。

In scope(在范围内)

章程明确了 SIG 的职责边界,主要涉及:

  • 调度相关特性:如 Node Affinity(节点亲和性);
  • kube-scheduler 性能与可扩展性(与 sig-scalability 协作);
  • kube-scheduler 可靠性:问题检测与修复;
  • Pod 调度 API(与 sig-api-machinery 协作);
  • 节点资源管理集群资源管理(与 sig-node 协作);
  • Pod 调度策略(与 sig-auth 协作)。

跨小组的外部流程还包括 kube-scheduler 的 [test grid] 与性能仪表盘(perf dashboard)。

Out of scope(范围之外)

以下领域不属于SIG Scheduling,贡献时不要走错门:

  • 网络管理(属于 sig-network);
  • 持久化存储管理(属于 sig-storage);
  • 资源配额及其他准入策略的强制(属于 sig-api-machinery)。

相关工作组与子项目

从 sig-scheduling/README.md 可以看到,SIG 还赞助了若干工作组(Working Groups),例如 WG Batch、WG Checkpoint Restore、WG Device Management、WG Node Lifecycle、WG Workload-aware Scheduling。同时维护着一批活跃子项目(Subprojects),包括:

  • scheduler:即 Kubernetes 主仓库中的cmd/kube-schedulerpkg/scheduler
  • descheduler:负责已调度 Pod 的再平衡;
  • kueue:面向批处理/排队工作负载的调度系统;
  • kwok:用于大规模模拟节点/Pod 的轻量工具;
  • scheduler-plugins:开箱即用的调度插件集合;
  • 以及 cluster-capacity、kube-scheduler-simulator、scheduler-library、dra-driver-topology 等。

如果对调度生态的其他部分感兴趣,同样可以贡献到这些子项目。

开始贡献前的准备:先读这三样东西

贡献指南强烈建议,任何新贡献者在动手之前先完成以下"预习":

  1. Kubernetes Contributor Guide:本仓库对应的入门文档位于 contributors/guide/README.md,涵盖开发环境搭建、代码规范、贡献全流程;
  2. Contributor Cheat Sheet:快速参考手册,位于 contributors/guide/contributor-cheatsheet/README.md,是 GitHub 协作体验的 "TL;DR" 速查表,包含分支策略、同步 fork、squash 提交等高频操作;
  3. 社区成员角色体系:见 community-membership.md。Kubernetes 的贡献角色由低到高分为 Member、Reviewer、Approver、Subproject owner:
角色职责核心要求
Member社区活跃贡献者2 名 Reviewer 担保 + 多次实质性贡献(至少 1 个已合并 PR)
Reviewer审查他人贡献的质量与正确性至少 3 个月 Member 身份、主审 5 个以上 PR、累计审/合 20 个以上 PR,由子项目 Approver 提名
Approver审查并批准代码贡献至少 3 个月 Reviewer、主审 10 个以上实质 PR、累计审/合 30 个以上 PR,由子项目 owner 提名
Subproject owner制定子项目方向与优先级由 sigs.yaml 中子项目的owners条目定义

这些角色都由OWNERS 文件界定。以 SIG Scheduling 自身的 sig-scheduling/OWNERS 为例,它通过reviewers/approvers引用sig-scheduling-leads团队,并为该目录下的内容打上sig/scheduling标签——这意味着该目录的 PR 审查与批准权落在 SIG 负责人团队身上。

找到你的第一个贡献入口

SIG Scheduling 明确欢迎 PR、Issue、文档、新提案、帮助回答用户问题、参加会议等多种形式的贡献。入门渠道包括:

从 issue 池起步

  • first-good-issue:维护一个"非陈旧"(non-stale)的、面向新人的问题池,带good first issue+sig/scheduling标签,适合完全不知道从哪开始的贡献者;
  • help wanted:带help wanted+sig/scheduling标签的待办问题,适合有一定经验、想接手明确任务的贡献者。

报告 Bug

如果发现 bug,请在 kubernetes/kubernetes 仓库下打开 Issue,并遵循以下规范:

  • 添加标签/sig scheduling/kind bug
  • 遵循Bug Report模板的要求填写(复现步骤、期望行为、实际行为、环境信息等),这能极大帮助维护者定位错误。

提交功能请求(Feature Request)

流程相对完整,核心要点是"先讨论、后实现":

  1. 在 kubernetes/kubernetes 下打开 Issue,加标签/sig scheduling/kind feature聚焦于 user stories(用户故事),而不是直接给实现方案;
  2. 如果方案的合理性存在争议,可以拿到 SIG 例会(见 sig-scheduling/README.md 的 Meetings 部分)上讨论;
  3. 如果存在多个实现选项,建议先写一份包含Pros and Cons的文档,分享到 SIG 的邮件列表收集反馈;
  4. 任何涉及 API 变更或重大重构的特性,必须先提交 Kubernetes Enhancement Proposal(KEP),KEP 走增强提案流程,由 sig-scheduling 维护的 KEP 目录统一管理。

修正过期文档

发现文档过时是很好的切入点,分两种情况处理:

  • 网站类文档(用户文档):到 kubernetes/website 仓库开 Issue 或直接提 PR;
  • 开发者类文档(面向开发者的文档):到 kubernetes/community 仓库(即本仓库)处理,例如直接修正 sig-scheduling 目录下的内容。

贡献子项目

SIG 维护的子项目清单见 sig-scheduling/README.md 的 Subprojects 一节,每个子项目都有独立的 OWNERS,可以直接参与。

PR 提交流程与协作最佳实践

SIG 长期遵循一套保证代码质量与 git 历史整洁的实践,新贡献者应当内化于心:

审查链路:Reviewer → Approver

  • PR 最好先由Reviewer审查:Reviewer 在 PR 上打/lgtm(Looks Good To Me)表示代码质量与正确性通过;
  • 随后由Approver审查并批准:Approver 的关注点是整体接受度,包括前后向兼容、API 与 flag 约定、隐蔽的性能与正确性问题、与其他系统组件的交互等;
  • 尽量保留机器人自动分配的 Reviewer,除非确实需要某个特定贡献者的专长;
  • 关键 bug 修复可以直接分配给 Approver,以加快合入。

Commit 纪律

  • 回应 review 意见时,始终新增一个 commit 而不是 amend,这样 Reviewer 可以清晰看到新改动;Reviewer 可能会在合适时机要求你 squash;
  • PR 准备合并时执行 squash,把过程性提交压缩成语义清晰的提交,对 git 历史是极大的帮助;
  • 代码贡献应当相对小、简单、文档完备、测试充分;功能较大时尽量拆分成增量 PR 分批提交。

沟通与上下文保留

  • 无论是线下讨论还是社区会议上的结论,都要回写到对应的 Issue/PR,以保留决策上下文,方便后来者理解"为什么这么做";
  • 遇到 TODO 或后续跟进事项,立即开一个 Issue 记录,防止遗忘。

技术与风格指南:kube-scheduler 开发红线

以下指南主要适用于 kube-scheduler 本身,部分子项目也遵循同样的标准。

设计阶段的思考

设计新特性时,必须考虑依赖 kube-scheduler 代码的组件:

  • cluster-autoscaler:依赖调度器逻辑做扩缩容预测与模拟;
  • scheduler-plugins:基于调度框架扩展调度能力的插件集合;
  • kubelet:作为最终执行 Pod 落地的节点代理,与调度结果直接交互。

也就是说,任何调度器改动都不能破坏这些下游组件的假设。

编码规范

  • 遵循effective go的 Go 代码风格;
  • 日志方面优先使用contextual logging(基于上下文的结构化日志),部分老包仍在用structured logging,两者都属于 Kubernetes 结构化日志演进路线,详见 contributors/devel/sig-instrumentation/ 下的日志迁移文档;
  • 编写 API 时遵循k8s API conventions(见 contributors/devel/sig-architecture/api-conventions.md),包括版本化、持久化、DeepCopy 等约定;
  • 命名规则:经验法则是——变量名的长度应与它所在作用域的大小成正比,与它的使用次数成反比。局部小作用域可用短名,全局/跨包作用域应当用含义清晰的长名。

测试要求:四层测试体系

kube-scheduler 的测试分层非常明确,贡献者应当按改动的影响范围选择对应层级:

层级覆盖内容说明
Unit tests单函数/单模块逻辑每个改动都应有高覆盖率单元测试
Integration testskube-scheduler 内部组件交互(event handlers、队列、缓存、调度周期)与 kube-apiserver覆盖组件间协作
E2E tests与 kubelet、kube-controller-manager 等其他组件的真实交互端到端验证
Perf tests关键/CPU 密集型操作的性能参见 scheduler_benchmarking.md

测试代码的通用准则

  • 遵循DAMP 原则(Descriptive And Meaningful Phrases,描述性且有意义的短语):测试中的重复是允许的,只要每个片段都有描述意义,不要为了 DRY 把测试抽象得晦涩难懂;
  • 断言使用cmp.Diff代替reflect.DeepEqual,以提供有意义的差异比较输出;
  • 错误比较使用errors.Is(配合cmp.Diff时用cmpopts.EquateErrors),禁止比较错误字符串
  • 充分利用pkg/scheduler/testing下的现有工具函数(构造 Pod、Node、测试环境的辅助方法);
  • 避免创建或使用断言库,使用标准库的t.Errort.Fatal
  • gomegaginkgo只允许在 E2E 测试中使用

注意:部分现存代码是在这些规范确立之前写的,可能存在违规。指南明确欢迎你通过 PR 把旧代码改到符合标准——这也是一个不错的入门贡献方向。

深入源码:kube-scheduler 架构与代码层次

要写出符合 SIG 期望的代码,必须先理解调度器的整体骨架。仓库中的 scheduling_code_hierarchy_overview.md 提供了权威的代码导航地图。

调度循环:Scheduling Cycle + Binding Cycle

默认调度器有一个无限运行的主循环,每拿到一个 Pod 就执行一轮调度:

  • Scheduling Cycle(调度周期,阻塞式):运行调度算法,选出最合适的节点。步骤为:取下一个待调度 Pod → 用算法调度 → 若因FitError失败,则运行PostFilter扩展点中的抢占(preemption)插件提名候选节点 → 若成功找到节点,执行AssumePod写入调度缓存,再依次运行ReservePermit扩展点 → 全部通过后进入绑定周期,同时开始处理下一个 Pod;
  • Binding Cycle(绑定周期,非阻塞式):依次调用WaitOnPermit(等待Permit插件设定的条件,如 gang 调度中等待兄弟 Pod 全部 Assume)、PreBindBindPostBind扩展点。任一环节失败时,会触发所有Reserve插件的Unreserve回滚操作(例如释放为 Pod 组预留的资源)。

整体组件连接关系如下图所示,事件处理器负责把 Pod 正确入队到调度队列,缓存持续更新 Pod/Node 快照,每个 profile 拥有独立的调度框架实例:

kube-scheduler 默认调度器架构:事件处理器、调度队列、缓存与调度/绑定周期协同工作

关键代码位置

调度器代码横跨多个目录,从源码结构看,核心位置包括:

  • cmd/kube-scheduler/app:控制器代码与 CLI 参数定义(符合所有 Kubernetes 控制器的标准搭建方式),负责初始化命令行选项、校验、metrics(/metrics)、健康检查(/healthz)、读取KubeSchedulerConfiguration、构建插件注册表、leader election 等;
  • pkg/scheduler:默认调度器代码根目录,负责装配调度器(初始化缓存、合并 in-tree/out-of-tree 插件注册表、注册事件处理器);
  • pkg/scheduler/core:默认调度算法实现,定义了ScheduleAlgorithm接口与Schedule/Extenders方法;
  • pkg/scheduler/framework:调度框架及其插件;
  • pkg/scheduler/internal:缓存、队列等内部实现;
  • staging/src/k8s.io/kube-scheduler:ComponentConfig API 类型。

调度框架、缓存与快照

  • 调度框架(Scheduling Framework):位于pkg/scheduler/framework,插件初始化时被传入一个framework.FrameworkHandle,提供访问/操作 Pod、Node、clientset、事件记录器等能力;
  • 调度缓存(Scheduler Cache):捕获集群当前状态,维护节点列表与 assumed pods(已假设运行的 Pod)列表,通过AssumePodFinishBindingForgetPod三个操作管理假设 Pod——Assume机制让 Pod 在 kube-apiserver 尚未确认前就先"假跑"在目标节点上,从而提升调度吞吐量;
  • 快照(Snapshot):每次调度周期开始时从缓存生成集群快照,固定集群状态,避免插件在并发处理中看到不一致的数据。

实战范例:为调度插件添加可配置参数

理解了架构之后,最有代表性的"第一个真功能"就是给 in-tree 插件增加配置参数。仓库中的 scheduler_framework_plugins.md 给出了完整六步走流程。假设插件名为FooPlugin,要新增一个可选的整型参数barParam

第一步:定义并注册结构体

pkg/scheduler/apis/config/types_pluginargs.go定义调度器内部表示:

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type FooPluginArgs struct { // metav1 is k8s.io/apimachinery/pkg/apis/meta/v1 (package is in staging/src) metav1.TypeMeta BarParam int32 }

嵌入TypeMeta以支持 API 元数据的版本化与持久化;+k8s:deepcopy-gen:interfaces注释用于自动生成DeepCopy函数。

然后在staging/src/k8s.io/kube-scheduler/config/{version}/types_pluginargs.go定义带版本的外部表示。为了让"未指定参数"与"显式默认值"可区分,字段使用指针类型——字段为 nil 时框架会填入默认值:

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type FooPluginArgs struct { metav1.TypeMeta `json:",inline"` BarParam *int32 `json:"barParam,omitempty"` }

每新增一个types_pluginargs.go类型,都要在对应的register.go中注册,调度器才能在解析KubeSchedulerConfiguration时识别它。

第二步:设置默认值

KubeSchedulerConfigurationcmd/kube-scheduler/app/options/options.go中被解析,随后从版本化类型转换到内部类型并填充默认值。在pkg/scheduler/apis/config/v1beta1/defaults.go定义默认值函数:

// v1beta1 refers to k8s.io/kube-scheduler/config/v1beta1 (package is in staging/src) func SetDefaults_FooPluginArgs(obj *v1beta1.FooPluginArgs) { if obj.BarParam == nil { obj.BarParam = pointer.Int32Ptr(42) } }

第三步:运行时校验

pkg/scheduler/apis/config/validation/validation_pluginargs.go添加校验器,确保用户配置与默认值合法:

// From here on, FooPluginArgs refers to the type defined in pkg/scheduler // definition, not the kube-scheduler definition. We're dealing with // post-default values. func ValidateFooPluginArgs(args config.FooPluginArgs) error { if args.BarParam < 0 && args.BarParam > 100 { return fmt.Errorf("must be in the range [0, 100]") } return nil }

第四步:代码生成

提交所有改动后,运行代码生成命令,自动产出 DeepCopy、类型转换、指针/原始类型互转与默认值设置代码:

$ cd $GOPATH/src/k8s.io/kubernetes $ git add -A && git commit $ make clean $ ./hack/update-codegen.sh $ make generated_files

第五步:补测试

生成代码后立刻补齐单元测试:

  • pkg/scheduler/apis/config/v1beta1/defaults_test.go:单测默认值逻辑;
  • pkg/scheduler/apis/config/validation/validation_pluginargs_test.go:单测校验器;
  • pkg/scheduler/apis/config/scheme/scheme_test.go:用一份完整KubeSchedulerConfiguration定义测试整个解析链路。

第六步:在插件中接收参数

修改插件的New方法签名,从runtime.Object断言出FooPluginArgs并校验:

func New(fpArgs runtime.Object, fh framework.FrameworkHandle) (framework.Plugin, error) { // config.FooPluginArgs refers to the pkg/scheduler struct type definition. args, ok := fpArgs.(*config.FooPluginArgs) if !ok { return nil, fmt.Errorf("got args of type %T, want *FooPluginArgs", fpArgs) } if err := validation.ValidateFooPluginArgs(*args); err != nil { return nil, err } // Use args.BarParam as you like. }

这套模式正是调度框架"插件可配置化"的标准实现路径,也是社区大量插件的开发模板。

理解调度队列:贡献调度逻辑前必须掌握的基础

调度队列机制是调度器吞吐与公平性的核心,scheduler_queues.md 详细描述了其内部结构。队列机制需要处理 Pod 的各种前置条件(持久卷存在、反亲和规则、容忍污点等),因此设计了三层队列:

  • activeQ(活动队列,堆):提供立即可调度的 Pod,默认优先级最高的 Pod 在堆顶,可通过QueueSort扩展点自定义排序;
  • backoffQ(退避队列,堆):指数退避那些"暂时失败但终将可调度"的 Pod(如卷还在创建中)。默认初始退避 1 秒、最大退避 10 秒(均可配置);退避超时随失败次数指数增长,例如 3 次失败约 8 秒、5 次失败约 32 秒,达到上限后不再增长;
  • unschedulableQ(不可调度队列,Map):停放等待特定条件发生的 Pod,直到有"移动请求"(move request)触发。

两个后台 goroutine 周期性把 Pod 挪回活动队列:flushBackoffQCompleted每秒运行一次(退避到期的 Pod 回到活动队列);flushUnschedulableQLeftover每 30 秒运行一次(停留超过 30 秒的不可调度 Pod 获得重试机会,最坏 60 秒内被挪动)。此外,集群事件(Pod/Node/Service/PV/PVC/存储类/CSI 节点变化)会触发移动请求,把 unschedulable 队列中的 Pod 批量搬回 active 或 backoff 队列:

调度队列中 Pod 在 active、backoff、unschedulable 三个队列之间流转示意

队列还对外暴露pending_podsqueue_incoming_pods_total两个指标,用于观测各队列积压量、入队事件来源与调度吞吐。

性能基准测试:调度器的关键防线

调度器是控制平面中性能敏感的组件。按照 scheduler_benchmarking.md 的约定,任何可能影响调度性能的 PR,都应在提交时运行集成基准测试,并附上前后对比数据

运行全部集成基准:

make test-integration WHAT=./test/integration/scheduler_perf KUBE_TEST_VMODULE="''" KUBE_TEST_ARGS="-run=^$$ -bench=."

只跑指定基准(例如BenchmarkScheduling):

make test-integration WHAT=./test/integration/scheduler_perf KUBE_TEST_VMODULE="''" KUBE_TEST_ARGS="-run=^$$ -bench=BenchmarkScheduling"

基准用例定义在./test/integration/scheduler_perf/scheduler_bench_test.go,函数名以BenchmarkScheduling开头,通过结构体数组描述测试规模:

tests := []struct{ nodes, existingPods, minPods int }{ {nodes: 100, existingPods: 1000, minPods: 100}, {nodes: 1000, existingPods: 1000, minPods: 100}, {nodes: 5000, existingPods: 1000, minPods: 1000}, }

其中nodes是测试集群节点数,existingPods是初始化阶段预调度 Pod 数,minPods是基准计时的实际调度 Pod 数。想测 5000 节点集群调度 10000 个 Pod,就往数组里加{nodes: 5000, existingPods: 1000, minPods: 10000};还可以用-bench=BenchmarkScheduling/5000Nodes/1000Pods精确跑某一规模组合。这些都是向 SIG 证明"我的改动不拖慢调度器"的标准动作。

@mentions 使用指南:找对人、办对事

在 GitHub 上需要对应角色的关注时,使用以下 SIG 团队提及(@mentions):

团队适用场景
@kubernetes/sig-scheduling-api-reviewsAPI 变更与审查
@kubernetes/sig-scheduling-bugsBug 分诊与排障
@kubernetes/sig-scheduling-feature-requests功能请求
@kubernetes/sig-scheduling-miscApprover 与 Reviewer 的一般性讨论
@kubernetes/sig-scheduling-pr-reviewsPR 审查
@kubernetes/sig-scheduling-proposals设计提案
@kubernetes/sig-scheduling-test-failures测试失败与分诊

精准使用这些团队别名,能让你的 Issue/PR 第一时间触达最合适的维护者,避免无效等待。

参与渠道与行动清单

SIG Scheduling 的日常交流渠道包括 Slack 的#sig-scheduling频道、邮件列表以及双周例会(分为亚太/欧洲时区与北美/欧洲时区两组,另有 descheduler 专项例会,具体排期见 sig-scheduling/README.md)。

总结一份可执行的贡献行动清单:

  1. 通读 contributors/guide/README.md 与 contributors/guide/contributor-cheatsheet/README.md;
  2. first-good-issue/help wanted池中认领第一个任务;
  3. 小步提交 PR,遵守"新 commit 回应 review、合并前 squash"的提交纪律;
  4. 按 sig-scheduling/CONTRIBUTING.md 的四层测试要求补齐测试,性能敏感改动附基准前后对比;
  5. 涉及 API 或重大重构时,先走 KEP 提案流程;
  6. 遇到问题在 Slack/邮件列表/例会中提出,并把结论回写到 Issue/PR。

无论你的起点是修一个文档、修一个 bug,还是完整地给插件添加一个新参数,SIG Scheduling 都欢迎——调度器是 Kubernetes 控制平面中最有挑战也最有成就感的领域之一,祝贡献顺利。

【免费下载链接】communityKubernetes Community Documentation项目地址: https://gitcode.com/GitHub_Trending/com/community

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

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

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

立即咨询