Сегодня рассмотрим такой компонент в Kubernetes, как kube‑scheduler — это компонент control plane в Kubernetes, отвечающий за назначение подов на узлы.
Полный процесс включает четыре этапа:
Критерии фильтрации:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-app
image: nginx
nodeSelector:
disktype: ssd
Если подходящих нод нет, под будет висеть в Pending.
После фильтрации kube‑scheduler оценивает оставшиеся ноды и выбирает лучшую.
Основные стратегии:
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
plugins:
score:
enabled:
- name: PodTopologySpread
weight: 10
Так указываем планировщику: старайся селить мои поды ближе друг к другу.
Если ни одна нода не подходит, kube‑scheduler пытается освободить место. Он ищет менее приоритетные поды и может их вытеснить.
Механика:
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
preemptionPolicy: PreemptLowerPriority
Так создается некий вип класс подов, которые будут вытеснять слабые.
Пример кастомного планировщика на 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 можно ознакомиться здесь.
habr.com
Полный процесс включает четыре этапа:
- Queueing — под попадает в очередь планировщика.
- Filtering — отсеиваются неподходящие ноды.
- Scoring — оцениваются оставшиеся ноды.
- Binding — под назначается на лучшую ноду.
Как kube-scheduler принимает решения?
Сначала kube‑scheduler убирает ноды, которые не соответствуют требованиям пода. Если нода не подходит, она сразу исключается.Критерии фильтрации:
- Node Unschedulable — если у ноды стоит spec.unschedulable: true, на неё нельзя посадить под.
- NodeSelector — поды могут размещаться только на нодах с нужными labels.
- Node Affinity — предпочтения, какие ноды нам нравятся.
- Pod Affinity / Anti‑Affinity — можно ли размещать поды рядом или нужно их разнести?
- Volume Binding — если под запрашивает PVC, он должен попасть на ноду с доступным storage.
- Taints & Tolerations — ограничения, которые накладывают админы.
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 пытается освободить место. Он ищет менее приоритетные поды и может их вытеснить.
Механика:
- Под запрашивает priorityClassName: high-priority.
- kube‑scheduler не находит свободных нод.
- Он ищет слабые поды и выселяет их.
- Выселенные поды перезапускаются в другом месте.
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 можно ознакомиться здесь.

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