Настройте политику планировщика Kubernetes в соответствии с желаемыми SLO.

Kubernetes - это механизм оркестрации контейнеров, который планирует и управляет контейнерными приложениями на наборе рабочих узлов. Kubernetes API используется для указания контейнера контейнера Kubernetes и его требований к расписанию. Планировщик Kubernetes отвечает за принятие решений о планировании модулей на основе модулей, которые были указаны для запуска в кластере. Планировщик учитывает требования модуля к ресурсам, требования QoS, соответствие, спецификации анти-сродства и т. Д., Чтобы принимать эффективные решения по планированию .

Несбалансированный кластер

В многозонном кластере Kubernetes планировщик изо всех сил пытается сбалансировать поды в контроллере репликации или службе по зонам, когда информация о зоне включена в метку узла, чтобы уменьшить влияние сбоев зоны.

Следующее цитируется из документации Kubernetes.

Планировщик автоматически распределяет модули в контроллере репликации или службе по узлам в однозонном кластере (чтобы уменьшить влияние сбоев). В кластерах с несколькими зонами такое распределение распространяется по зонам (чтобы уменьшить влияние отказов зон).

Однако по моему опыту, хотя Kubernetes изо всех сил пытается сбалансировать поды по зонам, он недостаточно старается. Помимо просмотра информации о зоне, прикрепленной к метке узла, планировщик по умолчанию также учитывает узлы с наименее запрошенными ресурсами, сродство / анти-сродство в спецификациях модуля и т. Д. Таким образом, вы можете оказаться в ситуации, когда поды размещены неравномерно по зонам, что поставит под угрозу ваши цели уровня обслуживания во время сбоев зон.

Рассмотрим очень простой протестированный пример многозонного кластера Kubernetes с 3 рабочими узлами, по одному в каждой зоне и размещающими 3 сервиса A, B и C. Давайте рассмотрим, что служба B и C работает с 2 модулями каждая, а служба Cpods должна работать вместе со службой Bpods с использованием привязки модулей. На следующей диаграмме показано размещение модулей всех трех служб. Предположим, служба Apods запросила 10% ресурсов узла, а служба B и C запросила 30% ресурсов.

Теперь, если вы развертываете службу D с 6 модулями, каждый из которых требует ресурсов в размере 10% от ресурсов узла. Поскольку ресурсы узла в Zone3 запрашиваются меньше всего (10%), тогда как его 70% в Zone2 & Zone3, он размещает 3 модуля обслуживания D в Zone3, 2 модуля в Zone2 и 1 модуль в Zone1. Причина этого в том, что хотя планировщик пытается сбалансировать модули по зонам, он также пытается сбалансировать запрошенные ресурсы (ЦП, память) между узлами, что делает распределение службы Dpods неравномерным по зонам, как показано на изображении ниже.

Теперь, если бы вы инициировали непрерывное обновление для своей службы D, поскольку непрерывное обновление пытается вызвать новые модули перед удалением старых, вы получите большинство модулей службы 4pods в zone3 и по 1podкаждой в оставшихся зонах. Исходя из моего опыта, существует множество других сценариев, в которых вы можете в конечном итоге не иметь модулей служб в определенной зоне или иметь все модули из службы, работающие в одной зоне.

А что, если мои реплики службы распределены неравномерно?

Kubernetes достаточно умен, чтобы запускать новые поды, если отдельный узел или зона выйдет из строя. Что ж, это правда, но Kubernetes может потребоваться некоторое время, чтобы оправиться от такого сбоя и предоставить дополнительную емкость в доступных зонах, если у них еще нет достаточной емкости для перемещения всей вашей рабочей нагрузки из отказавшей зоны в доступные зоны. Если модули в вашем сервисе не сбалансированы равномерно, отказ зоны может вывести из строя большинство или все ваши сервисные модули, что приведет к нарушениям SLO задержки и доступности, которые может предложить ваш сервис. Уровень нарушения может относиться к следующим категориям:

  1. Полная потеря обслуживания, если все реплики службы находятся в одной зоне.
  2. Существенное ухудшение качества обслуживания, если затронуто большинство ваших модулей, но может привести к полному отказу обслуживания, если остальные модули не смогут справиться с нагрузкой.
  3. Существенная деградация услуг, влияющая на клиентов из-за несоблюдения требований по задержке обслуживания и пропускной способности
  4. Незначительное ухудшение качества обслуживания с незначительным влиянием или без влияния на задержку и пропускную способность.

Как правило, вы должны выбрать уровень доступности, которого должен придерживаться ваш компонент, на основе обязательств по уровню обслуживания перед вашими клиентами и соответствующим образом настроить компонент, то есть количество реплик, размещение данных и уровень избыточного выделения ресурсов (количество реплик) для вашего сервиса. Если ваш сервис должен быть в 4-й категории выше, настроить его для обеспечения высокой доступности станет проще, если ваши сервисные модули распределены равномерно.

Как я могу убедиться, что мои пакеты распределены равномерно?

Давайте сначала посмотрим, какие шаги выполняет планировщик, чтобы принять решение о планировании.

Фильтрация узлов: для каждого модуля в состоянии ожидания Планировщик применяет набор функций предиката, чтобы отфильтровать узлы, на которых модуль не может быть запланирован. Функции Predicate фильтруют узлы на основе ограничений или требований, указанных в спецификациях модуля, таких как taints, affinity, anti-affinity и узлы, у которых недостаточно ресурсов, запрошенных модулем. Он также отфильтровывает узлы, которые уже испытывают нехватку ресурсов (память или диск).

