Chris Collins

Tools · containers

Kubernetes scheduling explainer

Paste your nodes and a pod or Deployment and see which nodes it can run on and why — every scheduler filter per node, the scores and weights that pick the winner, the FailedScheduling message, preemption victims, and N replicas placed one after another — checked against the real kube-scheduler v1.36.

Added

Works with

How to use it

Why is my pod Pending? Why did all three replicas land in one zone? Paste the cluster and the workload and this page runs the same filters and scores as kube-scheduler’s default profile, node by node, and shows its reasoning.

How to use it

  1. The cluster. Paste kubectl get nodes,pods,pdb,priorityclass -A -o yaml (or -o json) — any mix of Node, Pod, PodDisruptionBudget, PriorityClass, RuntimeClass and Namespace objects. Pods count when they are bound to a listed node and not Succeeded or Failed. No cluster at hand? The Node builder makes groups of nodes over zones with labels and taints, or load an example.

  2. The pod. Paste a Pod, Deployment, StatefulSet, ReplicaSet, Job or CronJob. Replicas default to the workload’s; change them to see where the next ones would go. Like the API server, the page adds the default not-ready/unreachable NoExecute tolerations (300 s) unless you untick it.

  3. Read the result.

    • Filters — for every node, each filter in the scheduler’s order: NodeUnschedulable (cordoned), NodeName, TaintToleration (NoSchedule and NoExecute; tolerationSeconds noted), NodeAffinity (nodeSelector and required terms with In/NotIn/Exists/DoesNotExist/Gt/Lt and matchFields), NodePorts, NodeResourcesFit (requests — including sidecar and init containers, pod-level resources and RuntimeClass overhead — against allocatable minus what bound pods request, and the pod count), PodTopologySpread (skew per domain, minDomains, nodeAffinityPolicy, nodeTaintsPolicy, matchLabelKeys) and InterPodAffinity (required affinity and anti-affinity, and other pods' anti-affinity against this one). The outlined cell is the first failure — the one the scheduler reports.

    • Scores — for nodes that pass: TaintToleration ×3 (PreferNoSchedule taints), NodeAffinity ×2 (preferred terms), PodTopologySpread ×2 (ScheduleAnyway constraints, or the built-in spreading over hostname and zone when the pod has none and a Service or controller selects it), InterPodAffinity ×2 (preferred terms both ways, and others' required affinity), NodeResourcesFit ×1 (least allocated, counting 100m/200Mi for containers without requests), NodeResourcesBalancedAllocation ×1 (since v1.36: how much the pod improves the node’s CPU/memory balance) and ImageLocality ×1 (status.images on the node).

    • When nothing fits: the FailedScheduling message exactly as kubectl describe pod shows it, and preemption — which nodes could make room by evicting lower-priority pods, which pods would go (most important spared first, PodDisruptionBudgets respected where possible), and why that node was chosen (fewest PDB violations, lowest victim priority, smallest priority sum, fewest victims, latest start time). preemptionPolicy: Never is honoured.

    • Replicas — each replica placed in turn, seeing the ones before it, so you can watch spreading, anti-affinity and resource exhaustion play out. Click a row for its tables.

The examples cover a mixed cluster with control-plane, cordoned, spot and GPU nodes; preemption with a PDB; required pod affinity with anti-affinity; a pod that fits nowhere for five different reasons; minDomains; scoring by resources, balance and images; soft rules; host ports with sidecars; and a priority that never preempts.

Not modelled: volumes (VolumeBinding, VolumeZone, attach limits), Dynamic Resource Allocation claims, scheduler extenders and custom profiles, and the random tie-break (ties are shown). Pods created by a DaemonSet are pinned to their node; here a DaemonSet’s replicas are tried on the whole cluster.

Related: build manifests with the manifest builder, render a chart or overlay in the Helm and Kustomize renderer and send its Deployment here with Check scheduling, watch the control loop in the Kubernetes simulator, and find the kubectl commands for taints, cordons and describe in the kubectl helper.

How it was checked

The model follows the plugin source of kube-scheduler v1.36.1 (the plugins under pkg/scheduler/framework/plugins, the default plugin set and weights in default_plugins.go, and FitError for the message). Every example was then replayed on a throwaway cluster running the real kube-scheduler v1.36.1 (under kwok, with simulated nodes): the placements of all replicas, the FailedScheduling messages character for character, the preempted pod and all 275 per-plugin scores the scheduler logged agree with this page. The tests keep that record.

Browser support

Any current browser. Thousands of nodes are fine; replicas are capped at 500.

Privacy

Everything runs in the page; what you paste is kept in this browser’s local storage and never uploaded. A share link carries the cluster and workload YAML in the link, so scrub it before sharing (kubectl get … -o yaml output contains annotations, environment variables and image names).

Runs entirely in your browser; nothing you type leaves this page.