Обмеження топології розміщення Podʼів

Ви можете використовувати обмеження топології розміщення для контролю того, як Podʼи розподіляються по вашому кластеру серед доменів відмов, таких як регіони, зони, вузли та інші, визначені користувачем, топологічні домени. Це може допомогти забезпечити високу доступність, а також ефективне використання ресурсів.

Ви можете встановлювати типові обмеження на рівні кластера або налаштовувати обмеження топології розміщення для окремих навантажень.

Мотивація

Уявіть, що у вас є кластер, в якому до двадцяти вузлів, і ви хочете запустити навантаження, яке автоматично масштабує кількість реплік, які використовує. Тут може бути як два Podʼи, так і пʼятнадцять. Коли є лише два Podʼи, ви б хотіли, щоб обидва ці Podʼи не працювали на одному вузлі: ви ризикуєте, що відмова одного вузла призведе до зникнення доступу до вашого навантаження.

Крім цього основного використання, є деякі приклади використання, які дозволяють вашим навантаженням отримувати переваги високої доступності та використання кластера.

При масштабуванні та запуску більшої кількості Podʼів важливим стає інша проблема. Припустімо, що у вас є три вузли, на яких працюють по пʼять Podʼів на кожному. У вузлів достатньо потужності для запуску такої кількості реплік; проте клієнти, які взаємодіють з цим навантаженням, розподілені по трьох різних центрах обробки даних (або зонах інфраструктури). Тепер ви менше хвилюєтеся про відмову одного вузла, але ви помічаєте, що затримка вища, ніж ви хотіли б, і ви платите за мережеві витрати, повʼязані з передачею мережевого трафіку між різними зонами.

Ви вирішуєте, що при нормальній роботі ви б хотіли, щоб у кожній інфраструктурній зоні була приблизно однакова кількість реплік, і ви хотіли б, щоб кластер самостійно відновлювався у разі виникнення проблеми.

Обмеження топології розміщення Podʼів пропонують вам декларативний спосіб налаштування.

Поле topologySpreadConstraints

У API Pod є поле spec.topologySpreadConstraints. Використання цього поля виглядає так:

---
apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  # Налаштувати обмеження топології розміщення
  topologySpreadConstraints:
    - maxSkew: <ціле число>
      minDomains: <ціле число> # необовʼязково
      topologyKey: <рядок>
      whenUnsatisfiable: <рядок>
      labelSelector: <обʼєкт>
      matchLabelKeys: <список> # необовʼязково; бета з v1.27
      nodeAffinityPolicy: [Honor|Ignore] # необовязково; бета з v1.26
      nodeTaintsPolicy: [Honor|Ignore] # необовязково; бета з v1.26
  ### інші поля Pod тут

Примітка:

Для заданого значення topologyKey та whenUnsatisfiable може бути лише одне значення topologySpreadConstraint. Наприклад, якщо ви визначили topologySpreadConstraint, що використовує topologyKey "kubernetes.io/hostname" і значення whenUnsatisfiable "DoNotSchedule", ви можете додати інший topologySpreadConstraint для topologyKey "kubernetes.io/hostname" лише в тому випадку, якщо ви використовуєте інше значення whenUnsatisfiable.

Додаткову інформацію про це поле можна отримати, запустивши команду kubectl explain Pod.spec.topologySpreadConstraints або звернувшись до розділу планування довідки API для Pod.

Визначення обмежень топології розміщення

