- Обзор
- Простое планирование
- NodeName [1]
- nodeSelector [2]
- Сродство узлов [4]
- Сродство узлов
- Описание параметров сродства узлов
- Пример сродства узлов
- Сродство к стручкам [4]
- Конфигурация сродства стручков
- Под анти-аффинность
- Пороки и терпимость [6]
- Пятна
- Допуски
- Изгнание [7]
- Распределение приоритетов и преимущественное использование
- Невыкуп
- Преемственность
Обзор
kube-scheduler
— это основной компонент плоскости управления kubernetes, чье поведение по умолчанию заключается в распределении стручков по узлам при балансировке использования ресурсов между стручками и узлами. В терминах обывателя это означает, что kube-scheduler
работает на плоскости управления и распределяет рабочую нагрузку на кластер Kubernetes.
В этой статье мы подробно рассмотрим использование планирования Kubernetes: «Общее планирование», «Аффинити» и «Планирование выселений для Taint и Tolerance». И наконец, мы рассмотрим настройку производительности планировщика, т.е. тонкую настройку параметров планировщика под кластер.
Простое планирование
NodeName [1]
В простейшем планировании можно указать поле NodeName, которое позволяет Pod запускаться на соответствующем узле. Это показано в следующем списке ресурсов
apiVersion: v1
kind: Pod
metadata:
name: netpod
spec:
containers:
- name: netbox
image: cylonchau/netbox
nodeName: node01
С приведенным выше списком ресурсов Pod будет запущен на узле 01. Этот сценарий имеет ряд недостатков, таких как недостаточное количество ресурсных узлов и неизвестные имена узлов, и в целом он не рекомендуется.
$ kubectl describe pods netpod
Name: netpod
Namespace: default
...
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulling 86s kubelet Pulling image "cylonchau/netbox"
Normal Pulled 17s kubelet Successfully pulled image "cylonchau/netbox"
Normal Created 17s kubelet Created container netbox
Normal Started 17s kubelet Started container netbox
$ kubectl get pods netpod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
netpod 1/1 Running 0 48m 192.168.0.3 node01 <none> <none>
Вывод выше показывает, что метод NodeName
не запланирован планировщиком
nodeSelector [2]
label
— очень важное понятие в kubernetes, обычно каждому рабочему узлу присваивается несколько меток, которые можно просмотреть с помощью команды
$ kubectl get node node01 --show-labels
NAME STATUS ROLES AGE VERSION LABELS
node01 Ready <none> 15h v1.18.20 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
nodeSelector
выбирает узлы с определенной меткой или метками на основе этих меток. Например, если вам нужно запустить pod на определенном наборе узлов, вы можете установить nodeSelector
в «PodSpec» как набор пар ключ-значение.
apiVersion: apps/v1
kind: Deployment
metadata:
name: netpod-nodeselector
spec:
selector:
matchLabels:
app: netpod
replicas: 2
template:
metadata:
labels:
app: netpod
spec:
containers:
- name: netbox
image: cylonchau/netbox
nodeSelector:
beta.kubernetes.io/os: linux
Для приведенного выше стручка планировщик Kubernetes найдет узлы с тегом beta.kubernetes.io/os: linux
. О других встроенных тегах kubernetes см. [3]
Для селектора тегов, в конечном счете, он будет распределен по узлам с тегами
kubectl describe pod netpod-nodeselector-69fdb567d8-lcnv6
Name: netpod-nodeselector-69fdb567d8-lcnv6
Namespace: default
...
QoS Class: BestEffort
Node-Selectors: beta.kubernetes.io/os=linux
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 8m18s default-scheduler Successfully assigned default/netpod-nodeselector-69fdb567d8-lcnv6 to node01
Normal Pulling 8m17s kubelet Pulling image "cylonchau/netbox"
Normal Pulled 7m25s kubelet Successfully pulled image "cylonchau/netbox"
Normal Created 7m25s kubelet Created container netbox
Normal Started 7m25s kubelet Started container netbox
Сродство узлов [4]
Сродство (Affinity
) — это общая концепция для систем, использующих планирование, и обычно сродство возникает в параллельной (parallel
) среде; в этой среде сродство обеспечивает возможность более эффективного выполнения стручка на одном узле, чем на других. и расчет сродства обычно состоит из множества условий. В целом, аффинити делится на «мягкое аффинити и жесткое аффинити
- Soft Affinity, или мягкое сродство, — это когда планировщик держит задачи на одном и том же узле настолько, насколько это возможно. Это только попытка; если это невозможно, процесс переносится на другой узел
- Hard affinity, жесткое сродство, принудительное привязывание задачи к определенному узлу.
Концепция affinity также поддерживается в kubernetes, и affinity — это алгоритм, формируемый совместно с nodeSelector. Жесткая близость определяется как requiredDuringSchedulingIgnoredDuringExecution
; мягкая близость определяется как предпочитаемыйПри планированииИгнорируемыйПри выполнении
- Жесткая близость (
requiredDuringSchedulingIgnoredDuringExecution
): должна быть выполнена, иначе планировщик не сможет запланировать Pod. - Мягкое сродство (
preferredDuringSchedulingIgnoredDuringExecution
): планировщик будет искать узлы, удовлетворяющие условию. Если ни один узел не соответствует требованиям, это правило будет проигнорировано, и планировщик все равно составит расписание Pod.
Сродство узлов
Описание параметров сродства узлов
Планировщик будет предпочитать планировать стручки на узлы, которые удовлетворяют выражению родства, указанному в этом поле, но он может выбрать узлы, которые нарушают одно или несколько выражений. Наиболее предпочтительным узлом является узел с наибольшей суммой весов, т.е. для каждого узла, удовлетворяющего всем требованиям планирования (запросы ресурсов, выражения сродства requiredDuringScheduling и т.д.), вычисляется сумма путем итерации по элементам этого поля Если узел соответствует соответствующим выражениям соответствия, то «weight » прибавляется к сумме; узел с наибольшей суммой является наиболее предпочтительным.
Если требование близости, указанное в этом поле, не выполняется во время отправки, капсула не будет отправлена на этот узел. Если требование близости, указанное в этом поле, больше не выполняется в какой-то момент во время выполнения стручка (например, из-за обновления), система может попытаться или не попытаться в конечном итоге исключить стручок из своего узла.
Диапазон аффинности применяется в разделе Pod.Spec
со следующими параметрами.
Примечания: matchFields использует поля из списка ресурсов (kubectl get node -o yaml), в то время как matchExpressions соответствует тегам
Пример сродства узлов
Во введении выше показано, как сложные требования к планированию могут быть лучше выражены в Kubernetes относительно nodeSelector
: сродство узлов, с использованием поля .spec.affinity.nodeAffinity
в PodSpec для указания соответствующего конфигурация сродства.
apiVersion: apps/v1
kind: Deployment
metadata:
name: netpod-nodeselector
spec:
selector:
matchLabels:
app: netpod
replicas: 2
template:
metadata:
labels:
app: netpod
spec:
containers:
- name: netbox
image: cylonchau/netbox
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: app
operator: In
values:
- test
Приведенный выше список показывает, что когда тег app: test
присутствует на узле, он будет отправлен на соответствующий узел, не имеет значения, если ни один узел не соответствует этим условиям, он будет отправлен на основе общего соответствия.
Когда присутствуют и жесткая, и мягкая политики, в зависимости от настройки, жесткая политика будет иметь более высокий приоритет, чем мягкая политика, даже если вес мягкой политики установлен на 100
apiVersion: apps/v1
kind: Deployment
metadata:
name: netpod-nodeselector
spec:
selector:
matchLabels:
app: netpod
replicas: 2
template:
metadata:
labels:
app: netpod
spec:
containers:
- name: netbox
image: cylonchau/netbox
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: app
operator: In
values:
- test
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- antarctica-east1
- antarctica-west1
Вот сообщение об ошибке
Warning FailedScheduling 4s (x3 over 24s) default-scheduler 0/2 nodes are available: 2 node(s) didn't match node selector.
Сродство к стручкам [4]
Pod affinity и anti-affinity — это ограничения на то, на каких узлах может быть запланирован Pod, основанные на метке Pod, уже запущенного на узле, а не на метке узла. Например, X удовлетворяет одному или нескольким условиям для выполнения Y. В этот раз Pod удовлетворяет выполнению в X. Где X — домен топологии, а Y — правило.
Примечания: Официальная документация не рекомендует использовать эту функцию в кластерах с более чем сотней узлов. [5]
Конфигурация сродства стручков
Сродство и антисродство узла аналогичны сродству узла, диапазон сродства применяется в разделе Pod.Spec.podAffinity
, который здесь не повторяется, см. раздел описания параметров сродства узла.
topologyKey, ==не допускается быть null==, это значение будет влиять на то, где развернут Pod, с точки зрения того, какая топология находится в соответствующем узле, который соответствует условию сродства, домен топологии topologyKey определяется меткой label.
В дополнение к topologyKey
, селектор меток labelSelector
и пространства имен namespaces
доступны как альтернативы одного уровня
apiVersion: apps/v1
kind: Deployment
metadata:
name: netpod-podaffinity
spec:
selector:
matchLabels:
app: podaffinity
replicas: 1
template:
metadata:
labels:
app: podaffinity
spec:
containers:
- name: podaffinity
image: cylonchau/netbox
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- netpod
topologyKey: zone
Если ни одна ботва не соответствует правилу, то статус ожидания
Warning FailedScheduling 59s (x2 over 59s) default-scheduler 0/2 nodes are available: 2 node(s) didn't match pod affinity rules, 2 node(s) didn't match pod affinity/anti-affinity.
Под анти-аффинность
Существуют сценарии, в которых некоторые узлы не должны иметь много ресурсов, т.е. некоторые узлы не хотят быть запланированными. Например, узел мониторинга не хочет иметь на себе много ресурсов из-за своей природы, или, в зависимости от конфигурации узла, узел более низкой конфигурации не хочет планировать много ресурсов; в этом случае планирование Pod, не соответствующее ожиданиям, ухудшит производительность сервиса, который он размещает. В этом случае требуется анти-аффинити (Anti-Affinity
), чтобы держать Pod подальше от этой группы узлов.
apiVersion: apps/v1
kind: Deployment
metadata:
name: netpod-podaffinity
spec:
selector:
matchLabels:
app: podaffinity
replicas: 1
template:
metadata:
labels:
app: podaffinity
spec:
containers:
- name: podaffinity
image: cylonchau/netbox
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- netpod
topologyKey: zone
Пороки и терпимость [6]
Пятна
В то время как affinity и anti-affinity могут предотвратить запуск Pods на определенных узлах, существует также проблема того, что affinity и anti-affinity должны быть объявлены для узлов, которые работают или не хотят работать, и если вы забудете объявить их, они все равно будут отправлены на соответствующий узел. kubernetes также предоставляет способ выселения Pods, который заключается в taints ( Taints
) и терпимости (Tolerations
).
Чтобы создать пятно
kubectl taint nodes node1 key1=value1:NoSchedule
$ kubectl taint nodes mon01 role=monitoring:NoSchedule
Удаление пятна.
kubectl taint nodes node1 key1=value1:NoSchedule-
В дополнение к NoSchedule
, существуют PreferNoSchedule
и NoExecute
Допуски
Если узел испорчен, он автоматически исключается из планирования. Хотя планирование будет неудачным, когда часть Predicate выполняется на испорченном узле, толерантность — это то, что делает pod толерантным к taint на этом узле, т.е. pod с толерантностью может быть запланирован поверх испорченного узла.
apiVersion: apps/v1
kind: Deployment
metadata:
name: netpod-podaffinity
spec:
selector:
matchLabels:
app: podaffinity
replicas: 1
template:
metadata:
labels:
app: podaffinity
spec:
containers:
- name: podaffinity
image: cylonchau/netbox
tolerations:
- key: "role"
operator: "Equal"
value: "monitoring"
effect: "NoSchedule"
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- netpod
topologyKey: zone
В tolerance есть специальное поле TolerationSeconds
, которое указывает, как долго терпеть порчу, которое не установлено по умолчанию, т.е. порча будет терпеться вечно. Значение 0 или отрицательное число означает, что выселение понимается. == Действует только если taint равен NoExecute
.
Атрибут operator
имеет два значения Exists
и Equal
.
- Если оператор
Exists
, атрибут value не требуется, поскольку суждение находится в испорченном случае. -
Если оператор
Equal
, то это означает, что связь между ключом и значением равна $key=value$. -
Пустой ключ и оператор
Exists
будет соответствовать всем, т.е. терпеть все пятна -
Empty
effect
соответствует всемeffect
, т.е. соответствует всем пятнам; этот случай с условием будет допускать все типы пятен
Изгнание [7]
Боды выселяются, когда для taint установлено значение NoExecute
, а условия выселения следующие.
- Капсула, которая не терпит запятнанности, будет немедленно выселена.
- Бод, который терпимо относится к taint, но не имеет настроенного атрибута
tolerationSeconds
, останется неизменным, т.е. узел останется привязанным к боду. - Бод, который терпимо относится к указанному taint и имеет настроенный атрибут
tolerationSeconds
, узел привязывается к боду только на настроенное время.
Kubernetes имеет встроенную функцию taint, при которой контроллер автоматически запятнает узел.
-
node.kubernetes.io/not-ready
: Сбой узла. СоответствуетReady
=False
из NodeCondition. -
node.kubernetes.io/unreachable
: Контроллер узла не может получить доступ к узлу. Соответствует NodeConditionReady
=Unknown
. -
node.kubernetes.io/memory-pressure
: давление на память узла. -
node.kubernetes.io/disk-pressure
: Дисковое давление узла. -
node.kubernetes.io/pid-pressure
: Узел имеет PID-давление. -
node.kubernetes.io/network-unavailable
: Сеть узла недоступна. -
node.kubernetes.io/unschedulable
: Node не является планируемым.
Примечания: Свойство Kubernetes
node.kubernetes.io/not-ready
и свойствоnode.kubernetes.io/unreachable
добавляют ограничение по времени допуска <#code tolerationSeconds=300. То есть, после обнаружения проблемы в бутоне он будет оставаться связанным в течение 5 минут.
Распределение приоритетов и преимущественное использование
В kubernetes также предусмотрен механизм приоритетов для стручков. С помощью механизма приоритетов можно обеспечить преимущественное использование ресурсов в параллельных системах. При преимущественном использовании стручки с более высоким приоритетом будут запланированы раньше стручков с более низким приоритетом, когда они еще не запланированы, а стручки с более низким приоритетом могут быть вытеснены стручками с более высоким приоритетом, когда ресурсы недоступны.
Функция приоритета предоставляется PriorityClasses. PriorityClasses
используются как ресурсы на уровне кластера, а не на уровне пространства имен, и используются только для объявления уровней приоритетов.
value
используется в качестве уровня приоритета, чем больше число, тем выше уровень приоритета. А name
— это имя данного уровня приоритета, аналогично другим значениям имени ресурса, содержание значения должно соответствовать ограничениям домена DNS.
globalDefault
является уровнем приоритета по умолчанию в кластере, и только один PriorityClass
может быть установлен на true
.
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for XYZ service pods only."
Примечания:
- Если в кластере не существует
PriorityClass
, все существующие Pods будут иметь приоритет 0.- Когда
globalDefault=true
установлен для кластера, это не изменяет приоритет уже существующих Pods. Это верно только для Pods, созданных послеPriorityClass
globalDefault=true
.- Если
PriorityClass
удаляется, существующие Подсистемы, которые все еще используют этотPriorityClass
, остаются неизменными, а вновь созданные Подсистемы не могут использовать этотPriorityClass
.
Невыкуп
Когда preemptionPolicy: Never
, Стручок не будет вытеснять другие Стручки, но если он не запланирован, он будет оставаться в очереди планирования, ожидая быть запланированным, пока не будут выполнены требования. ==Не вытесняющие стручки могут быть вытеснены другими стручками с высоким приоритетом==
Примечания: preemptionPolicy в Kubernetes v1.24 [stable]
preemptionPolicy
настроена как невытесняющая, с параметром по умолчанию PreemptLowerPriority
; это означает, что капсулам с более высоким приоритетом разрешено вытеснять капсулы с более низким приоритетом. if preemptionPolicy: Никогда
, означает, что Pod является невытесняющим.
Ниже приведен пример конфигурации без права выкупа
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority-nonpreempting
value: 1000000
preemptionPolicy: Never
globalDefault: false
description: "This priority class will not cause other pods to be preempted."
Когда приоритет настроен, контроллер приоритетного доступа будет использовать значение соответствующего PriorityClass
, настроенного в priorityClassName
для заполнения приоритета текущего Pod, или отклонит его, если не будет найдена соответствующая политика преимущественного использования.
Ниже приведен пример настройки приоритета в бутоне
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
priorityClassName: high-priority
Преемственность
Когда Pod создается, он попадает в очередь и ждет, когда его запланируют. планировщик выбирает Pod из очереди и пытается запланировать его на узел. Если не найдено ни одного узла, который бы отвечал всем заданным требованиям Под, то для Pending
Под включается предварительное использование. Когда бод ищет подходящий узел, т.е. пытается упредить узел, один или несколько бодов с более низким приоритетом, чем текущий бод, удаляются из этого узла, позволяя текущему боду быть отправленным в соответствующий узел. Когда из узла выселяется бод с более низким приоритетом, текущий бод может быть запланирован на этот узел, этот процесс известен как предварительное вымогательство preemption
.
А узел, который предоставляет ресурсы, готовые к выселению, становится номинированным узлом (nominated Node
), и когда Pod вытесняет узел, его nominatedNodeName
помечается как имя этого узла, хотя, конечно, за пометкой не обязательно следует имя узла, который должен быть вытеснен. Например, если другой узел становится доступным в то время, когда текущий Pod ожидает выселения Pod с более низким приоритетом, Pod будет вытеснен на этот узел.
Ссылка
[1] Создайте Pod, который будет запланирован на определенном узле
[2] nodeSelector
[3] метки аннотации пятна
[4] аффинность и антиаффинность
[5] сродство и антисродство
[6] запятнанность и терпимость
[7] выселения
[8] приоритетная преференция