使用scheduler-framework扩展原生k8s调度器

scheduler-framework

本文将讲述如何使用scheduler-framework扩展原生调度器

目的: 在prefilter阶段检查pod是否添加有dely注释,如果未达到对应时间则不调度

分析需要实现的method

注册插件

WithPlugin返回一个注册选项,由此我们可以看出,我们的插件需要实现framework.PluginFactory 接口

func WithPlugin(name string, factory framework.PluginFactory) Option {
	return func(registry framework.Registry) error {
		return registry.Register(name, factory)
	}
}

该接口接收传入的附加参数和FrameworkHandle,关于FrameworkHandle的作用请查看之前文章

type PluginFactory = func(configuration *runtime.Unknown, f FrameworkHandle) (Plugin, error)

PreFilterPlugin接口

// PreFilterPlugin is an interface that must be implemented by "prefilter" plugins.
// These plugins are called at the beginning of the scheduling cycle.
type PreFilterPlugin interface {
	Plugin
	// PreFilter is called at the beginning of the scheduling cycle. All PreFilter
	// plugins must return success or the pod will be rejected.
	PreFilter(ctx context.Context, state *CycleState, p *v1.Pod) *Status
	// PreFilterExtensions returns a PreFilterExtensions interface if the plugin implements one,
	// or nil if it does not. A Pre-filter plugin can provide extensions to incrementally
	// modify its pre-processed info. The framework guarantees that the extensions
	// AddPod/RemovePod will only be called after PreFilter, possibly on a cloned
	// CycleState, and may call those functions more than once before calling
	// Filter again on a specific node.
	PreFilterExtensions() PreFilterExtensions
}

// Plugin is the parent type for all the scheduling framework plugins.
type Plugin interface {
	Name() string
}

PreFilterExtensions()方法返回PreFilterExtensions接口

type PreFilterExtensions interface {
	// AddPod is called by the framework while trying to evaluate the impact
	// of adding podToAdd to the node while scheduling podToSchedule.
	AddPod(ctx context.Context, state *CycleState, podToSchedule *v1.Pod, podToAdd *v1.Pod, nodeInfo *schedulernodeinfo.NodeInfo) *Status
	// RemovePod is called by the framework while trying to evaluate the impact
	// of removing podToRemove from the node while scheduling podToSchedule.
	RemovePod(ctx context.Context, state *CycleState, podToSchedule *v1.Pod, podToRemove *v1.Pod, nodeInfo *schedulernodeinfo.NodeInfo) *Status
}

我们需要实现五个method:

  • Name 返回插件名称
  • PreFilter 对pod进行筛选
  • PreFilterExtensions prefilter扩展功能,评估add/removepod的影响,如果不实现可返回nil
  • AddPod 评估添加pod到node的影响
  • RemovePod 评估删除pod到node的影响

代码实现

实现注册相关

const Name = "test"

var _ framework.PreFilterPlugin = &TestPlugin{}

type Args struct {
	KubeConfig string `json:"kubeconfig,omitempty"`
	Master     string `json:"master,omitempty"`
}

type TestPlugin struct {
	handle framework.FrameworkHandle
	Args   *Args
}

func New(rargs *runtime.Unknown, handle framework.FrameworkHandle) (framework.Plugin, error) {
	args := &Args{}
	if err := framework.DecodeInto(rargs, args); err != nil {
		return nil, err
	}
	klog.Info(args)
	return &TestPlugin{
		handle: handle,
		Args:   args,
	}, nil
}

实现prefilter接口

# 返回名称,任何plugin都需要实现
func (self *TestPlugin) Name() string {
	return Name
}

# 实现PreFilter method
func (self *TestPlugin) PreFilter(ctx context.Context, state *framework.CycleState, p *v1.Pod) *framework.Status {
	klog.Error("into controller test")
	state.Write()
	var dtime int64
	var err error
    # 判断是否有延迟字段
	if v, ok := p.Annotations["delay"]; ok {
		if dtime, err = strconv.ParseInt(v, 10, 64); err != nil {
			return nil
		}
        # 距离当前大于延时间,则调度
		if time.Now().Unix()-p.CreationTimestamp.Unix() >= dtime {
			klog.Infof("scheduler: %s/%s", p.Namespace, p.Name)
			return nil
		}
        # 否则不调度
		klog.Infof("not reatch scheduler time: %s/%s", p.Namespace, p.Name)
		return framework.NewStatus(framework.Skip, "not reatch scheduler time")
	}
	return nil
}

# PreFilterExtensions AddPod method,返回nil即success
func (self *TestPlugin) AddPod(ctx context.Context, state *framework.CycleState, podToSchedule *v1.Pod, podToAdd *v1.Pod, nodeInfo *schedulernodeinfo.NodeInfo) *framework.Status {
	return nil
}

# PreFilterExtensions RemovePod,返回nil即success
func (self *TestPlugin) RemovePod(ctx context.Context, state *framework.CycleState, podToSchedule *v1.Pod, podToRemove *v1.Pod, nodeInfo *schedulernodeinfo.NodeInfo) *framework.Status {
	return nil
}

# 这里也可以返回nil
func (self *TestPlugin) PreFilterExtensions() framework.PreFilterExtensions {
	return self
}

测试

  • 测试时使用kubeadm,停止原有kubelet
# 将static pod配置移走,kubelet会自动停止
mv /etc/kubernetes/manifests/kube-scheduler.yaml ./
  • 编译运行
go build 
./test-scheduler-framework --config=config.yaml
  • 测试pod

创建deploy 配置如下

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: busybox
  name: busybox
  namespace: default
spec:
  replicas: 0
  selector:
    matchLabels:
      run: busybox
  template:
    metadata:
      annotations:
        delay: "15"
      labels:
        run: busybox
    spec:
      containers:
      - args:
        - sleep
        - "123456"
        image: busybox
        name: busybox
  • 扩容观察pod状态
$ kubectl scale deploy busybox --replicas=1
$ kubectl get pods -l run=busybox -w
NAME                      READY   STATUS    RESTARTS   AGE
busybox-8d8554fc8-f9899   0/1     Pending   0          3s
busybox-8d8554fc8-f9899   0/1     Pending   0          85s
busybox-8d8554fc8-f9899   0/1     ContainerCreating   0          85s
busybox-8d8554fc8-f9899   0/1     ContainerCreating   0          86s
busybox-8d8554fc8-f9899   1/1     Running             0          90s
  • 观察调度器日志
E1226 18:19:11.071899   92593 type.go:59] into controller test
I1226 18:19:11.071909   92593 type.go:70] not reatch scheduler time: default/busybox-8d8554fc8-f9899
E1226 18:19:11.071923   92593 framework.go:287] error while running "test" prefilter plugin for pod "busybox-8d8554fc8-f9899": not reatch scheduler time
E1226 18:19:11.071941   92593 factory.go:469] Error scheduling default/busybox-8d8554fc8-f9899: error while running "test" prefilter plugin for pod "busybox-8d8554fc8-f9899": not reatch scheduler time; retrying
E1226 18:19:11.071970   92593 scheduler.go:638] error selecting node for pod: error while running "test" prefilter plugin for pod "busybox-8d8554fc8-f9899": not reatch scheduler time
E1226 18:20:36.064233   92593 type.go:59] into controller test
I1226 18:20:36.064258   92593 type.go:67] scheduler: default/busybox-8d8554fc8-f9899

可以看到确实延时调度了,但是因为重新调度本身有时间间隔(30s),所以并不是我们设置的值

扫描关注我:

微信

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值