Open-Source Wikis

/

Kubernetes

/

Components

/

kube-scheduler

kubernetes/kubernetes

kube-scheduler

The kube-scheduler is the component that decides which node each new pod runs on. Architecturally it is a single binary with a pluggable framework: every constraint, preference, and post-bind hook is a plugin registered through the pkg/scheduler/framework API.

Directory layout

cmd/kube-scheduler/
├── scheduler.go                      # main(), 5 lines
└── app/
    ├── server.go                     # NewSchedulerCommand, Run
    └── options/                      # KubeSchedulerOptions, profile config

pkg/scheduler/
├── scheduler.go                      # The Scheduler struct, Run loop
├── schedule_one.go                   # Per-pod scheduling cycle
├── schedule_one_podgroup.go          # Gang/podgroup scheduling
├── eventhandlers.go                  # Informer event → queue routing
├── extender.go                       # Legacy HTTP-based extender support
├── apis/config/                      # KubeSchedulerConfiguration types
├── backend/
│   ├── api_cache/                    # Read-side cache used by plugins
│   ├── api_dispatcher/               # Async write batching (gated by SchedulerAsyncAPICalls)
│   ├── cache/                        # Internal node-and-pod cache; see also debugger/
│   └── queue/                        # The scheduling queue: active / backoff / unschedulable / gated
├── framework/
│   ├── interface.go                  # Plugin extension-point interfaces
│   ├── types.go                      # NodeInfo, PodInfo, CycleState, QueuedPodInfo
│   ├── runtime/                      # Plugin orchestrator + instrumentation
│   ├── plugins/                      # Built-in plugins (see below)
│   ├── preemption/                   # Preemption helper used by the default-preemption plugin
│   ├── parallelize/                  # Bounded-parallelism helper for filter/score
│   ├── api_calls/                    # Bind/Patch/Update wrappers that respect the dispatcher
│   └── autoscaler_contract/          # Hooks consumed by Cluster Autoscaler
├── metrics/                          # Prometheus metrics
└── profile/                          # Multi-profile config evaluation

How a pod gets scheduled

graph TD
    Q[SchedulingQueue] -->|NextPod| Cycle[Scheduling cycle]
    Cycle --> PreFilter
    PreFilter --> Filter
    Filter -->|fits| Score
    Filter -->|none fit| Preempt[PostFilter / preemption]
    Score --> NormalizeScore
    NormalizeScore --> Reserve
    Reserve --> Permit
    Permit --> PreBind
    PreBind --> Bind
    Bind --> PostBind
    Preempt -.requeue.-> Q

The cycle is in pkg/scheduler/schedule_one.go. It:

  1. Pulls a pod off the active queue.
  2. Snapshots the cluster state (a copy of pkg/scheduler/backend/cache.Cache).
  3. Runs PreFilter plugins — they can compute per-pod state stored in the framework's CycleState.
  4. Runs Filter plugins against every node in parallel. Nodes returning Unschedulable are eliminated.
  5. If at least one node fits, run PreScore then Score plugins. Each plugin returns a 0–100 score per node.
  6. NormalizeScore lets a plugin re-scale its scores. The scheduler then computes a weighted sum across plugins.
  7. The highest-scored node wins ties via random selection.
  8. Reserve plugins are called to mark the assumed pod-on-node binding (e.g., volume binding holds claim reservations).
  9. Permit plugins can delay (e.g., gang scheduling) or reject. If they delay, the pod is requeued.
  10. PreBind runs (including the volume-binding plugin's actual PVC bind). On error, Reserve is rolled back.
  11. Bind plugins (default: write Pod.Spec.NodeName via Patch). External binders are also allowed.
  12. PostBind for any cleanup or notification.

If Filter returns no candidates, PostFilter plugins run — most importantly defaultpreemption (pkg/scheduler/framework/plugins/defaultpreemption), which can evict lower-priority pods from a candidate node to make room.

The scheduling queue

pkg/scheduler/backend/queue implements a four-band priority queue:

  • Active queue — pods ready to be scheduled, ordered by priority.
  • Backoff queue — pods that failed scheduling recently. Re-enter the active queue after exponential backoff.
  • Unschedulable pods map — pods that no node fits. Re-evaluated when a relevant cluster event occurs (a node becomes Ready, a Resource is freed, a PodAntiAffinity peer is deleted, …).
  • Gated pods — pods whose SchedulingGates have not been removed.

Cluster events are mapped to "which pods should we reconsider" via the EventToRegister set each plugin declares. This avoids waking every unschedulable pod for every irrelevant change.

Built-in plugins

Located in pkg/scheduler/framework/plugins/:

Plugin Extension points Purpose
nodename Filter Honour Pod.Spec.NodeName
nodeunschedulable Filter Skip nodes with Spec.Unschedulable
nodeaffinity Filter, Score NodeSelector + NodeAffinity
noderesources (fit, balanced, leastallocated, mostallocated, requestedtocapacityratio) Filter, Score, PreScore CPU/memory/ephemeral-storage fit and balancing
nodevolumelimits Filter Per-CSI-driver attach limits
nodeports Filter hostPort conflicts
tainttoleration Filter, PreScore, Score NoSchedule / PreferNoSchedule
podtopologyspread PreFilter, Filter, PreScore, Score Spread by topologyKey
interpodaffinity PreFilter, Filter, PreScore, Score Pod affinity / antiaffinity
volumebinding PreFilter, Filter, Reserve, PreBind PVC binding decisions
volumerestrictions / volumezone Filter Volume-specific constraints
imagelocality Score Prefer nodes that already have the image
defaultbinder Bind The Patch-based default binder
defaultpreemption PostFilter Standard preemption
dynamicresources PreFilter, Filter, Reserve, PreBind, PostBind Dynamic Resource Allocation
gangscheduling / podgrouppodscount Permit, Reserve, Filter Gang/PodGroup support
nodedeclaredfeatures Filter Match Pod.Spec.NodeRequirements against Node.Status.Features
topologyaware Filter, Score Topology-aware scheduling for heterogeneous clusters
queuesort QueueSort Default ordering for the active queue
schedulinggates PreEnqueue Implement Pod.Spec.SchedulingGates

The full registry is in pkg/scheduler/framework/plugins/registry.go.

Profiles

A KubeSchedulerConfiguration lets cluster operators define multiple profiles. A profile is a named (plugin-set, plugin-config) tuple; pods opt into a profile via Pod.Spec.SchedulerName. The default profile is named default-scheduler. Multi-profile clusters can run several scheduling policies in one binary.

Async API calls

The SchedulerAsyncAPICalls feature gate (and the pkg/scheduler/backend/api_dispatcher) decouples scheduling decisions from API-server write latency. With the gate on, the scheduler's bind/patch/update calls are queued through an APIDispatcher that batches and serializes them. The internal cache reflects the post-write state immediately so the next scheduling cycle can proceed.

Sub-page

Key source files

File Purpose
pkg/scheduler/scheduler.go The Scheduler struct, Run loop
pkg/scheduler/schedule_one.go Per-pod scheduling cycle
pkg/scheduler/eventhandlers.go Informer events → queue updates
pkg/scheduler/framework/interface.go Plugin extension-point interfaces
pkg/scheduler/framework/runtime/framework.go Plugin runner
pkg/scheduler/framework/plugins/registry.go Plugin registry
pkg/scheduler/backend/queue/scheduling_queue.go The four-band queue
pkg/scheduler/backend/cache/cache.go Internal node + pod cache
cmd/kube-scheduler/app/server.go Boot, Cobra command

Integration points

  • kube-apiserver — the only thing the scheduler talks to. It uses informers for read and Patch for write.
  • Cluster Autoscaler — reads pkg/scheduler/framework/autoscaler_contract to predict whether a pending pod would fit if a new node existed.
  • Volume controllervolumebinding plugin coordinates with the PV controller in kube-controller-manager.
  • DRA driver kubelet plugins — the dynamicresources plugin reads ResourceSlice and writes ResourceClaim allocations consumed by kubelet.

Entry points for modification

  • Adding a new plugin: implement one or more extension-point interfaces from pkg/scheduler/framework/interface.go, register it in pkg/scheduler/framework/plugins/registry.go, optionally add a config schema under pkg/scheduler/apis/config/.
  • Tuning a profile: edit KubeSchedulerConfiguration YAML or change the default in pkg/scheduler/apis/config/v1.
  • Replacing the binder: implement a BindPlugin that talks to your custom binder service; disable defaultbinder in the profile.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

kube-scheduler – Kubernetes wiki | Factory