Kubernetes произвел настоящую революцию в распределенных вычислениях. Хотя он решает ряд сверхсложных проблем, появляются и новые вызовы. Одна из таких проблем - обеспечение того, чтобы кластеры Kubernetes были спроектированы с учетом доменов отказов. Проектирование с учетом доменов отказов включает в себя такие аспекты, как предоставление инфраструктуры в зонах доступности, обеспечение того, чтобы физические серверы находились на разных стойках, также необходимо убедиться, что поды, поддерживающие ваше приложение, не окажутся в одном и том же физическом воркере Kubernetes. Для решения последней задачи можно использовать правила совместного или раздельного существования между подами (inter-pod affinity and anti-affinity rules), и в официальной документации Kubernetes они описаны очень хорошо: “Сходство между подами (inter-pod affinity) и анти-сходство (anti-affinity) позволяет вам ограничивать, на каких узлах может быть запланирован ваш под, основываясь на метках подов, которые уже запущены на узле, а не на основе меток на узлах. Правила имеют вид "этот под должен (или, в случае anti-affinity, не должен) работать на узле X, если на этом X уже работает один или несколько подов, удовлетворяющих правилу Y". Y выражается как LabelSelector с опциональным ассоциированным списком пространств имен; в отличие от узлов, поскольку поды разделены по именам (и поэтому метки на поды также неявно разделены по именам), селектор меток  должен указать, к каким пространствам имен он должен применяться. Концептуально X - это домен топологии, такой как узел, стойка, зона облачного провайдера, регион облачного провайдера и т. д. Вы выражаете его с помощью topologyKey, который является ключом для метки узла, используемой системой для обозначения такого топологического домена; например, см. ключи меток, перечисленные выше в разделе "Интерлюдия: встроенные метки узлов". Affinity могут быть определены с помощью утверждения о принадлежности в манифесте развертывания. Например, дан кластер из 3 узлов: $ kubectl get nodes Вы можете создать affinity-правило, добавив affinity-строфу в спецификацию подов: $ cat nginx.yaml В разделе Affinity много всего происходит, поэтому я разберу каждую часть. Affinity предоставляет следующие 3 ограничения планирования: $ kubectl explain pod.spec.affinity В приведенном выше примере я использую правило podAntiAffinity, которое можно применять, чтобы избежать размещения двух похожих подов вместе. Карта labelSelector содержит выражение для соответствия подам, к которым будут применены affinity-правила. И, наконец, topologyKey используется для указания элемента, к которому вы хотите применить это правило. В этом примере я указал ключ топологии hostname, который предотвратит размещение двух подов, соответствующих labelSelector, на одном узле. После создания развертывания мы можем проверить то, что каждый под был запланирован на уникальный рабочий узел: $ kubectl get po -o wide Но при любой реализации affinity всегда есть тонкости, о которых необходимо знать. В приведенном выше примере, что будет если потребуется масштабировать развертывание для обработки дополнительной нагрузки? Это можно увидеть наглядно: $ kubectl scale deploy nginx --replicas 6 Если мы просмотрим список подов: $ kubectl get po Мы видим, как новые поды застряли в состоянии Pending. Это потому, что у нас всего три узла, и affinity-правило не позволяет запланировать два одинаковых пода на один узел. Планировщик Kubernetes отлично справляется со своей работой, но иногда необходимо немного больше контроля над тем, где окажутся ваши поды. Это особенно актуально, когда вы используете несколько зон доступности в "облаке", и вам нужно обеспечить распределение подов между ними. Я вернусь к этой теме в одной из следующих статей, где я обсужу ключи топологии зон и приоритеты распределения. Материал подготовлен в рамках курса «Инфраструктурная платформа на основе Kubernetes». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь. Переводчик, редактор