Что такое taints и tolerations? Чем они отличаются от nodeSelector и nodeAffinity?
Taints/tolerations — механизм отталкивания: узел отталкивает поды (taint), под разрешает себя туда поставить (toleration). nodeSelector и nodeAffinity — механизм притяжения: под выбирает узлы по labels. Taints отталкивают всех, affinity притягивает конкретных.
Taints, tolerations, nodeSelector и nodeAffinity
Kubernetes предоставляет несколько механизмов для управления тем, на каких узлах запускаются поды. Они работают в разных направлениях и с разной гибкостью.
Taints и Tolerations
Taint устанавливается на узел и говорит: «не размещай сюда поды, если они не имеют подходящего toleration».
# Добавить taint на узел
kubectl taint nodes gpu-node-1 gpu=true:NoSchedule
# Эффекты:
# NoSchedule — новые поды без toleration не будут сюда планироваться
# PreferNoSchedule — мягкий запрет (постарается не ставить, но может)
# NoExecute — выселяет существующие поды без toleration
# Удалить taint
kubectl taint nodes gpu-node-1 gpu=true:NoSchedule-
Toleration в поде разрешает его размещение на узлах с matching taint:
spec:
tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
# Toleration не ПРИВЛЕКАЕТ под к узлу,
# оно только РАЗРЕШАЕТ туда попасть
Типичные use cases taints:
- Dedicated узлы для GPU-workloads:
nvidia.com/gpu=present:NoSchedule. - Изоляция control-plane:
node-role.kubernetes.io/control-plane:NoSchedule(дефолт в kubeadm). - Временное «maintenance» узла:
maintenance=true:NoExecuteс опциональнымtolerationSeconds.
nodeSelector
Простейший механизм: под планируется только на узлы с заданными labels.
spec:
nodeSelector:
disktype: ssd
zone: us-east-1a
Ограничение: только равенство, AND-логика, нет гибкости. Если узел с такими labels недоступен — под зависнет в Pending.
nodeAffinity
Расширенная версия nodeSelector с операторами, OR-логикой и мягкими предпочтениями.
spec:
affinity:
nodeAffinity:
# Жёсткое требование (=nodeSelector, но гибче)
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: node.kubernetes.io/instance-type
operator: NotIn
values: ["t3.nano"]
# Мягкое предпочтение
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: zone
operator: In
values: ["us-east-1a"]
- weight: 20
preference:
matchExpressions:
- key: zone
operator: In
values: ["us-east-1b"]
Операторы: In, NotIn, Exists, DoesNotExist, Gt, Lt.
Совместное использование
Типичный паттерн для выделенных GPU-узлов:
# На узле:
# kubectl taint nodes gpu-node-1 nvidia.com/gpu=present:NoSchedule
# kubectl label nodes gpu-node-1 hardware=gpu
spec:
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: hardware
operator: In
values: ["gpu"]
Toleration позволяет поду попасть на GPU-узел. nodeAffinity гарантирует, что под пойдёт именно туда, а не на любой другой узел.
Подводные камни
- Toleration без affinity не гарантирует попадание на нужный узел. Под просто может попасть туда, если свободно. Для гарантии нужна пара taint + affinity.
- NoExecute выселяет поды немедленно. При добавлении taint NoExecute существующие поды без toleration получают SIGTERM. Используйте
tolerationSecondsдля graceful period. - IgnoredDuringExecution. Affinity проверяется только при планировании. Если labels узла изменились после запуска пода — под не выселяется. Для этого нужен RequiredDuringExecution (beta в K8s 1.27).
- Системные taints. При недоступности узла K8s автоматически добавляет
node.kubernetes.io/unreachable:NoExecuteиnode.kubernetes.io/not-ready:NoExecute. Системные поды (CoreDNS) имеют toleration с большим tolerationSeconds. - podAffinity/podAntiAffinity — дорогая операция. При тысячах подов scheduler тратит значительное время на вычисление affinity. Используйте
topologySpreadConstraintsкак более эффективную альтернативу. - Конфликт с Cluster Autoscaler. Если taint+affinity требует узел с конкретными labels, Autoscaler должен знать об этих labels в node group конфигурации — иначе не создаст нужный узел.
Common mistakes
- Путать taint и label
- Считать toleration обязательным placement
- Не знать effects
What the interviewer is testing
- Различает repel и attract
- Понимает combination pattern
- Знает NoSchedule и NoExecute