Scheduling Classes
SchedulingClass - это cluster-scoped custom resource, который позволяет администраторам задавать политики размещения для tenant workload. Когда tenant назначен scheduling class, все его pod автоматически направляются в custom scheduler Cozystack, который объединяет ограничения, заданные классом, с ограничениями, уже указанными в pod.
Это позволяет операторам платформы закреплять tenant за конкретными дата-центрами, availability zone или группами узлов без изменения отдельных application charts.
Как это работает
Функция состоит из двух компонентов:
Lineage-controller webhook (часть
cozystack): mutating admission webhook, который перехватывает создание pod в tenant namespace. Если у namespace есть меткаscheduler.cozystack.io/scheduling-class, webhook задаетschedulerName: cozystack-schedulerи добавляет аннотациюscheduler.cozystack.io/scheduling-classна каждый pod. Если указанный SchedulingClass CR не существует, например scheduler не установлен, pod остаются без изменений и планируются обычным способом.Cozystack scheduler (пакет
cozystack-scheduler): custom Kubernetes scheduler, который работает рядом со стандартным scheduler. Во время планирования он находит SchedulingClass, указанный в аннотации pod, и объединяет ограничения CR (node affinity, pod affinity/anti-affinity, topology spread) с собственным spec pod полностью в памяти, не изменяя pod в API server.
Предварительные требования
- Cozystack v1.2+
- The
cozystack-schedulersystem package (v0.2.0+)
Установка scheduler
cozypkg add cozystack.cozystack-scheduler
Создание SchedulingClass
SchedulingClass CR повторяет привычные примитивы планирования Kubernetes. Все поля необязательны: указывайте только те ограничения, которые вам нужны.
Пример: закрепление workload за дата-центром
apiVersion: cozystack.io/v1alpha1
kind: SchedulingClass
metadata:
name: dc-west
spec:
nodeSelector:
topology.kubernetes.io/region: us-west-2
Pod, назначенные этому классу, будут планироваться только на узлы с меткой
topology.kubernetes.io/region=us-west-2.
Пример: распределение по availability zone
apiVersion: cozystack.io/v1alpha1
kind: SchedulingClass
metadata:
name: zone-spread
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
Примечание
Если уtopologySpreadConstraint или у условия pod affinity/anti-affinity значение
labelSelector равно nil, scheduler автоматически заполняет его селектором,
который соответствует identity labels приложения Cozystack (apps.cozystack.io/application.group,
.kind, .name). Это позволяет задавать универсальные политики распределения или anti-affinity
без жестко прописанных значений меток для каждого приложения.Пример: требование выделенных узлов с anti-affinity
apiVersion: cozystack.io/v1alpha1
kind: SchedulingClass
metadata:
name: dedicated-nodes
spec:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-pool
operator: In
values:
- dedicated
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
Это закрепляет workload за узлами из пула dedicated и распределяет pod по
хостам. labelSelector для anti-affinity автоматически заполняется для каждого приложения, поэтому
pod из разных приложений одного tenant все еще могут попадать на один узел.
Полный справочник spec SchedulingClass
| Поле | Тип | Описание |
|---|---|---|
spec.nodeSelector | map[string]string | Простые key-value метки узлов, которым должны соответствовать все подходящие узлы. |
spec.nodeAffinity | NodeAffinity | Обязательные и предпочтительные правила node affinity. |
spec.podAffinity | PodAffinity | Обязательные и предпочтительные правила совместного размещения pod. |
spec.podAntiAffinity | PodAntiAffinity | Обязательные и предпочтительные правила разнесения pod. |
spec.topologySpreadConstraints | []TopologySpreadConstraint | Ограничения topology spread для равномерного распределения по failure domain. |
Назначение SchedulingClass tenant
При создании или редактировании tenant задайте параметр schedulingClass равным имени
существующего SchedulingClass CR:
Через dashboard:
Выберите scheduling class в выпадающем списке формы создания tenant.
Через Helm values (values.yaml):
schedulingClass: dc-west
Через tenant secret (наследование дочерними tenant):
Если родительскому tenant назначен scheduling class, все дочерние tenant наследуют его автоматически. Дочерний tenant не может переопределить scheduling class родителя: он может задать свой class только если у родителя его нет.
Назначение записывает метку scheduler.cozystack.io/scheduling-class в namespace
tenant. Webhook читает эту метку (или определяет ее из owning Application CR), чтобы
вставить имя scheduler и аннотацию в pod.
Автоматически заполняемые label selectors
Scheduler (v0.2.0+) автоматически заполняет поля labelSelector со значением nil
в условиях pod affinity, pod anti-affinity и topology spread constraint. Он использует
identity labels приложения Cozystack у pod:
apps.cozystack.io/application.groupapps.cozystack.io/application.kindapps.cozystack.io/application.name
Это означает, что универсальный SchedulingClass, например:
spec:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
автоматически ограничит anti-affinity pod одного приложения: каждое приложение получит собственное поведение anti-affinity без отдельного SchedulingClass для каждого приложения.
Ключи меток по умолчанию можно переопределить в Helm values scheduler:
defaultLabelSelectorKeys:
- apps.cozystack.io/application.group
- apps.cozystack.io/application.kind
- apps.cozystack.io/application.name
Если у условия уже есть явный labelSelector, он сохраняется без изменений.
Операторы без встроенной поддержки schedulerName
Некоторые операторы, используемые Cozystack, не предоставляют schedulerName в своих CRD.
Подход на основе webhook обрабатывает такие случаи прозрачно, потому что изменяет pod
напрямую во время admission, независимо от того, какой оператор их создал:
- etcd-operator
- redis-operator (spotahome)
- mariadb-operator
- clickhouse-operator (altinity)
Для workload, которыми управляют эти операторы, специальная конфигурация не требуется.
Проверка настройки
Убедитесь, что scheduler запущен:
kubectl get pods -n cozy-system -l app.kubernetes.io/name=cozystack-schedulerУбедитесь, что SchedulingClass существует:
kubectl get schedulingclassesПроверьте, что namespace tenant содержит метку:
kubectl get ns tenant-example -o jsonpath='{.metadata.labels.scheduler\.cozystack\.io/scheduling-class}'Проверьте, что pod в namespace tenant используют custom scheduler:
kubectl get pods -n tenant-example -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.schedulerName}{"\n"}{end}'