Что управляет перемещением подов (pods) между узлами (nodes) в Kubernetes?

Ответ

Первоначальное размещение пода на узле управляется компонентом kube-scheduler. Он отвечает за автоматический выбор подходящего узла для каждого нового пода, учитывая:

  • Ресурсные требования и ограничения (requests/limits для CPU, памяти).
  • Политики размещения: affinity/anti-affinity (притяжение/отталкивание подов друг от друга или от узлов), taints и tolerations ("загрязнения" узлов).
  • Топологию распределения (например, распределение по зонам доступности).

Пример правила nodeAffinity для размещения на узлах с SSD:

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd

Перемещение уже работающих подов (эвакуация) — это отдельный процесс, которым напрямую управляет не scheduler, а администратор или система. Основные инструменты:

  • kubectl drain <node-name>: Безопасно удаляет все поды с узла, перенаправляя их на другие узлы (для контроллеров с репликами, например, Deployment).
  • kubectl cordon <node-name>: Помечает узел как недоступный для планирования новых подов.
  • kubectl delete pod <pod-name>: Принадлежащий ReplicaSet или Deployment под будет автоматически пересоздан на другом узле.
  • Cluster Autoscaler: Может инициировать перемещение подов при масштабировании кластера вниз.
  • DaemonSet: Поды, управляемые DaemonSet, будут автоматически перезапущены на новом узле, если старый узел выходит из строя.

Ответ 18+ 🔞

А, ну это же классика, ёпта! Слушай сюда, сейчас разжуем, как этот цирк работает.

Представь себе: у тебя есть куча серверов (нод) и куча контейнеров (подов), которые нужно по ним раскидать. Так вот, за первоначальную расстановку по полю отвечает kube-scheduler — этакий главный распределитель, хитрая жопа. Он смотрит на каждый новый под и думает: "Э, бошка, думай, куда бы эту обузу приткнуть?".

Смотрит он на три главные вещи:

  1. Жадину. Сколько под хочет CPU и памяти (requests) и сколько максимум может сожрать (limits). Чтобы не получилось, что на одной ноде все поды вдруг решат память хавать как не в себя, и она накроется медным тазом.
  2. Прихоти. Разные правила affinity/anti-affinity. Например, "посади меня только на ноду с SSD" (это как раз пример в коде ниже) или "рассадь нас подальше друг от друга, чтобы если одна нода загнётся, не все сразу". А ещё есть taints и tolerations — это когда нода говорит: "Я токсичная, ко мне только те, у кого есть иммунитет (tolerations)!".
  3. Географию. Чтобы, например, реплики одной хрени не все в одной зоне доступности оказались, а то зона упадёт — и тебе писец полный.

Вот, смотри, как приказать посадить под только на ноду с SSD. Код не трогаем, он святой:

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd

Теперь, вторая часть истории — перемещение уже работающего барахла. Это овердохуища важная тема! Scheduler тут уже не главный, он только первый раз выбирал. Дальше — админские танцы с бубном.

Вот основные способы:

  • kubectl drain <node-name> — это мощно, бля. Ты говоришь ноде: "Всё, дружок, закругляйся". Она перестаёт принимать новых, а всех текущих обитателей начинает вежливо выселять (terminate). Если за подом следит какой-нибудь Deployment, то он тут же создаст его копию на другой ноде. Главное — чтобы приложения умели терпеть такие фокусы, а то будет вам хиросима.
  • kubectl cordon <node-name> — просто ставишь шлагбаум. "Новых — не пущать!". Старые пока работают. Полезно для обновления ноды.
  • kubectl delete pod <pod-name> — самый простой и иногда дикий способ. Просто берёшь и убиваешь под. Если он от контроллера (ReplicaSet, Deployment), то система самовосстановления охуеет на секунду и породит его заново, уже на другом узле (если есть куда). Доверия ебать ноль к стабильности, но работает.
  • Cluster Autoscaler — умная штука. Если нода стала не нужна (мало нагрузки), он может её вообще выключить, предварительно всех с неё выгнав командами drain. Автоматизация, ёбать копать!
  • DaemonSet — это отдельная песня. Это такие поды-прилипалы, которые должны быть на каждой ноде (или на каждой из выбранных). Если нода умирает, под с неё просто исчезает. Но как только нода воскресает (или появляется новая) — DaemonSet тут же лепит на неё свой под. Сам от себя охуеешь, как это удобно для мониторинга или логирования.

Короче, вся система построена на идее, что поды — одноразовые цыплята, их можно гонять туда-сюда. Главное — правила задать правильно, а то получится пиздопроебибна, когда все легковесные поды на одной ноде, а тяжёлые — на другой.