Ви можете визначити один або кілька записів topologySpreadConstraints, щоб вказати kube-scheduler, як розмістити кожний новий Pod відносно наявних Podʼів у вашому кластері. Ці поля включають:

  • maxSkew описує ступінь нерівномірності розподілу Podʼів. Ви повинні вказати це поле, а його числове значення має бути більше нуля. Його семантика відрізняється залежно від значення параметра whenUnsatisfiable:

    • якщо ви виберете whenUnsatisfiable: DoNotSchedule, тоді maxSkew визначає максимально допустиму різницю між кількістю відповідних Podʼів у цільовій топології та глобальним мінімумом (мінімальною кількістю відповідних подів у домені, що відповідає критеріям, або нулем, якщо кількість таких доменів менша за MinDomains). Наприклад, якщо у вас є 3 зони з 2, 2 та 1 відповідних Podʼів, а maxSkew встановлено на 1, тоді глобальний мінімум дорівнює 1.
    • якщо ви виберете whenUnsatisfiable: ScheduleAnyway, планувальник надає вищий пріоритет топологіям, які допомагають зменшити перекіс.
  • minDomains вказує мінімальну кількість прийнятних областей. Це поле є необовʼязковим. Домен — це певний екземпляр топології. Прийнятний домен — це домен, чиї вузли відповідають селектору вузлів.

    Примітка:

    До Kubernetes v1.30 поле minDomains було доступним, якщо функціональну можливість MinDomainsInPodTopologySpread було увімкнено (типово увімкнено починаючи з v1.28). В старіших кластерах Kubernetes воно може бути явно відключеним або поле може бути недоступним.
    • Значення minDomains повинно бути більше ніж 0, коли вказано. Ви можете вказати minDomains лише разом з whenUnsatisfiable: DoNotSchedule.
    • Коли кількість прийнятних доменів з відповідними ключами топології менше minDomains, обмеження топології розміщення Podʼів розглядає глобальний мінімум як 0, а потім виконується розрахунок skew. Глобальний мінімум — це мінімальна кількість відповідних Podʼів у прийнятному домені, або нуль, якщо кількість прийнятних доменів менше, ніж minDomains.
    • Коли кількість прийнятних доменів з відповідними ключами топології дорівнює або більше minDomains, це значення не впливає на планування.
    • Якщо ви не вказуєте minDomains, обмеження поводиться так, ніби minDomains дорівнює 1.
  • topologyKey — ключ міток вузла. Вузли, які мають мітку з цим ключем і ідентичними значеннями, вважаються присутніми в тій самій топології. Кожен екземпляр топології (іншими словами, пара <ключ, значення>) називається доменом. Планувальник спробує помістити вирівняну кількість Podʼів в кожен домен. Також ми визначаємо прийнятний домен як домен, вузли якої відповідають вимогам nodeAffinityPolicy та nodeTaintsPolicy.

  • whenUnsatisfiable вказує, як розвʼязувати проблему з Podʼом, якщо він не відповідає обмеженню поширення:

    • DoNotSchedule (типово) вказує планувальнику не планувати його.
    • ScheduleAnyway вказує планувальнику все одно його планувати, проте з пріоритетом вибору вузлів, що мінімізують розрив.
  • labelSelector використовується для знаходження відповідних Podʼів. Podʼи, які відповідають цьому селектору міток, враховуються для визначення кількості Podʼів у відповідному домені топології. Дивіться селектори міток для отримання додаткових відомостей.

  • matchLabelKeys — це список ключів міток Podʼа для вибору Podʼів, відносно яких буде розраховано поширення. При створенні Podʼа kube-apiserver використовує ці ключі для пошуку значень з вхідних міток Podʼа, і ці мітки ключ-значення будуть обʼєднані з будь-яким наявним labelSelector. Існування однакового ключа заборонене як у matchLabelKeys, так і в labelSelector. matchLabelKeys не може бути встановлено, коли labelSelector не встановлено. Ключі, яких не існує в мітках Podʼа, будуть проігноровані. Порожній або нульовий список означає, що збіг буде відповідати лише labelSelector.

    Увага:

    Не рекомендується використовувати matchLabelKeys з мітками, які можуть бути оновлені безпосередньо в Podʼах. Навіть якщо ви редагуєте мітку Podʼа, яка вказана в matchLabelKeys безпосередньо, (тобто, ви редагуєте Pod, а не Deployment), kube-apiserver не відображає оновлення мітки на обʼєднаний labelSelector.

    З matchLabelKeys вам не потрібно оновлювати pod.spec між різними версіями. Контролер/оператор просто повинен встановити різні значення для того самого ключа мітки для різних версій. Наприклад, якщо ви налаштовуєте Deployment, ви можете використовувати мітку за ключем pod-template-hash, яка додається автоматично контролером Deployment, для розрізнення різних версій в одному Deployment.

        topologySpreadConstraints:
            - maxSkew: 1
              topologyKey: kubernetes.io/hostname
              whenUnsatisfiable: DoNotSchedule
              labelSelector:
                matchLabels:
                  app: foo
              matchLabelKeys:
                - pod-template-hash
    

    Примітка:

    Поле matchLabelKeys є полем на рівні бета-версії та включено стандартно у 1.27. Ви можете відключити його, вимкнувши функціональну можливість MatchLabelKeysInPodTopologySpread.

    До v1.34, matchLabelKeys оброблявся неявно. З v1.34, мітки ключ-значення, що відповідають matchLabelKeys, явно обʼєднуються з labelSelector. Ви можете відключити це і повернутися до попередньої поведінки, вимкнувши функціональну можливість MatchLabelKeysInPodTopologySpreadSelectorMerge kube-apiserver.

  • nodeAffinityPolicy вказує, як ми будемо обробляти nodeAffinity/nodeSelector Podʼа, коли розраховуємо розрив поширення топології Podʼів. Опції:

    • Honor: до розрахунків включаються лише вузли, які відповідають nodeAffinity/nodeSelector.
    • Ignore: nodeAffinity/nodeSelector ігноруються. Включаються всі вузли.

    Якщо це значення є null, поведінка еквівалентна політиці Honor.

    Примітка:

    Поле nodeAffinityPolicy було полем на рівні бета-версії з v1.26 та загальнодоступним з v 1.33. Воно є стандартно увімкеними і ви можете відключити його, вимкнувши функціональну можливість NodeInclusionPolicyInPodTopologySpread.
  • nodeTaintsPolicy вказує, як ми будемо обробляти заплямованість вузлів при розрахунку розриву поширення топології Podʼів. Опції:

    • Honor: включаються вузли без заплямованості, разом з заплямованими вузлами, для яких вхідний Pod має толерантність.
    • Ignore: заплямованість вузла ігноруються. Включаються всі вузли.

    Якщо це значення є null, поведінка еквівалентна політиці Ignore.

    Примітка:

    Поле nodeTaintsPolicy було полем на рівні бета-версії з v1.26 та загальнодоступним з v 1.33. Воно є стандартно увімкеними і ви можете відключити його, вимкнувши функціональну можливість NodeInclusionPolicyInPodTopologySpread.

