Что такое Node Affinity и Pod Affinity/Anti-Affinity?
Node Affinity
Node Affinity — это расширенная и более гибкая замена nodeSelector. Она позволяет задавать правила, по которым планировщик решает, на каких узлах может быть запланирован Pod. Правила задаются в spec.affinity.nodeAffinity и бывают двух типов:
-
requiredDuringSchedulingIgnoredDuringExecution — жёсткое требование: если условие не выполняется, Pod не будет запланирован на узле.
-
preferredDuringSchedulingIgnoredDuringExecution — мягкое предпочтение: планировщик постарается разместить Pod на узлах, удовлетворяющих условию, но может разместить и на других.
Условия описываются через nodeSelectorTerms и matchExpressions (ключ, оператор, список значений). Типичные операторы: In, NotIn, Exists, DoesNotExist (в некоторых полях доступны Gt/Lt).
Пример (нужны ноды с меткой disktype=ssd):
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
\- matchExpressions:
\- key: disktype
operator: In
values: \["ssd"\]
Отличия от nodeSelector: nodeAffinity поддерживает сложные выражения, предпочтения (weights) и операторы.
Pod Affinity и Pod Anti-Affinity
Pod Affinity/Anti-Affinity управляют взаимным расположением Pod’ов относительно друг друга (кора, «ягодное» и «противоядро»). Задаются в spec.affinity.podAffinity и spec.affinity.podAntiAffinity. Основные элементы:
-
labelSelector — выбирает набор целевых Pod’ов (по меткам), относительно которых применяется правило.
-
topologyKey — ключ метки на ноде, по которой определяется «координата» (например, kubernetes.io/hostname для уровня ноды, topology.kubernetes.io/zone для зоны).
-
Типы: requiredDuringSchedulingIgnoredDuringExecution (жёсткое) и preferredDuringSchedulingIgnoredDuringExecution (мягкое, с weight 1–100).
-
Можно ограничить область поиска — поле namespaces в podAffinityTerm (если не указано, по умолчанию обычно используется namespace Pod’а).
Примеры:
- Co-locate: поместить Pod рядом с Pod’ом app=redis на той же ноде:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
\- labelSelector:
matchLabels:
app: redis
topologyKey: "kubernetes.io/hostname"
- Spread (anti-affinity): избегать размещения frontend на той же ноде (мягкое правило с весом):
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
\- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: frontend
topologyKey: "kubernetes.io/hostname"
Семантика и поведение планировщика
-
Правила применяются при планировании Pod; поля IgnoredDuringExecution означают, что правило не принудительно повторно проверяется для уже запущенных Pod’ов при изменении меток/состояния ноды. (NoReevaluateDuringExecution — грубо: не гоняться за соответствием в рантайме.)
-
required* блокируют кандидатов-нод: если нет ни одной подходящей ноды — Pod остаётся в состоянии Pending. preferred* влияет на scoring — ноды получают баллы за совпадения.
-
weight в preferred* — целое 1–100, чем больше — тем сильнее предпочтение.
-
podAffinity проверяет существующие Pod’ы с указанными метками; полезно для locality (кеши, данные) или colocating компонентов. podAntiAffinity — для распределения реплик и повышения отказоустойчивости.
Когда применять и рекомендации
-
Используйте Node Affinity для требования аппаратных характеристик (GPU, SSD), принадлежности нод к зонe или биллинговой категории.
-
Pod Affinity — когда нужно локальность (например, co-locate nginx с локальным кэшем redis).
-
Pod Anti-Affinity — для равномерного распределения реплик по нодам/зонам, чтобы снизить blast radius. Для больших кластеров используйте мягкое anti-affinity (preferred) для уменьшения шансов, что поды останутся Unschedulable.
-
topologyKey должен быть существующей меткой на нодах; распространённые значения: kubernetes.io/hostname (node), topology.kubernetes.io/zone (zone).
-
Комбинируйте с taints/tolerations и resource requests/limits для полного контроля.
-
Осторожно с жёсткими anti-affinity в больших кластерах: проверка множества Pod’ов может замедлить планировщик и привести к Pending.
Частые ошибки
-
Задать topologyKey, которого нет на нодах — правило не сработает ожидаемо.
-
Сочетать слишком много required правил — легко получить Pending.
-
Ожидать, что affinity пересматривается в рантайме — нет, по умолчанию это только при планировании.