Модуль 10 / 19
Scheduling: affinity, taints и topology
Содержание
1. Цели модуля
Вы научитесь объяснять решения scheduler, применять nodeSelector, affinity, taints/tolerations и topology spread, диагностировать Pending Pod и безопасно готовить Node к обслуживанию.
2. Теория: scheduling cycle
Scheduler рассматривает только неназначенные Pods: filter исключает неподходящие Nodes, score ранжирует оставшиеся, binding записывает spec.nodeName. Запуск контейнера выполняет kubelet, а не scheduler.
Основные ограничения: requests против allocatable, nodeSelector/affinity, taints, topology, volume topology и свободные host ports.
3. Теория: selectors и affinity
nodeSelector — простое обязательное совпадение labels. requiredDuringSchedulingIgnoredDuringExecution — обязательное правило при scheduling; preferred — весовой приоритет без гарантии. IgnoredDuringExecution означает, что изменение label не выселяет уже работающий Pod.
Pod affinity размещает рядом с другими Pods, anti-affinity разносит их. TopologySpreadConstraints управляет skew по hostname/zone; DoNotSchedule является жёстким ограничением, ScheduleAnyway — предпочтением.
4. Теория: taints и tolerations
Taint отталкивает Pods, toleration лишь разрешает рассматривать Node и не притягивает Pod. NoSchedule блокирует новое размещение, PreferNoSchedule является мягким, NoExecute также может выселять уже запущенные Pods.
Для выделенного node pool обычно комбинируйте taint с node affinity, иначе tolerating workload всё ещё может уйти на другой Node.
5. Методические указания
- Не используйте spec.nodeName вместо scheduler constraints
- Защищайте доверенные node labels через NodeRestriction-compatible prefixes
- Начинайте Pending-диагностику с Pod Events
- Проверяйте все constraints одновременно: они объединяются логическим AND
- Оценивайте topology при scale и rolling update
- Перед drain проверьте PDB, local storage, unmanaged Pods и capacity других Nodes
6. Лабораторная работа: placement
Сохраните первые объекты как scheduling-lab.yaml, а tolerating Pod — как toleration-pod.yaml.
apiVersion: v1
kind: Namespace
metadata: {name: lab-scheduling}
---
apiVersion: v1
kind: Pod
metadata: {name: selector-demo, namespace: lab-scheduling}
spec:
nodeSelector: {workload.course/tier: general}
containers:
- {name: app, image: "busybox:1.37.0", command: ["sh", "-c", "sleep 3600"]}
---
apiVersion: v1
kind: Pod
metadata: {name: affinity-demo, namespace: lab-scheduling}
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: workload.course/tier, operator: In, values: [general]}
containers:
- {name: app, image: "busybox:1.37.0", command: ["sh", "-c", "sleep 3600"]}apiVersion: v1
kind: Pod
metadata: {name: toleration-demo, namespace: lab-scheduling}
spec:
nodeSelector: {workload.course/tier: general}
tolerations:
- {key: dedicated, operator: Equal, value: course, effect: NoSchedule}
containers:
- {name: app, image: "busybox:1.37.0", command: ["sh", "-c", "sleep 3600"]}kubectl label node course-worker workload.course/tier=general
kubectl apply -f scheduling-lab.yaml
kubectl wait -n lab-scheduling --for=condition=Ready pod/selector-demo pod/affinity-demo --timeout=120s
kubectl get pods -n lab-scheduling -o wide
kubectl taint node course-worker dedicated=course:NoSchedule
kubectl apply -f toleration-pod.yaml
kubectl wait -n lab-scheduling --for=condition=Ready pod/toleration-demo --timeout=120s
kubectl get pods -n lab-scheduling -o wide
kubectl get node course-worker --show-labelsКритерий: selector, affinity и toleration Pods имеют Ready и назначены на course-worker; toleration-demo запускается несмотря на taint.
7. Диагностика: Unschedulable Pod
Создайте Pod с обязательным label, которого нет ни на одном Node. Он останется Pending без container logs.
kubectl run impossible -n lab-scheduling --image=busybox:1.37.0 --overrides='{"spec":{"nodeSelector":{"hardware.course/gpu":"true"},"containers":[{"name":"impossible","image":"busybox:1.37.0","command":["sh","-c","sleep 3600"]}]}}'
kubectl get pod impossible -n lab-scheduling
kubectl describe pod impossible -n lab-scheduling
kubectl events -n lab-scheduling --for pod/impossible --types=Warning
kubectl label node course-worker hardware.course/gpu=true
kubectl wait -n lab-scheduling --for=condition=Ready pod/impossible --timeout=120s
kubectl get pod impossible -n lab-scheduling -o wideЦепочка: Pod Events → requests/allocatable → labels и required affinity → taints/tolerations → volume topology → ports. Исправляйте причину, указанную FailedScheduling.
8. Обслуживание Node: cordon и drain
cordon запрещает новое scheduling, но не выселяет Pods. drain использует eviction и учитывает PDB; --delete-emptydir-data разрешает потерю локальных emptyDir данных. Сначала выполните server dry-run.
kubectl drain course-worker --ignore-daemonsets --delete-emptydir-data --dry-run=server
kubectl cordon course-worker
kubectl get nodes
kubectl uncordon course-worker
kubectl taint node course-worker dedicated=course:NoSchedule-
kubectl label node course-worker workload.course/tier- hardware.course/gpu-
kubectl delete namespace lab-schedulingНе запускайте реальный drain без проверки capacity и владельцев workload. --force и --disable-eviction обходят защитные механизмы и требуют отдельного обоснования.
9. Контроль и шпаргалка
- Чем filter отличается от score?
- Почему toleration не гарантирует Node?
- Что означает IgnoredDuringExecution?
- Когда DoNotSchedule опаснее ScheduleAnyway?
- Какие данные может удалить drain?
Модуль освоен, если вы объясняете FailedScheduling, размещаете Pod декларативно и составляете безопасный план обслуживания Node.
PDF для работы офлайн
Скачайте оформленную версию модуля для чтения без подключения к сети.