Коли Pod визначає більше одного обмеження topologySpreadConstraint, вони комбінуються за допомогою операції AND: kube-scheduler шукає вузол для вхідного Podʼа, який задовольняє всі налаштовані обмеження.

Мітки вузлів

Обмеження топології розміщення ґрунтуються на мітках вузлів для ідентифікації доменів топології, в яких знаходиться кожен вузол. Наприклад, вузол може мати такі мітки:

  region: us-east-1
  zone: us-east-1a

Примітка:

У цьому прикладі не використовуються відомі ключі міток topology.kubernetes.io/zone та topology.kubernetes.io/region. Однак, рекомендується використовувати саме ці зареєстровані ключі міток, а не приватні (непідтверджені) ключі міток region та zone, які використовуються тут.

Не можна надійно припускати про наявність значення приватного ключа мітки в різних контекстах.

Припустимо, у вас є кластер з 4 вузлами з наступними мітками:

NAME    STATUS   ROLES    AGE     VERSION   LABELS
node1   Ready    <none>   4m26s   v1.16.0   node=node1,zone=zoneA
node2   Ready    <none>   3m58s   v1.16.0   node=node2,zone=zoneA
node3   Ready    <none>   3m17s   v1.16.0   node=node3,zone=zoneB
node4   Ready    <none>   2m43s   v1.16.0   node=node4,zone=zoneB

