解释
Scheduler-Framework的介绍现在也比较多了,这篇文章假设您已经了解Scheduler-Framework的框架和每个扩展点的作用。
如果想全面了解,可以参阅:
《浅谈 Kubernetes Scheduling-Framework 插件的实现》
《自定义 Kubernetes 调度器》
《kube-scheduler》
接下来,我们就重点说说Permit
Permit
Permit用户阻止或者延迟与Node绑定,属于Binding Cycle阶段,就是说,此时Permit已经经过了预选、优选和打分,确定了将要binding到那个node上。Permit主要有三个作用:
- allow(批准):当所有的 permit 扩展都 allow 了 Pod 与节点的绑定,调度器将继续执行绑定过程
- deny(拒绝):如果任何一个 permit 扩展 deny 了 Pod 与节点的绑定,Pod 将被放回到待调度队列,此时将触发 Unreserve 扩展
- wait(等待):如果一个 permit 扩展返回了 wait,则 Pod 将保持在 permit 阶段,直到被其他扩展 allow,如果超时事件发生,wait 状态变成 deny,Pod 将被放回到待调度队列,此时将触发 Unreserve 扩展
理解完Permit作用之后,解释一下:
- 如果allow之后,pod将会被移除waitingPod的队列,进入pre-bind、bind、post-bind扩展。
- 如果返回wait,并且带有超时设定时间,则会进入waitingPod队列,进行等待。如果在超时时间满足后,仍然没有被批准,就会触发unreserve,并且会重新调度。
使用
写个简单的例子:
func (s *Sample) Permit(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (*framework.Status, time.Duration) {
s.Handle.IterateOverWaitingPods(func(waitingPod framework.WaitingPod) {
if _, ok := waitingPod.GetPod().Annotations["test-label"]; ok {
waitingPod.Allow(po.Name())
}
})
if _, ok := pod.Annotations["test-label"]; !ok {
return framework.NewStatus(framework.Wait, "wait label add"), 20 * time.Minute
}
return nil, 0
}
当执行到permit时,会检查pod是否有test-label的注解,如果没有。则等待20分钟。在IterateOverWaitingPods会遍历waitingPod
检测到存在test-label的注解则允许其创建。
注意事项
- 上面代码有一个使用误区:
return framework.NewStatus(framework.Wait, "wait label add"), 20 * time.Minute
看下官方的解释
源码:k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/framework.go +759
if status.Code() == Wait {
// Not allowed to be greater than maxTimeout.
if timeout > maxTimeout {
timeout = maxTimeout
}
pluginsWaitTime[pl.Name()] = timeout
statusCode = Wait
} else {
msg := fmt.Sprintf("error while running %q permit plugin for pod %q: %v", pl.Name(), pod.Name, status.Message())
klog.Error(msg)
return NewStatus(Error, msg)
}
看看 maxTimeout 是什么?
// Specifies the maximum timeout a permit plugin can return.
maxTimeout time.Duration = 15 * time.Minute
也就是说,permit 超时的最长时间是15分钟。
- permit的执行是单例执行的,也就是在wait期间其他的扩展不会被执行,社区也在提这个问题,现在的建议是使用goroutine。
- 不要在permit尝试修改pod的信息,否则会引发,scheduler cache AssumePod failed 错误。
- waitingPod的最好在permit阶段批准