Cluster scheduling answers 'which task goes to which GPU and how to avoid wasting resources'. The K8s default scheduler (kube-scheduler) is a two-phase pipeline: ① Filtering: drop nodes that violate hard constraints — resource requests (CPU/memory/extended resources like GPUs), NodeSelector and node affinity, taints/tolerations, port and volume conflicts; ② Scoring: rank the feasible nodes with policies (least-requested spreads load, most-requested packs tightly, custom priorities) and bind the Pod to the best one. GPU scheduling: the device plugin advertises GPUs as an indivisible extended resource
nvidia.com/gpu; the scheduler allocates whole cards, never fractional ones — memory and SMs cannot be safely split, so allocation is by card, not by MB; for finer granularity use MIG (Multi-Instance GPU, hardware slicing on A100/H100, up to 7 instances per card, e.g.
1g.5gb,
7g.80gb), where each instance owns fixed SMs and memory partitions with hardware isolation and no performance jitter — unlike vGPU time-slicing. Ray is an application-level scheduler built on top of K8s: Driver (entry script) → Head (global control plane GCS + Raylet) → one Raylet per node (local scheduler + Object Store, an in-memory shared store giving zero-copy data transfer between tasks on the same node) → Workers (execute Tasks/Actors). Autoscaling: the Ray Autoscaler adds/removes nodes based on the pending-task queue and reclaims idle ones; K8s scales via HPA or custom metrics (QPS, queue length, GPU utilization); on scale-down or spot preemption, in-flight work is drained gracefully, backed by replicas and checkpoint-resume.