Taints vs Affinity: пропуск и адрес
Почему toleration без affinity не удерживает Pod на выделенной ноде, а affinity без toleration оставляет его в Pending.
Зачем сравнивать taints и affinity
На первый взгляд они делают одно и то же: ограничивают, где запускается pod. На самом деле они работают с двух разных сторон, и именно поэтому их часто комбинируют.
Короткое правило, которое стоит держать в голове:
Taint = пропуск (на ноду пускают только тех, у кого есть toleration). Affinity = адрес (pod сам идёт по нужному адресу).
Чтобы pod ОБЯЗАТЕЛЬНО попал на dedicated-ноду И НЕ ушёл на чужую, нужны оба механизма. Один без другого ломается.
| Механизм | Кто настраивает | Что даёт | Чего не даёт |
|---|---|---|---|
| taint + toleration | админ на ноде, разработчик в Pod | пускает на ноду с пометкой | не притягивает Pod к ней |
| label + nodeAffinity | админ на ноде, разработчик в Pod | нацеливает Pod на ноду | не снимает taint |
Только toleration: pod пройдёт куда угодно
Toleration даёт разрешение игнорировать taint. Она не говорит шедулеру «посади меня сюда», только «если посадишь, ничего не сломается». При выборе ноды шедулер сначала фильтрует кандидатов по taints+tolerations, потом по affinity, потом по ресурсам.
В мультинодовом кластере без affinity Pod с toleration уйдёт на любую ноду из пула. Dedicated-нода останется пустой, хотя именно для неё выделяли ресурсы.
Только affinity: pod пойдёт правильно, но его не пустят
Affinity делает обратное: говорит «хочу ноду с такими labels», но не снимает с неё taint-ы. Шедулер видит affinity, выбирает ноду с label, видит taint без toleration, исключает ноду. Pod Pending.
Это классическая ловушка. Дан pod с правильным affinity, dedicated-нода с правильным label, и pod почему-то Pending. Ответ: taint на ноде не покрыт toleration.
В событиях Pod при этом прямо написано «untolerated taint». Все смотрят на affinity и не догадываются проверить taint.
Полный комплект
spec:
tolerations:
- key: dedicated
operator: Equal
value: critical
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: dedicated
operator: In
values: [critical]
Pod терпит taint dedicated=critical:NoSchedule и сам идёт на
ноду с label dedicated=critical. Оба требования сходятся на
одном узле. Шедулер пропускает pod через оба фильтра.
Сценарий «GPU-пул только для ML»
Типичная схема:
- Админ ставит taint:
kubectl taint nodes gpu-pool dedicated=gpu:NoSchedule. Случайные Pod без toleration сюда не сядут. - Админ ставит label:
kubectl label nodes gpu-pool dedicated=gpu. По нему можно прицелиться через affinity. - ML-приложения добавляют в Pod и toleration на
dedicated=gpu:NoSchedule, и nodeAffinity наdedicated In [gpu].
GPU-ноды защищены от посторонних. ML-Pod гарантированно едут на нужное железо.
Как шедулер их обрабатывает
kube-scheduler делает два прохода: filtering и scoring.
На фильтре:
- taints+tolerations исключают неподходящие ноды;
- requiredDuring nodeAffinity исключает ноды без нужных labels;
- ресурсы (requests) тоже здесь.
На скоринге:
- preferredDuring nodeAffinity добавляет очков;
- встроенные правила (балансировка нагрузки, image locality) тоже считают.
Если на фильтре отсеялись все, pod Pending. Если на скоринге несколько кандидатов, выбирается тот, у кого больше очков.
В кластере из одной ноды видна только половина картины: фильтр по taints и required-affinity работает, а расхождение «toleration есть, affinity нет» не проявляется, уезжать Pod всё равно некуда. Разница между механизмами становится заметной, когда нод хотя бы две.
Что часто ломается
- Поставили только toleration, забыли affinity. Pod уехал на обычную ноду. Dedicated пустует, бюджет тратится зря.
- label и taint разные ключи.
dedicated=criticalдля taint иtier=criticalдля label. Сматчиться нечему. Лучше единый ключ. - Effect перепутали. Pod с toleration на
NoSchedule, на ноде taintNoExecute. Не сматчится, pod не сядет.
Связанные команды
kubectl taint nodes <name> <key>=<value>:<effect>
kubectl label nodes <name> <key>=<value>
kubectl get nodes -L <label-key>
kubectl describe node <name> | grep -A3 Taints
kubectl describe pod <name> | grep -A10 Events
kubectl explain pod.spec.tolerations
kubectl explain pod.spec.affinity.nodeAffinity
Коротко
- Toleration разрешает сесть на ноду с taint, но никуда Pod не притягивает.
- nodeAffinity нацеливает Pod на ноду с нужным label, но taint не снимает.
- Для выделенной ноды нужны оба: taint + toleration и label + affinity, желательно на одном ключе.
- Шедулер сначала фильтрует (taints, required-affinity, ресурсы), потом скорит (preferred-affinity и встроенные правила).
- Pod в
Pendingс «untolerated taint» в событиях означает, что забыли именно toleration, а не affinity.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс