Привет, Хабр! Сегодня рассмотрим такой компонент в Kubernetes, как kube‑scheduler — это компонент control plane в Kubernetes, отвечающий за назначение подов на узлы.
Полный процесс включает четыре этапа:
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 — ограничения, которые накладывают админы.
Пример пода, который хочет жить только на нодах с 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 пытается освободить место. Он ищет менее приоритетные поды и может их вытеснить.
Механика:
Под запрашивает
priorityClassName: high-priority.kube‑scheduler не находит свободных нод.
Он ищет слабые поды и выселяет их.
Выселенные поды перезапускаются в другом месте.
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 можно ознакомиться здесь.
В заключение рекомендую всем желающим к посещению открытый урок «Kubernetes + CI/CD + GitOps — как сделать стабильный деплой без выхода из кластера». Если интересно, записаться можно по ссылке.
Также список всех остальных онлайн-уроков от практикующих преподавателей можно посмотреть в календаре.