Тоді кластер логічно виглядає так:

graph TB subgraph "zoneB" n3(Node3) n4(Node4) end subgraph "zoneA" n1(Node1) n2(Node2) end classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; class n1,n2,n3,n4 k8s; class zoneA,zoneB cluster;

Узгодженість

Вам слід встановити однакові обмеження топології розміщення Podʼів для всіх Podʼів у групі.

Зазвичай, якщо ви використовуєте контролер робочого навантаження, такий як Deployment, шаблон Podʼа забезпечує це за вас. Якщо ви комбінуєте різні обмеження топології розміщення, то Kubernetes дотримується визначення API поля; однак, це більш ймовірно призведе до плутанини в поведінці, а усунення несправностей буде менш прямолінійним.

Вам потрібен механізм для забезпечення того, що всі вузли в домені топології (наприклад, регіон хмарного постачальника) мають однакові мітки. Щоб уникнути необхідності ручного маркування вузлів, більшість кластерів автоматично заповнюють відомі мітки, такі як kubernetes.io/hostname. Перевірте, чи підтримує ваш кластер це.

Приклад обмеження топології розміщення

Приклад: одне обмеження топології розміщення

Припустимо, у вас є кластер із чотирма вузлами, де 3 Podʼа з міткою foo: bar знаходяться на вузлах node1, node2 та node3 відповідно:

graph BT subgraph "zoneB" p3(Pod) --> n3(Node3) n4(Node4) end subgraph "zoneA" p1(Pod) --> n1(Node1) p2(Pod) --> n2(Node2) end classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; class n1,n2,n3,n4,p1,p2,p3 k8s; class zoneA,zoneB cluster;

Якщо ви хочете, щоб новий Pod був рівномірно розподілений поміж наявними Podʼами у зонах, ви можете використовувати маніфест Podʼів, схожий на такий:

kind: Pod
apiVersion: v1
metadata:
  name: mypod
  labels:
    foo: bar
spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        foo: bar
  containers:
  - name: pause
    image: registry.k8s.io/pause:3.1

У цьому маніфесті topologyKey: zone означає, що рівномірний розподіл буде застосовуватися лише до вузлів, які мають мітку zone: <будь-яке значення> (вузли, які не мають мітки zone, будуть пропущені). Поле whenUnsatisfiable: DoNotSchedule повідомляє планувальнику, що потрібно залишити новий Pod у стані очікування, якщо планувальник не може знайти спосіб задовольнити обмеження.

Якщо планувальник розмістить цей новий Pod у зоні A, розподіл Podʼів стане [3, 1]. Це означає, що фактичне відхилення складає 2 (розраховане як 3 - 1), що порушує maxSkew: 1. Щоб задовольнити умови обмеження та контекст для цього прикладу, новий Pod може бути розміщений лише на вузлі в зоні B.

graph BT subgraph "zoneB" p3(Pod) --> n3(Node3) p4(mypod) --> n4(Node4) end subgraph "zoneA" p1(Pod) --> n1(Node1) p2(Pod) --> n2(Node2) end classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; class n1,n2,n3,n4,p1,p2,p3 k8s; class p4 plain; class zoneA,zoneB cluster;

або

graph BT subgraph "zoneB" p3(Pod) --> n3(Node3) p4(mypod) --> n3 n4(Node4) end subgraph "zoneA" p1(Pod) --> n1(Node1) p2(Pod) --> n2(Node2) end classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; class n1,n2,n3,n4,p1,p2,p3 k8s; class p4 plain; class zoneA,zoneB cluster;

