kube-scheduler源码分析(三)之 调度流程
scheduleOne
以下代码分析基于
kubernetes v1.12.0
版本。
本文主要分析/pkg/scheduler/
中调度的基本流程。具体的预选调度逻辑
、优选调度逻辑
、节点抢占逻辑
待后续再独立分析。
scheduler的pkg
代码目录结构如下:
1. Scheduler.Run
此部分代码位于pkg/scheduler/scheduler.go
此处为具体调度逻辑的入口。
2. Scheduler.scheduleOne
此部分代码位于pkg/scheduler/scheduler.go
scheduleOne
主要为单个pod选择一个适合的节点,为调度逻辑的核心函数。
对单个pod进行调度的基本流程如下:
- 通过podQueue的待调度队列中弹出需要调度的pod。
- 通过具体的调度算法为该pod选出合适的节点,其中调度算法就包括预选和优选两步策略。
- 如果上述调度失败,则会尝试抢占机制,将优先级低的pod剔除,让优先级高的pod调度成功。
- 将该pod和选定的节点进行假性绑定,存入scheduler cache中,方便具体绑定操作可以异步进行。
- 实际执行绑定操作,将node的名字添加到pod的节点相关属性中。
完整代码如下:
以下对重要代码分别进行分析。
3. config.NextPod
通过podQueue
的方式存储待调度的pod队列,NextPod
拿出下一个需要被调度的pod。
NextPod
的具体函数在factory.go的CreateFromKey函数中定义,如下:
3.1. getNextPod
通过一个podQueue来存储需要调度的pod的队列,通过队列Pop的方式弹出需要被调度的pod。
4. Scheduler.schedule
此部分代码位于pkg/scheduler/scheduler.go
此部分为调度逻辑的核心,通过不同的算法为具体的pod选择一个最合适的节点。
schedule
通过调度算法返回一个最优的节点。
4.1. ScheduleAlgorithm
ScheduleAlgorithm
是一个调度算法的接口,主要的实现体是genericScheduler
,后续分析genericScheduler.Schedule
。
ScheduleAlgorithm
接口定义如下:
5. genericScheduler.Schedule
此部分代码位于/pkg/scheduler/core/generic_scheduler.go
genericScheduler.Schedule
实现了基本的调度逻辑,基于给定需要调度的pod和node列表,如果执行成功返回调度的节点的名字,如果执行失败,则返回错误和原因。主要通过预选和优选两步操作完成调度的逻辑。
基本流程如下:
- 对pod做基本性检查,目前主要是对pvc的检查。
- 通过
findNodesThatFit
预选策略选出满足调度条件的node列表。 - 通过
PrioritizeNodes
优选策略给预选的node列表中的node进行打分。 - 在打分的node列表中选择一个分数最高的node作为调度的节点。
完整代码如下:
5.1. podPassesBasicChecks
podPassesBasicChecks主要做一下基本性检查,目前主要是对pvc的检查。
podPassesBasicChecks具体实现如下:
5.2. findNodesThatFit
预选,通过预选函数来判断每个节点是否适合被该Pod调度。
具体的
findNodesThatFit
代码实现细节待后续文章独立分析。
genericScheduler.Schedule
中对findNodesThatFit
的调用过程如下:
5.3. PrioritizeNodes
优选,从满足的节点中选择出最优的节点。
具体操作如下:
- PrioritizeNodes通过并行运行各个优先级函数来对节点进行优先级排序。
- 每个优先级函数会给节点打分,打分范围为0-10分。
- 0 表示优先级最低的节点,10表示优先级最高的节点。
- 每个优先级函数也有各自的权重。
- 优先级函数返回的节点分数乘以权重以获得加权分数。
- 最后组合(添加)所有分数以获得所有节点的总加权分数。
具体
PrioritizeNodes
的实现逻辑待后续文章独立分析。
genericScheduler.Schedule
中对PrioritizeNodes
的调用过程如下:
5.4. selectHost
scheduler
在最后会从priorityList
中选择分数最高的一个节点。
selectHost
获取优先级的节点列表,然后从分数最高的节点以循环方式选择一个节点。
具体代码如下:
5.4.1. findMaxScores
findMaxScores
返回priorityList
中具有最高Score
的节点的索引。
6. Scheduler.preempt
如果pod在预选和优选调度中失败,则执行抢占操作。抢占主要是将低优先级的pod的资源空间腾出给待调度的高优先级的pod。
具体
Scheduler.preempt
的实现逻辑待后续文章独立分析。
7. Scheduler.assume
将该pod和选定的节点进行假性绑定,存入scheduler cache中,方便可以继续执行调度逻辑,而不需要等待绑定操作的发生,具体绑定操作可以异步进行。
如果假性绑定成功则发送请求给apiserver,如果失败则scheduler会立即释放已分配给假性绑定的pod的资源。
assume方法的具体实现:
8. Scheduler.bind
异步的方式给pod绑定到具体的调度节点上。
bind具体实现如下:
9. 总结
本文主要分析了单个pod的调度过程。具体流程如下:
- 通过podQueue的待调度队列中弹出需要调度的pod。
- 通过具体的调度算法为该pod选出合适的节点,其中调度算法就包括预选和优选两步策略。
- 如果上述调度失败,则会尝试抢占机制,将优先级低的pod剔除,让优先级高的pod调度成功。
- 将该pod和选定的节点进行假性绑定,存入scheduler cache中,方便具体绑定操作可以异步进行。
- 实际执行绑定操作,将node的名字添加到pod的节点相关属性中。
其中核心的部分为通过具体的调度算法选出调度节点的过程,即genericScheduler.Schedule
的实现部分。该部分包括预选和优选两个部分。
genericScheduler.Schedule
调度的基本流程如下:
- 对pod做基本性检查,目前主要是对pvc的检查。
- 通过
findNodesThatFit
预选策略选出满足调度条件的node列表。 - 通过
PrioritizeNodes
优选策略给预选的node列表中的node进行打分。 - 在打分的node列表中选择一个分数最高的node作为调度的节点。
参考:
- https://github.com/kubernetes/kubernetes/blob/v1.12.0/pkg/scheduler/scheduler.go
- https://github.com/kubernetes/kubernetes/blob/v1.12.0/pkg/scheduler/core/generic_scheduler.go
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.