Короткий ответ
Taint на узле отталкивает все поды, у которых нет соответствующей toleration (например, резервирование узлов с GPU только под нагрузку, которая их реально использует), тогда как affinity работает в обратную сторону — это предпочтение/требование со стороны Pod к определённым узлам; для гарантированного выделения пула узлов под конкретную нагрузку обычно комбинируют taint+toleration с nodeAffinity.
Как это работает подробнее
taint состоит из ключа, значения и эффекта (NoSchedule — не планировать новые поды без toleration; PreferNoSchedule — мягкое избегание; NoExecute — дополнительно выселяет уже запущенные поды без toleration). Toleration на Pod лишь "разрешает" планирование на узел с таким taint, но не обязывает планировщик выбрать именно этот узел — для принудительного направления на нужный пул узлов toleration дополняют nodeAffinity/nodeSelector.
Пример кода
tolerations:
- key: "nvidia.com/gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- { key: "nvidia.com/gpu", operator: In, values: ["true"] }Что использовать на практике
- Практика. типичный сценарий — выделенный пул GPU-узлов с taint
nvidia.com/gpu=true:NoSchedule; только поды с явной toleration под этот taint (обычно ML-нагрузка) могут туда попасть, а GPU-узлы не засоряются случайными обычными workload. Аналогично используют для узлов под конкретные команды/тарифные пулы в мультиарендных кластерах или для исключения control-plane узлов из обычного планирования.
Подводные камни
- Риски. добавлять toleration без nodeAffinity, ожидая, что под обязательно попадёт именно на нужный выделенный узел — toleration лишь снимает запрет, но не создаёт предпочтение, и планировщик может разместить под на любом другом подходящем узле без этого taint; использовать
NoExecuteбез понимания, что это может неожиданно выселить уже работающие поды при добавлении taint на уже занятый узел.