kubernetes-sigs / scheduler-plugins

Repository for out-of-tree scheduler plugins based on scheduler framework.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

schduler-plugin calls the filter interface but does not call (sort,score) types of interfaces

guojianyu opened this issue · comments

Area

  • Scheduler
  • Controller
  • Helm Chart
  • Documents

Other components

No response

What happened?

schduler-plugin calls the filter interface but does not call (sort,score) types of interfaces.
The code is as follows:

package main
import (
	"context"
	"fmt"
	"os"
	"time"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/component-base/cli"
	_ "k8s.io/component-base/logs/json/register" // for JSON log format registration
	_ "k8s.io/component-base/metrics/prometheus/clientgo"
	_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
	"k8s.io/klog/v2"
	"k8s.io/kubernetes/cmd/kube-scheduler/app"
	"k8s.io/kubernetes/pkg/scheduler/framework"
)

func main() {
	myPlugin := app.WithPlugin("nodeAge", New)

	command := app.NewSchedulerCommand(myPlugin)
	code := cli.Run(command)
	os.Exit(code)
}

type NodeAge struct {
	handle framework.Handle
}

func (pl *NodeAge) Name() string {
	return "nodeAge"
}

var _ = framework.ScorePlugin(&NodeAge{})
var _ = framework.QueueSortPlugin(&NodeAge{})
var _ = framework.FilterPlugin(&NodeAge{})
var _ = framework.PreScorePlugin(&NodeAge{})
var _ = framework.PreFilterPlugin(&NodeAge{})

func (c *NodeAge) PreFilter(ctx context.Context, state *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) {
	klog.Infof("PreFilter is called for Pod: %s/%s", pod.Namespace, pod.Name)
	return nil, nil
}

func (c *NodeAge) PreFilterExtensions() framework.PreFilterExtensions {
	return nil
}


func (pl *NodeAge) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
	klog.Infof("filter pod: %v", pod.Name)
	//klog.Infof("filter state: %v", state)
	node := nodeInfo.Node()
	if node == nil {
		return framework.NewStatus(framework.Error, "node not found")
	}

	return framework.NewStatus(framework.Success, "Node: "+node.Name)
}

func getPriority(pod *v1.Pod) int {

	return 0 // TODO: Replace with actual logic
}

func (pl *NodeAge) Less(pod1, pod2 *framework.QueuedPodInfo) bool {
	klog.Infof("Less: %v,%v", pod1, pod2)
	priority1 := getPriority(pod1.Pod)
	priority2 := getPriority(pod2.Pod)
	if emer, ok := pod1.Pod.Labels["emergency"]; ok && emer == "red" {
		return true
	} else {
		return priority1 > priority2
	}
	//return priority1 > priority2 
}

func (p *NodeAge) PreScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status {
	klog.Infof("PreScore plugin executed for Pod %s/%s", pod.Namespace, pod.Name)
	for _, node := range nodes {
		klog.Infof("Node available: %s", node.Name)
	}
	return framework.NewStatus(framework.Success, "")
}

func (pl *NodeAge) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
	nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
	if err != nil {
		return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err))
	}
	tsCreation := nodeInfo.Node().ObjectMeta.CreationTimestamp.Second()
	tsCurrent := time.Now().Second()
	score := 0
	if tsCurrent-tsCreation < 15*3600*24 {
		score += 1
		klog.InfoS("node get score", "pod_name", pod.Name, "current node", nodeInfo.Node().Name, "node age(days)", (tsCurrent-tsCreation)/3600/24)
	} else {
		klog.InfoS("node can't get score", "pod_name", pod.Name, "current node", nodeInfo.Node().Name, "node age(days)", (tsCurrent-tsCreation)/3600/24)
	}
	return int64(score), nil
}

func (pl *NodeAge) ScoreExtensions() framework.ScoreExtensions {
	return pl
}

func (pl *NodeAge) NormalizeScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status {
	return framework.NewStatus(framework.Success, "")
}

func New(_ runtime.Object, h framework.Handle) (framework.Plugin, error) {
	return &NodeAge{handle: h}, nil
}

The Scheduler_config.yaml is as follows:

apiVersion: kubescheduler.config.k8s.io/v1
leaderElection:
  leaderElect: true
clientConnection:
  kubeconfig: "/etc/kubernetes/scheduler.conf"
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: my-scheduler
    plugins:
      preFilter:
        enabled:
        - name: nodeAge
      filter:
        enabled:
        - name: nodeAge
      preScore:
        enabled:
        - name: nodeAge
      score:
        enabled:
        - name: nodeAge
      queueSort:
        enabled:
        - name: nodeAge
        disabled:
        - name: "*"

scheduler-deploy.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      schedulerName: my-scheduler
      containers:
      - image: nginx
        imagePullPolicy: IfNotPresent       
        name: nginx

The scheduler log output is as follows:
image

Is this a problem with my code or something else? If it is a code problem, how can I fix it? Thank you very much!! 🙏

What did you expect to happen?

Sort and Score interface can be called normally.

How can we reproduce it (as minimally and precisely as possible)?

No response

Anything else we need to know?

I upgraded the scheduler-plugin to the latest version with the same problem

Kubernetes version

$ kubectl version
# paste output here

image

Scheduler Plugins version

release-1.26

I would like to confirm the core issue. Your question is, you wrote a custom plugin, and then found that only the filter method was executed, but the score method was not executed, right?
You can first check how many nodes your test cluster has. If there is only a single node, the scheduler will only use this node for scheduling by default and will not execute scoring process.
refer to: https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/schedule_one.go#L428

