Kubernetes的调度器(kube-scheduler)是整个系统中至关重要的组件,它负责将待调度的Pods分配到合适的节点上。本文将深入分析kube-scheduler的源码,揭示其内部工作机制。
kube-scheduler的核心功能包括:
监听Pod变化:通过Kubernetes API监听所有未调度的Pods。
过滤(Filtering):根据一系列规则(Predicates)过滤出可调度的节点。
打分(Scoring):对过滤后的节点进行打分,以确定最佳调度位置。
绑定(Binding):将Pod绑定到选定的节点。
调度决策的持久化:将调度决策持久化到Kubernetes API。
SchedulingQueue
是用于存储待调度Pods的数据结构,通常实现为优先级队列。
type SchedulingQueue interface {
AddUnschedulablePod(pod *v1.Pod)
ScheduleOne() (*v1.Pod, error)
Len() int
}
Framework
是一组插件的集合,包括过滤插件、打分插件等。
// Framework defines the interfaces that must be implemented by the components interested in participating in the scheduling process.
type Framework interface {
// Handle adds/updates the nodeInfo of a node.
HandlePods(pods []*v1.Pod) error
// Has the same effect as Handle, but won't update any Pod's nodeName.
HandlePodsWithoutBind(pods []*v1.Pod) error
// Unhandle removes the nodeInfo of a node.
UnhandlePods(pods []*v1.Pod) error
// List lists all nodes known to the framework.
List() ([]*v1.Node, error)
// Run the framework's filtering, scoring, and binding plugins, if any.
Run(stopCh <-chan struct{})
// Score returns the score a node gets for a pod according to the framework's score plugins.
Score(ctx context.Context, cycle *Cycle, pod *v1.Pod, nodes []*v1.Node) (framework.NodeScoreList, *framework.Status)
// Filter filters the given nodes according to the framework's filter plugins.
Filter(ctx context.Context, cycle *Cycle, pod *v1.Pod, nodes []*v1.Node) (framework.NodeToStatusMap, *framework.Status)
// PreprocessRegister registers the predicate and priority function and returns the preprocessor.
PreprocessRegister() framework.PreprocessRegister
// Bind binds a pod to a node.
Bind(binding *framework.Binding) *framework.Status
}
SchedulerCache
缓存了节点和Pod的状态,用于加速调度决策。
kube-scheduler
监听API Server,获取所有未绑定的Pods。func (s *Scheduler) scheduleOne() {
// 从队列中获取一个待调度的Pod
pod, err := s.schedulingQueue.Pop()
if err != nil {
utilruntime.HandleError(err)
return
}
// 调度Pod
err = s.schedulePod(pod)
if err != nil {
utilruntime.HandleError(err)
s.schedulingQueue.AddUnschedulablePod(pod)
}
}
过滤节点
func (f *frameworkImpl) Filter(ctx context.Context, cycleState *CycleState, pod *v1.Pod, nodes []*v1.Node) (framework.NodeToStatusMap, *framework.Status) {
// 调用所有过滤插件
for _, pl := range f.filterPlugins {
statusMap := pl.Filter(ctx, cycleState, pod, nodes)
if statusMap.AsError() != nil {
return statusMap, framework.NewStatus(framework.Error, statusMap.AsError().Error())
}
}
return nil, framework.NewStatus(framework.Success, "")
}
kube-scheduler
还支持抢占机制,允许高优先级的Pods抢占低优先级Pods所占用的节点。
kube-scheduler的抢占机制通常涉及以下步骤:
调度器首先会检查Pod的优先级类,这通常在调度策略中定义。
podPriority := pod.Spec.Priority
if podPriority == nil {
podPriority = int32(0) // 默认优先级
}
调度器通过过滤和打分选择节点。
feasibleNodes, _, err := f.Filter(ctx, cycleState, pod, allNodes)
if err != nil {
return nil, err
}
调度器检查节点上是否有资源冲突或反亲和性冲突。
for _, node := range feasibleNodes {
if !s.isPodAffinitySatisfied(pod, node, cycleState) {
continue
}
if !s.isPodResourcesSatisfied(pod, node, cycleState) {
continue
}
// 节点满足条件,考虑抢占
}
如果节点上没有足够的资源,调度器会考虑抢占。
if shouldPreempt, victims := s.shouldPreempt(pod, nodeInfo, cycleState); shouldPreempt {
// 执行抢占逻辑
}
调度器发出抢占指令,删除低优先级的Pods。
for _, victim := range victims {
// 发送抢占事件
s.recorder.Event(victim, v1.EventTypeNormal, "Preempting", "Preempting pod to fit a higher priority pod")
if err := s.preemptPod(victim, nodeInfo, cycleState); err != nil {
// 处理抢占错误
}
}