Ви можете змінити специфікацію Podʼа, щоб вона відповідала різним вимогам:

  • Змініть maxSkew на більше значення, наприклад 2, щоб новий Pod також можна було розмістити в зоні A.
  • Змініть topologyKey на node, щоб рівномірно розподілити Podʼи по вузлах, а не зонам. У вищезазначеному прикладі, якщо maxSkew залишиться 1, новий Pod може бути розміщений лише на вузлі node4.
  • Змініть whenUnsatisfiable: DoNotSchedule на whenUnsatisfiable: ScheduleAnyway, щоб гарантувати, що новий Pod завжди можна розмістити (якщо інші API планування задовольняються). Однак перевага надається розміщенню в області топології, яка має менше відповідних Podʼів. (Памʼятайте, що ця перевага спільно нормалізується з іншими внутрішніми пріоритетами планування, такими як коефіцієнт використання ресурсів).

Приклад: декілька обмежень топології розміщення

Цей приклад будується на попередньому. Припустимо, у вашому кластері з 4 вузлами є 3 Podʼа, позначених як foo: bar, що знаходяться на вузлі node1, node2 і node3 відповідно:

graph BT subgraph "zoneB" p3(Pod) --> n3(Node3) n4(Node4) end subgraph "zoneA" p1(Pod) --> n1(Node1) p2(Pod) --> n2(Node2) end classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; class n1,n2,n3,n4,p1,p2,p3 k8s; class p4 plain; class zoneA,zoneB cluster;

Ви можете поєднати два обмеження поширення топології, щоб контролювати розподіл Podʼів як за вузлами, так і за зонами:

kind: Pod
apiVersion: v1
metadata:
  name: mypod
  labels:
    foo: bar
spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        foo: bar
  - maxSkew: 1
    topologyKey: node
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        foo: bar
  containers:
  - name: pause
    image: registry.k8s.io/pause:3.1

У цьому випадку для збігу з першим обмеженням новий Pod може бути розміщений лише на вузлах у зоні B; тоді як для відповідності другому обмеженню новий Pod може бути розміщений лише на вузлі node4. Планувальник розглядає лише варіанти, які задовольняють всі визначені обмеження, тому єдине допустиме розташування — це на вузлі node4.

Приклад: конфліктуючі обмеження топології розміщення

Кілька обмежень може призвести до конфліктів. Припустимо, у вас є кластер з 3 вузлами у 2 зонах:

graph BT subgraph "zoneB" p4(Pod) --> n3(Node3) p5(Pod) --> n3 end subgraph "zoneA" p1(Pod) --> n1(Node1) p2(Pod) --> n1 p3(Pod) --> n2(Node2) end classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; class n1,n2,n3,n4,p1,p2,p3,p4,p5 k8s; class zoneA,zoneB cluster;

Якщо ви застосуєте two-constraints.yaml (файл маніфесту з попереднього прикладу) до цього кластера, ви побачите, що Pod mypod залишається у стані Pending. Це трапляється тому, що для задоволення першого обмеження Pod mypod може бути розміщений лише у зоні B; тоді як для відповідності другому обмеженню Pod mypod може бути розміщений лише на вузлі node2. Перетин двох обмежень повертає порожній набір, і планувальник не може розмістити Pod.

Щоб подолати цю ситуацію, ви можете або збільшити значення maxSkew, або змінити одне з обмежень, щоб використовувати whenUnsatisfiable: ScheduleAnyway. Залежно від обставин, ви також можете вирішити видалити наявний Pod вручну — наприклад, якщо ви розвʼязуєте проблему, чому розгортання виправлення помилки не виконується.

Взаємодія з селектором вузла та спорідненістю вузла

Планувальник пропустить вузли, що не відповідають, з обчислень нерівності, якщо у вхідного Podʼа визначено spec.nodeSelector або spec.affinity.nodeAffinity.

Приклад: обмеження топології розміщення зі спорідненістю вузла

Припустимо, у вас є 5-вузловий кластер, розташований у зонах від A до C:

