В статье — варианты использования расширенного планирования подов в Kubernetes, а также передовые методы его применения на практике. Информация пригодится разработчикам приложений и администраторам K8s, чтобы реализовать расширенные шаблоны развёртывания приложений, в которых есть локальность данных, совместное размещение модулей, высокая доступность и эффективное использование ресурсов кластеров K8s. В Kubernetes задача планирования подов для определённых узлов в кластере выполняется с помощью компонента kube-scheduler. По умолчанию он фильтрует узлы на основе запросов ресурсов и ограничений каждого контейнера в созданном модуле. Затем возможные узлы оцениваются для поиска лучшей возможности для размещения пода. Во многих сценариях планирование подов на основе ограничений ресурсов — лучший из возможных вариантов. Однако иногда администраторы Kubernetes планируют поды для опредёленных узлов в соответствии с другими вариантами ограничений. В таких случаях стоит рассматривать возможность расширенного планирования. В производственном применении Kubernetes всегда необходима настройка распределения подов по узлам. Перечислим некоторые распространённые сценарии, при которых расширенное планирование — оптимальный вариант. Запуск подов на узлах с выделенным оборудованием. У некоторых приложений Kubernetes особые требования к оборудованию. Поды, выполняющие задания по машинному обучению, требуют высокопроизводительных графических процессоров вместо ЦП, в то время как модули Elasticsearch более эффективны на твердотельных накопителях, чем на жёстких дисках. Лучшая практика для любого управления кластером K8s с учётом ресурсов — это назначать поды узлам с правильным оборудованием. Совместное размещение подов и кодовая зависимость. В настройке микросервисов или тесно связанном стеке приложений определённые поды должны быть размещены на одном компьютере, чтобы повысить производительность, избежать проблем с задержкой в ​​сети и сбоев подключения. Рекомендуется запускать веб-сервер на том же компьютере, что и службу кэширования в памяти или базу данных. Локальность данных. Требования к локальности данных для приложений, интенсивно использующих данные, аналогичны предыдущему варианту использования. Для более быстрого чтения и лучшей пропускной способности записи этим приложениям требуется развёртывание баз данных на одном компьютере с клиентским приложением. Kubernetes располагает множеством ресурсов и стратегий API. Рассмотрим некоторые из них: концепции nodeSelector, сродства узлов и сродства между модулями — и покажем наглядно, как реализовать их в вашем кластере K8s. В более ранних версиях K8s пользователи могли планировать поды вручную, используя поле nodeSelector в файле PodSpec. NodeSelector — метод планирования от пода к узлу на основе меток, при котором пользователи назначают определённые метки узлам и следят за тем, чтобы поле nodeSelector соответствовало этим меткам. Допустим, что одна из меток узла — «storage = ssd», указывающая тип хранилища на узле. Для планирования подов на узле с этой меткой указываем поле nodeSelector с ней в манифесте для пода. Селекторы узлов — наиболее доступный метод расширенного планирования модулей. Однако они неэффективны в случаях, когда при планировании подов приходится учитывать дополнительные правила и условия. Функция привязки узлов более эффективна по сравнению с ручным размещением подов. Она включает в себя функциональный язык сродства с использованием логических операторов и ограничений, обеспечивающий точный контроль над размещением подов. Язык поддерживает мягкие и жёсткие правила планирования, позволяющие контролировать строгость ограничений привязки узлов в зависимости от требований пользователя. Рассмотрим привязку узлов для размещения подов на узлах в определённых зонах доступности. Жёсткие правила сродства указываются в поле “required during scheduling ignored during execution”(«Требуется во время планирования, игнорируется во время выполнения») раздела nodeAffinity в манифесте для пода. В примере планировщику было дано задание разместить модуль только на узлах с меткой, имеющей ключ kubernetes.io/cp-az-name и значения cp-1a или cp-1b. Для этого использован логический оператор In, фильтрующий массив существующих значений меток. Другие возможные в подобных случаях операторы: NotIn, Exists, DoesNotExist, Gt и Lt. Мягкое правило указывается в поле спецификации «Предпочитается во время планирования, игнорируется во время выполнения» (“preferred during scheduling ignored during execution”). В примере среди узлов, отвечающих жёстким критериям, используются узлы с меткой, имеющей ключ с именем custom-key и значением custom-value. Если таких узлов нет, возможно добавление подов другим кандидатам, если они соответствуют жёстким критериям. Эффективная практика — создание правил привязки узлов таким образом, чтобы они включали как жёсткие, так и мягкие правила. Следование этому подходу максимальных усилий (использовать по возможности ту или иную опцию, но не отклонять планирование, если опция недоступна) помогает гибко и предсказуемо планировать развёртывание. Сродство в Kubernetes — это функция, служащая для планирования подов на основе их отношения к другим подам. Сродство позволяет использовать различные интересные варианты, такие как совместное размещение подов в рамках созависимой службы (служб) или реализация локальности данных, при которой поды данных работают на том же компьютере, что и основной под службы. Сродство между пакетами определяется аналогично сродству узлов. В данном случае мы будем использовать поле podAffinity внутри спецификации. Как и сродство узла, сродство пода определяется с помощью выражений соответствия и логических операторов. Но в этом случае они применяются к селектору меток подов, работающих на определённом узле. Если указанное выражение совпадает с меткой целевого пода, новый под размещается вместе с целевым на том же компьютере. Иногда предпочтительнее использовать метод чёрного списка для планирования пакетов. Такой подход препятствует планированию подов на определённых узлах при невыполнении опредёленных условий. Такая концепция называется анти-сродством Kubernetes. В основном анти-сродство от пода к узлу применяется для выделенных узлов. Для управления использованием ресурсов в кластере администраторы K8s могут выделить определённые узлы для опредёленных типов подов и приложений. Есть и другие интересные варианты использования анти-сродства между подами. Во-первых, это предотвращение единой точки отказа. Это достигается путём распределения подов в рамках одного и того же сервиса по разным машинам, что требует предотвращения совмещения подов с другими подами того же типа. Во-вторых, это предотвращение конкуренции между службами за ресурсы. Для повышения производительности некоторых сервисов их не стоит размещать вместе с другими сервисами, которые потребляют много ресурсов. Анти-сродство от пода к узлу в Kubernetes может быть достигнуто с помощью порчи и толерантности.  Ошибки, условия и допуски помогают пользователю контролировать планирование подов для определённых узлов без изменения уже существующих. По умолчанию все поды, не имеющие допусков к порче узла, будут отклонены или исключены из него. Такое поведение обеспечивает гибкость шаблонов развёртывания кластеров и приложений. Не нужно изменять спецификацию пода, если вы не хотите, чтобы он работал на определённых узлах. Реализовать порчи и терпимости довольно просто. Для начала — добавить к узлу искажение, для которого необходимо применить нестандартное поведение при планировании: Формат порчи выглядит так: <taintKey> = <taintValue>: <taintEffect>. Эффект порчи в примере предотвращает включение любого модуля без соответствующих допусков в расписание для этого узла. Другие поддерживаемые эффекты порчи — NoExecute и PreferNoSchedule (мягкая версия NoSchedule). При использовании эффекта PreferNoSchedule kube-scheduler попытается не размещать под модуль без требуемого допуска на испорченный узел. Эффект NoExecute вызывает мгновенное удаление всех подов без определённого разрешения узла. Он может быть полезен, если у вас уже есть поды, запущенные на узле, которые вам больше не нужны. Создание порчи — лишь первая часть настройки. Чтобы поды могли быть запланированы на испорченном узле, нужно добавить терпимость:  Терпимость для порчи добавлена с помощью оператора «Равно». Можно использовать оператор Exists, который применяет допуск к любому узлу, соответствующему ключу порчи. При этом точное значение указывать не нужно. В этом случае используем taint storage = ssd: NoSchedule, чтобы запланировать под, определённый выше, для узла. Также можно отделять поды друг от друга с помощью функции анти-сродства. Одна из лучших практик, доступных Kubernetes — избегание единой точки отказа с распределением подов по разным зонам доступности. Можно настроить аналогичное поведение в анти-сродстве для части спецификации пода. Для анти-сродства нам понадобятся два пода. Первый под: Для первого пода использована метка “security: s1.”  Второй под: Второй под относится к селектору меток security: s1 в spec.affinity.podAntiAffinity. Соответственно, он не будет назначен узлу, на котором уже размещены какие-либо поды с меткой security: s1. Расширенное планирование подов позволяет использовать множество интересных вариантов и продвинутых практик для развёртывания сложных приложений и микросервисов в Kubernetes. С помощью привязки подов реализуется их размещение и локализация данных для тесно связанных стеков приложений и микросервисов. В таблице — ключевая информация для каждого типа ресурсов. Обзор возможностей Kubernetes для расширенного планирования подов Тип ресурса Когда используется Достоинства Недостатки Оптимальные сферы применения nodeSelector Назначение подов узлам с определёнными метками Простота использова-ния, незначитель-ные изменения в PodSpec Отсутствие поддержки логических операторов, ограниченные возможности расширения с помощью сложных правил планирования Только в ранних версиях K8s, не поддержива-ющих сродство узлов Сродство узлов Реализация локальности данных, запуск модулей на узлах с помощью специального программного обеспечения. Функциональ-ный синтаксис с поддержкой логических операторов, детальный контроль над правилами размещения подов, поддержка жёстких и мягких правил размещения подов Необходи-мость модификации существующих подов для изменения поведения Сочетание        жёстких и мягких правил для охвата различных вариантов использова-ния и сценариев Сродство подов Размещение модулей в зависимой службе, обеспечива-ющей локальность данных Аналогично сродству узлов Необходи-мость модификации существующих подов для изменения поведения Правильное управление метками в подах и документи-рование используемых меток Анти-сродство подов Обеспечение высокой доступности через распростране-ние пакетов, предотвраще-ние конкуренции между сервисами за ресурсы Развёрнутый контроль над отторжением подов, поддержка жёстких и мягких правил анти-сродства подов Необходи-мость модификации существующих подов для изменения поведения Аналогично сродству узлов Порча и терпимость Узлы с выделенным программным обеспечением, разделение ресурсов команды Отсутствие необходи-мости модификации существующих подов, поддержка автоматического удаления подов без требуемой терпимости, поддержка различных эффектов порчи Отсутствие поддержки синтаксиса с логическими операторами Необходимо быть осторожными при нанесении нескольких порч на узел. Важно убедиться, что нужные поды имеют требуемые уровни терпимости Используя анти-сродство узлов и порчу, можно запускать узлы с оборудованием, выделенным для определённых приложений и сервисов, обеспечивая эффективное использование ресурсов в кластере. При помощи анти-сродства пода и анти-сродства узла возможна высокая доступность приложений с избежанием единой точки отказа: в таком случае разные компоненты будут работать на разных узлах. Сродство и анти-сродство — две мощные концепции в Kubernetes, которые необходимо освоить каждому администратору кластера.  Проводник Нетологии на Хабре