Ответ
Для управления размещением pod на конкретных узлах в Kubernetes используются несколько механизмов, которые я применял в зависимости от требований.
1. NodeSelector (Простой выбор по меткам): Используется, когда нужно запустить pod на узлах с определенными характеристиками (например, с SSD).
- Шаг 1: Добавьте метку на узел.
kubectl label nodes <node-name> disktype=ssd - Шаг 2: Укажите
nodeSelectorв манифесте pod (или deployment).apiVersion: v1 kind: Pod metadata: name: nginx-ssd spec: containers: - name: nginx image: nginx nodeSelector: disktype: ssd # Pod будет запланирован только на узлы с этой меткой
2. NodeAffinity / Anti-Affinity (Гибкие правила сродства): Более мощный и выразительный механизм. Я использовал его для распределения инстансов StatefulSet по разным зонам доступности (Availability Zones).
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
affinity:
nodeAffinity:
# Предпочтительное, но не обязательное правило
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- eu-west-1a
- eu-west-1b
podAntiAffinity:
# Обязательное правило: избегать размещения двух pod с меткой app=web на одном узле
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: kubernetes.io/hostname
containers:
- name: app
image: myapp:latest
3. Taints и Tolerations ("Защита" узлов): Используется для резервирования узлов под специфические нагрузки. Например, у нас были узлы с GPU только для задач машинного обучения.
- Шаг 1: Добавьте taint на узел.
kubectl taint nodes gpu-node-1 dedicated=ml:NoSchedule - Шаг 2: Добавьте toleration в pod, которому нужен этот узел.
apiVersion: v1 kind: Pod metadata: name: training-job spec: containers: - name: trainer image: tensorflow:latest tolerations: - key: "dedicated" operator: "Equal" value: "ml" effect: "NoSchedule"
4. Прямое указание nodeName (Только для особых случаев): Жесткая привязка, обходящая планировщик Kubernetes. Я использовал это только для отладки или для системных компонентов, которые должны работать на конкретном узле (например, DaemonSet-подобная логика в кастомных сценариях). Не рекомендуется для обычных приложений.
apiVersion: v1
kind: Pod
metadata:
name: debug-pod
spec:
nodeName: specific-node-42 # Pod будет запущен именно на этом узле
containers:
- name: debug
image: busybox
Выбор подхода: NodeSelector для простых случаев, Affinity/Anti-Affinity для обеспечения отказоустойчивости и распределения, Taints/Tolerations для выделения специализированных пулов узлов.