graph BT subgraph "zoneB" p3(Pod) --> n3(Node3) n4(Node4) end subgraph "zoneA" p1(Pod) --> n1(Node1) p2(Pod) --> n2(Node2) end classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; class n1,n2,n3,n4,p1,p2,p3 k8s; class p4 plain; class zoneA,zoneB cluster;
graph BT subgraph "zoneC" n5(Node5) end classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; class n5 k8s; class zoneC cluster;

і ви знаєте, що зону C потрібно виключити. У цьому випадку ви можете скласти маніфест, як наведено нижче, щоб Pod mypod був розміщений у зоні B, а не у зоні C. Так само Kubernetes також враховує spec.nodeSelector.

kind: Pod
apiVersion: v1
metadata:
  name: mypod
  labels:
    foo: bar
spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        foo: bar
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: zone
            operator: NotIn
            values:
            - zoneC
  containers:
  - name: pause
    image: registry.k8s.io/pause:3.1

Неявні домовленості

Тут є кілька неявних домовленостей, на які варто звернути увагу:

  • Відповідними кандидатами можуть бути лише ті Podʼи, що мають той самий простір імен, що й новий Pod.

  • Планувальник розглядає лише ті вузли, у яких одночасно присутні всі topologySpreadConstraints[*].topologyKey. Вузли, у яких відсутній будь-який з цих topologyKey, обминаються. Це означає, що:

    1. будь-які Podʼи, що розташовані на цих обхідних вузлах, не впливають на обчислення maxSkew — в прикладі вище, припустимо, що вузол node1 не має мітки "zone", тоді 2 Podʼа будуть проігноровані, тому новий Pod буде заплановано в зону A.
    2. новий Pod не має шансів бути запланованим на такі вузли — у вищенаведеному прикладі, припустимо, що вузол node5 має невірно введену мітку zone-typo: zoneC (і не має жодної встановленої мітки zone). Після приєднання вузла node5 до кластера, він буде обходитися, і Podʼи для цього робочого навантаження не будуть плануватися туди.
  • Будьте уважні, якщо topologySpreadConstraints[*].labelSelector нового Podʼа не відповідає його власним міткам. У вищенаведеному прикладі, якщо ви видалите мітки нового Podʼа, він все ще може бути розміщений на вузлах у зоні B, оскільки обмеження все ще виконуються. Проте, після цього розміщення ступінь незбалансованості кластера залишається без змін — зона A все ще має 2 Podʼи з мітками foo: bar, а зона B має 1 Pod з міткою foo: bar. Якщо це не те, що ви очікуєте, оновіть topologySpreadConstraints[*].labelSelector робочого навантаження, щоб відповідати міткам в шаблоні Podʼа.

Типові обмеження на рівні кластера

Можливо встановити типові обмеження топології розміщення для кластера. Типово обмеження топології застосовуються до Podʼа лише в тому випадку, якщо:

  • Він не визначає жодних обмежень у своєму .spec.topologySpreadConstraints.
  • Він належить до Service, ReplicaSet, StatefulSet або ReplicationController.

Типові обмеження можна встановити як частину аргументів втулка PodTopologySpread в профілі планувальника. Обмеження вказуються з тими ж API вище, за винятком того, що labelSelector повинен бути пустим. Селектори обчислюються з Service, ReplicaSet, StatefulSet або ReplicationControllers, до яких належить Pod.

Приклад конфігурації може виглядати наступним чином:

apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration

profiles:
  - schedulerName: default-scheduler
    pluginConfig:
      - name: PodTopologySpread
        args:
          defaultConstraints:
            - maxSkew: 1
              topologyKey: topology.kubernetes.io/zone
              whenUnsatisfiable: ScheduleAnyway
          defaultingType: List

Вбудовані типові обмеження

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.24 [stable]

