Как разместить pod на определенном узле (node) в Kubernetes?

«Как разместить pod на определенном узле (node) в Kubernetes?» — вопрос из категории Kubernetes, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для управления размещением 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 для выделения специализированных пулов узлов.