Приоритизация узлов: после того, как планировщик отфильтровал узлы, на которых нельзя запланировать пакет, он вычисляет оценку для каждого оставшегося узла с помощью набора функций приоритета. Функции Priority используются для поиска узла, который лучше всего подходит для планирования модуля из всех возможных узлов, и каждая функция priority предназначена для определенных критериев, таких как распределение модулей по узлам, сбалансировать запрошенные ресурсы на узлах, в то же время принимая во внимание предпочтительный режим пода и узла с требованием сродства / анти-сродства. См. Более подробную информацию в сообщении блога Расширенное планирование в Kubernetes.

Примеры оценок для возможных узлов:

Zone1 Node2 score - 15
Zone2 Node1 score - 12
Zone3 Node1 score - 16
Zone3 Node2 score - 18

Планирование модуля: на последнем этапе планировщик выбирает узел с наивысшим баллом для планирования модуля. Если несколько узлов имеют одинаковый наивысший балл, планировщик случайным образом выбирает один из них.

Node with highest priority score is selected for scheduling the pod:- Zone3 Node2 

Набор предикатов и функций приоритета, которые будут использоваться планировщиком, и возрастной коэффициент, связанный с функциями приоритета, можно настроить с помощью политики планировщика.

Ниже приведены функции приоритета по умолчанию, которые планировщик применяет для выбора наиболее подходящего узла из всех возможных узлов для планирования.

  • Распределение селектора: расставьте приоритеты на основе распределения реплик / пакетов службы
  • Наименее запрашиваемый: расставьте приоритеты на основе наименее запрашиваемых ресурсов на узле
  • Баланс ресурса: установите приоритет для сбалансированного использования ресурсов
  • Сходство между модулями: расставьте приоритеты на основе спецификации модуля (привязка модуля к типуpreferredDuringSchedulingIgnoredDuringExecution)
  • Устойчивость к заражению: приоритет основан на наименьшем количестве недопустимых загрязнений на узле
  • Родство узла: приоритет определяется спецификацией модуля (родство узла с типомpreferredDuringSchedulingIgnoredDuringExecution)
  • Узел предпочитает избегать приоритета модулей: игнорировать модули, принадлежащие контроллеру, отличному от контроллера репликации

Каждая приоритетная функция оценивается от 0 до 10, где 10 - наиболее предпочтительный, а 0 - наименее предпочтительный балл. Вес связан со всеми приоритетными функциями, и окончательная оценка для каждого узла рассчитывается следующим образом.

Node score :- (weightage * priorityFunction 1) + (weightage * priorityFunction 2) …

Политика планировщика по умолчанию дает равный вес 1 всем приоритетным функциям и увеличивает вес для функции «SelectorSpreadPriority», которая пытается равномерно распределить модули по узлам и зонам. У вас больше шансов добиться равномерного распределения ваших модулей по зонам, если во всех зонах достаточно ресурсов для запуска ваших модулей. Вы можете переопределить политику планировщика по умолчанию через файл политики или через configmaps.

Команда планировщика, используемая, если вы переопределяете политику планирования по умолчанию через файл политики

--use-legacy-policy-config=false
--policy-config-file=<file path>

Команда планировщика, используемая, если вы переопределяете конфигурационные карты политики планирования по умолчанию

--use-legacy-policy-config=false
--policy-configmap=scheduler-policy
--policy-configmap-namespace=kube-system

Вот пример политики, в которой вес для «SelectorSpreadPriority» был увеличен до 5 и оставлен на значениях по умолчанию для всех остальных. После увеличения веса планировщик будет уделять больше внимания распределению модуля по узлам и зонам.

"priorities": [
    {
      "name": "SelectorSpreadPriority",
      "weight": 5
    },
    {
      "name": "InterPodAffinityPriority",
      "weight": 1
    },
    {
      "name": "LeastRequestedPriority",
      "weight": 1
    },
    {
      "name": "BalancedResourceAllocation",
      "weight": 1
    },
        {
      "name": "NodePreferAvoidPodsPriority",
      "weight": 1
    },
        {
      "name": "TaintTolerationPriority",
      "weight": 1
   },
   {
      "name": "NodeAffinityPriority",
      "weight": 1
    }
  ]

После увеличения веса «SelectorSpreadPriority» планировщик будет уделять больше внимания равномерному распределению модулей в вашем сервисе по узлам и между зонами.

Вы также можете равномерно распределить поды из определенной службы по группе узлов на основе значений метки для конкретной метки, прикрепленной к группе узлов. Вот пример.

        {
            "argument": {
                "serviceAntiAffinity": {
                    "label": "<label_name>"
                }
            },
            "name": "<priority-Name>",
            "weight": <weight-age>
        },

Он дает одинаковую оценку всем узлам, которые имеют одинаковое значение для указанной метки. Он дает более высокий балл узлам в группе с наименьшей концентрацией стручков.

Вы также можете запустить вторичный планировщик в своем кластере с другим набором конфигураций политик и вызвать этот планировщик в YAML развертывания вашей службы для удовлетворения различных потребностей, см. Https://kubernetes.io/docs/tasks/administer-cluster/configure -множественные планировщики /

Надеюсь, этот пост помог вам понять, как работает Kubernetes Scheduler. Конфигурация планировщика по умолчанию может работать для вашего варианта использования в зависимости от желаемых SLO. Если у вас более требовательный SLO, вы можете переопределить политику планировщика в соответствии со своими требованиями.