← Kubernetes: планирование
6 мин · средне · Урок 6 из 7

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»

Типичная схема:

  1. Админ ставит taint: kubectl taint nodes gpu-pool dedicated=gpu:NoSchedule. Случайные Pod без toleration сюда не сядут.
  2. Админ ставит label: kubectl label nodes gpu-pool dedicated=gpu. По нему можно прицелиться через affinity.
  3. ML-приложения добавляют в Pod и toleration на dedicated=gpu:NoSchedule, и nodeAffinity на dedicated In [gpu].

GPU-ноды защищены от посторонних. ML-Pod гарантированно едут на нужное железо.

Как шедулер их обрабатывает

kube-scheduler делает два прохода: filtering и scoring.

На фильтре:

На скоринге:

Если на фильтре отсеялись все, pod Pending. Если на скоринге несколько кандидатов, выбирается тот, у кого больше очков.

В кластере из одной ноды видна только половина картины: фильтр по taints и required-affinity работает, а расхождение «toleration есть, affinity нет» не проявляется, уезжать 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

Коротко

Прошли материал до конца? Отметьте урок пройденным.