Как управлять раскладкой (размещением) Pod по узлам (Node) в Kubernetes?

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

Ответ

Kubernetes предоставляет несколько механизмов для тонкого контроля над тем, на каких узлах будут запускаться Pod'ы. Мы используем их в комбинации для обеспечения отказоустойчивости, производительности и эффективного использования ресурсов.

1. Node Selector & Node Affinity (Куда размещать):

  • nodeSelector: Простой выбор узлов по лейблам. Например, для запуска Pod'а только на узлах с SSD:
    spec:
      nodeSelector:
        disktype: ssd
  • nodeAffinity: Более выразительные правила ( In, NotIn, Exists, Gt, Lt). Бывает "жестким" (requiredDuringScheduling...) и "мягким" (preferredDuringScheduling...). Мы используем "мягкое" affinity для предпочтительного размещения на узлах в определенной зоне доступности.
    affinity:
      nodeAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          preference:
            matchExpressions:
            - key: topology.kubernetes.io/zone
              operator: In
              values:
              - eu-west-1a

2. Pod Affinity & Anti-Affinity (Размещать вместе или раздельно):

  • Pod Affinity: Размещать Pod'ы на тех же узлах/зонах, что и другие Pod'ы (полезно для снижения задержки).
  • Pod Anti-Affinity (используем чаще): Критически важно для распределения реплик одного приложения по разным узлам/зонам, чтобы повысить отказоустойчивость.
    affinity:
      podAntiAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchLabels:
              app: redis-cache
          topologyKey: kubernetes.io/hostname # Не размещать две реплики redis на одном узле

3. Taints & Tolerations (Куда НЕ размещать):

  • Taint ("пятно") на узле отталкивает все Pod'ы, которые не имеют соответствующего Toleration ("терпимости").
  • Мы используем это для выделения специальных узлов (например, с GPU). На них ставится taint gpu=true:NoSchedule, и только Pod'ы с соответствующим toleration могут там запуститься.
    tolerations:
    - key: "gpu"
      operator: "Equal"
      value: "true"
      effect: "NoSchedule"

4. Pod Topology Spread Constraints (Равномерное распределение): Самый современный механизм для гарантированного распределения Pod'ов по доменам сбоя (зонам, узлам). Мы настраиваем его для ключевых Deployment, чтобы максимизировать доступность.

    topologySpreadConstraints:
    - maxSkew: 1 # Максимальная разница в количестве Pod'ов между зонами
      topologyKey: topology.kubernetes.io/zone # Критерий распределения - зона доступности
      whenUnsatisfiable: DoNotSchedule # Жесткое требование
      labelSelector:
        matchLabels:
          app: my-critical-app

В нашем продакшене мы комбинируем Pod Anti-Affinity (для распределения по узлам) с Topology Spread Constraints (для распределения по зонам), а для специализированных рабочих нагрузок используем Taints/Tolerations.