Якщо ви не налаштовуєте жодних типових обмежень для топології розміщення Podʼа на рівні кластера, то kube-scheduler діє так, ніби ви вказали наступні обмеження:

defaultConstraints:
  - maxSkew: 3
    topologyKey: "kubernetes.io/hostname"
    whenUnsatisfiable: ScheduleAnyway
  - maxSkew: 5
    topologyKey: "topology.kubernetes.io/zone"
    whenUnsatisfiable: ScheduleAnyway

Також, типово відключений застарілий втулок SelectorSpread, який забезпечує еквівалентну поведінку.

Примітка:

Втулок PodTopologySpread не оцінює вузли, які не мають вказаних ключів топології в обмеженнях топології. Це може призвести до іншої типової поведінки порівняно з застарілим втулком SelectorSpread, коли використовуються типові обмеження топології.

Якщо ви не очікуєте, що ваші вузли матимуть обидві мітки kubernetes.io/hostname та topology.kubernetes.io/zone встановлені, визначте свої власні обмеження замість використання стандартних значень Kubernetes.

Якщо ви не хочете використовувати типові обмеження топології розміщення Podʼа для вашого кластера, ви можете відключити ці типові значення, встановивши defaultingType у List і залишивши порожніми defaultConstraints у конфігурації втулка PodTopologySpread:

apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration

profiles:
  - schedulerName: default-scheduler
    pluginConfig:
      - name: PodTopologySpread
        args:
          defaultConstraints: []
          defaultingType: List

Порівняння з podAffinity та podAntiAffinity

У Kubernetes, між-Podʼова (анти)спорідненість контролює те, як Podʼи розміщуються відносно один одного — більш щільно або більш розрізнено.

podAffinity
притягує Podʼи; ви можете намагатися упакувати будь-яку кількість Podʼів в кваліфікуючі топологічні домени.
podAntiAffinity
відштовхує Podʼи. Якщо ви встановите це у режим requiredDuringSchedulingIgnoredDuringExecution, тоді тільки один Pod може бути запланований в один топологічний домен; якщо ви виберете preferredDuringSchedulingIgnoredDuringExecution, то ви втратите можливість забезпечити дотримання цього обмеження.

Для більш точного контролю ви можете вказати обмеження топології розміщення для розподілу Podʼів по різним топологічним доменам — для досягнення як високої доступності, так і економії коштів. Це також може допомогти в роботі з оновленнями без відмов та плавному масштабуванні реплік.

Для отримання більш детальної інформації, див. розділ Motivation пропозиції щодо покращення про обмеження топології розміщення Podʼів.

Відомі обмеження

  • Немає гарантії, що обмеження залишаться задоволеними при видаленні Podʼів. Наприклад, зменшення масштабування Deployment може призвести до нерівномірного розподілу Podʼів.

    Ви можете використовувати інструменти, такі як Descheduler, для перебалансування розподілу Podʼів.

  • Podʼи, що відповідають заплямованим вузлам, враховуються. Див. Issue 80921.

  • Планувальник не має попереднього знання всіх зон або інших топологічних доменів, які має кластер. Вони визначаються на основі наявних вузлів у кластері. Це може призвести до проблем у автоматизованих кластерах, коли вузол (або група вузлів) масштабується до нуля вузлів, і ви очікуєте масштабування кластера, оскільки в цьому випадку ці топологічні домени не будуть враховуватися, поки в них є хоча б один вузол.

    Ви можете обійти це, використовуючи інструменти автоматичного масштабування Вузлів, які враховують обмеження розподілу топології Podʼів та також знають загальний набір топологічних доменів.

Що далі

  • У статті блогу Introducing PodTopologySpread докладно пояснюється maxSkew, а також розглядаються деякі приклади використання.
  • Прочитайте розділ scheduling з довідки API для Pod.
Востаннє змінено April 16, 2026 at 5:18 PM PST: [uk] Ukrainian translation (all-in-one) (d256f81780)