Коротко про kube-scheduler в Kubernetes

Kate

Administrator
Команда форума
Сегодня рассмотрим такой компонент в Kubernetes, как kube‑scheduler — это компонент control plane в Kubernetes, отвечающий за назначение подов на узлы.

Полный процесс включает четыре этапа:

  1. Queueing — под попадает в очередь планировщика.
  2. Filtering — отсеиваются неподходящие ноды.
  3. Scoring — оцениваются оставшиеся ноды.
  4. Binding — под назначается на лучшую ноду.

Как kube-scheduler принимает решения?​

Сначала kube‑scheduler убирает ноды, которые не соответствуют требованиям пода. Если нода не подходит, она сразу исключается.

Критерии фильтрации:

  • Node Unschedulable — если у ноды стоит spec.unschedulable: true, на неё нельзя посадить под.
  • NodeSelector — поды могут размещаться только на нодах с нужными labels.
  • Node Affinity — предпочтения, какие ноды нам нравятся.
  • Pod Affinity / Anti‑Affinity — можно ли размещать поды рядом или нужно их разнести?
  • Volume Binding — если под запрашивает PVC, он должен попасть на ноду с доступным storage.
  • Taints & Tolerations — ограничения, которые накладывают админы.
Пример пода, который хочет жить только на нодах с SSD:

apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-app
image: nginx
nodeSelector:
disktype: ssd
Если подходящих нод нет, под будет висеть в Pending.

После фильтрации kube‑scheduler оценивает оставшиеся ноды и выбирает лучшую.

Основные стратегии:

  • Least Requested Priority — чем меньше загружена нода, тем лучше.
  • Balanced Resource Allocation — баланс CPU/RAM.
  • Image Locality — нода, у которой уже есть нужный образ, получает приоритет.
  • Node Affinity Priority — предпочтения, заданные через nodeAffinity.
  • Taint Toleration Priority — обработка taints и tolerations.
Пример кастомного приоритета, который группирует поды на одной ноде:

apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
plugins:
score:
enabled:
- name: PodTopologySpread
weight: 10
Так указываем планировщику: старайся селить мои поды ближе друг к другу.

Если ни одна нода не подходит, kube‑scheduler пытается освободить место. Он ищет менее приоритетные поды и может их вытеснить.

Механика:

  1. Под запрашивает priorityClassName: high-priority.
  2. kube‑scheduler не находит свободных нод.
  3. Он ищет слабые поды и выселяет их.
  4. Выселенные поды перезапускаются в другом месте.
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
preemptionPolicy: PreemptLowerPriority
Так создается некий вип класс подов, которые будут вытеснять слабые.

Как запустить кастомный планировщик?​

Можно написать свой планировщик, если стандартный не подходит. Например, если нужно учитывать нестандартные метрики: доступные GPU, сетевую нагрузку или latency между нодами.

Пример кастомного планировщика на Go, который размещает поды только на ноды с минимум 50% свободного CPU.

package main

import (
"context"
"fmt"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/scheduler/framework"
)

type CustomScheduler struct{}

func (cs *CustomScheduler) Name() string {
return "CustomCPUScheduler"
}

func (cs *CustomScheduler) Score(ctx context.Context, state *framework.CycleState, pod *framework.PodInfo, nodeName string) (int64, *framework.Status) {
clientset, err := kubernetes.NewForConfig(rest.InClusterConfig())
if err != nil {
return 0, framework.AsStatus(err)
}

node, err := clientset.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
if err != nil {
return 0, framework.AsStatus(err)
}

allocatableCPU := node.Status.Allocatable["cpu"]
capacityCPU := node.Status.Capacity["cpu"]

// Подсчёт свободного CPU
freeCPU := allocatableCPU.Value() * 100 / capacityCPU.Value()
if freeCPU > 50 {
return int64(freeCPU), framework.NewStatus(framework.Success)
}

return 0, framework.NewStatus(framework.Unschedulable, "Not enough free CPU")
}

func main() {
fmt.Println("Запуск кастомного планировщика...")
}
Подключаемся к API Kubernetes, после получаем список нод. Далее считаем, сколько CPU занято, если свободно меньше 50% CPU, не размещаем под, аесли больше 50%, ставим под и возвращаем успех.

Подробнее с kube‑scheduler можно ознакомиться здесь.

 
Сверху