Please forgive me if my understanding is wrong.

I would like to confirm the core issue. Your question is, you wrote a custom plugin, and then found that only the filter method was executed, but the score method was not executed, right? You can first check how many nodes your test cluster has. If there is only a single node, the scheduler will only use this node for scheduling by default and will not execute scoring process. refer to: https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/schedule_one.go#L428

Please forgive me if my understanding is wrong.

Thank you very much for your reply,You understood me well, but my questions were not clear enough.According to the code you provided, I can understand that the scoring method did not execute, but the queuesort method did not execute, I understand that queuesort has nothing to do with the number of nodes.I hope you can guide me,Thank you!!

queueSort:
enabled:
- name: nodeAge
disabled:
- name: "*"

You can confirm whether the configuration is correct.

queueSort:
enabled:

  • name: nodeAge
    disabled:
  • name: "*"

You can confirm whether the configuration is correct.

I0617 10:38:41.617760   29590 configfile.go:101] "Using component config" config=<
	apiVersion: kubescheduler.config.k8s.io/v1
	clientConnection:
	  acceptContentTypes: ""
	  burst: 100
	  contentType: application/vnd.kubernetes.protobuf
	  kubeconfig: /etc/kubernetes/scheduler.conf
	  qps: 50
	enableContentionProfiling: true
	enableProfiling: true
	kind: KubeSchedulerConfiguration
	leaderElection:
	  leaderElect: false
	  leaseDuration: 15s
	  renewDeadline: 10s
	  resourceLock: leases
	  resourceName: kube-scheduler
	  resourceNamespace: kube-system
	  retryPeriod: 2s
	parallelism: 16
	percentageOfNodesToScore: 0
	podInitialBackoffSeconds: 1
	podMaxBackoffSeconds: 10
	profiles:
	- pluginConfig:
	  - args:
	      apiVersion: kubescheduler.config.k8s.io/v1
	      kind: DefaultPreemptionArgs
	      minCandidateNodesAbsolute: 100
	      minCandidateNodesPercentage: 10
	    name: DefaultPreemption
	  - args:
	      apiVersion: kubescheduler.config.k8s.io/v1
	      hardPodAffinityWeight: 1
	      ignorePreferredTermsOfExistingPods: false
	      kind: InterPodAffinityArgs
	    name: InterPodAffinity
	  - args:
	      apiVersion: kubescheduler.config.k8s.io/v1
	      kind: NodeAffinityArgs
	    name: NodeAffinity
	  - args:
	      apiVersion: kubescheduler.config.k8s.io/v1
	      kind: NodeResourcesBalancedAllocationArgs
	      resources:
	      - name: cpu
	        weight: 1
	      - name: memory
	        weight: 1
	    name: NodeResourcesBalancedAllocation
	  - args:
	      apiVersion: kubescheduler.config.k8s.io/v1
	      kind: NodeResourcesFitArgs
	      scoringStrategy:
	        resources:
	        - name: cpu
	          weight: 1
	        - name: memory
	          weight: 1
	        type: LeastAllocated
	    name: NodeResourcesFit
	  - args:
	      apiVersion: kubescheduler.config.k8s.io/v1
	      defaultingType: System
	      kind: PodTopologySpreadArgs
	    name: PodTopologySpread
	  - args:
	      apiVersion: kubescheduler.config.k8s.io/v1
	      bindTimeoutSeconds: 600
	      kind: VolumeBindingArgs
	    name: VolumeBinding
	  plugins:
	    bind: {}
	    filter:
	      enabled:
	      - name: nodeAge
	        weight: 0
	    multiPoint:
	      enabled:
	      - name: PrioritySort
	        weight: 0
	      - name: NodeUnschedulable
	        weight: 0
	      - name: NodeName
	        weight: 0
	      - name: TaintToleration
	        weight: 3
	      - name: NodeAffinity
	        weight: 2
	      - name: NodePorts
	        weight: 0
	      - name: NodeResourcesFit
	        weight: 1
	      - name: VolumeRestrictions
	        weight: 0
	      - name: EBSLimits
	        weight: 0
	      - name: GCEPDLimits
	        weight: 0
	      - name: NodeVolumeLimits
	        weight: 0
	      - name: AzureDiskLimits
	        weight: 0
	      - name: VolumeBinding
	        weight: 0
	      - name: VolumeZone
	        weight: 0
	      - name: PodTopologySpread
	        weight: 2
	      - name: InterPodAffinity
	        weight: 2
	      - name: DefaultPreemption
	        weight: 0
	      - name: NodeResourcesBalancedAllocation
	        weight: 1
	      - name: ImageLocality
	        weight: 1
	      - name: DefaultBinder
	        weight: 0
	      - name: SchedulingGates
	        weight: 0
	    permit: {}
	    postBind: {}
	    postFilter: {}
	    preBind: {}
	    preEnqueue: {}
	    preFilter: {}
	    preScore: {}
	    queueSort:
	      disabled:
	      - name: '*'
	        weight: 0
	      enabled:
	      - name: nodeAge
	        weight: 0
	    reserve: {}
	    score:
	      enabled:
	      - name: nodeAge
	        weight: 0
	  schedulerName: my-scheduler
 >

This is the scheduler output configuration, configuration should be no problem, I tested https://github.com/kubernetes-sigs/scheduler-plugins/tree/master/pkg/qos also no log output, this is very strange

I've found the cause, the pod schedule is too fast to cause the problem, the queuesort method will not be called if the queue length is equal to 1