← Kubernetes: рабочие нагрузки
5 мин · просто · Урок 5 из 11

DaemonSet: по одному Pod на ноду

Контроллер для агентов, которые обязаны быть на каждой машине: как он считает реплики, при чём тут nodeSelector и taint.

Зачем нужен DaemonSet

DaemonSet - контроллер, который держит по одному Pod на каждой подходящей ноде кластера. Число копий тут не пишет человек. Его выводит контроллер из набора нод: пять нод - пять Pod, пятьдесят - пятьдесят.

Список нод меняется, и DaemonSet следит за этим непрерывно. Добавили в кластер машину - Pod на ней появится сам, без единой команды. Вывели ноду из кластера - Pod уедет вместе с ней.

Так оформляют всё, что обязано работать на каждой машине: сборщик логов, экспортёр метрик вроде node-exporter, сетевой плагин CNI, агент безопасности. Пропустить одну ноду для такого агента означает слепое пятно в мониторинге или дыру в защите.

Чем отличается от Deployment

У Deployment spec.replicas задаёт человек и сам решает, сколько копий нужно. У DaemonSet поля replicas в схеме нет вообще.

Тут прячется ловушка. Патч DaemonSet числом реплик выглядит так:

kubectl patch daemonset node-agent -p '{"spec":{"replicas":5}}'
# daemonset.apps/node-agent patched (no change)

Ошибки не будет. Ответ выглядит успешным, хотя ничего не поменялось: неизвестное поле молча отбросили. Новичок читает слово patched и считает, что реплики выставились. Смотреть надо на скобки (no change) и проверять результат через kubectl get daemonset.

patched (no change) означает, что поле молча отбросили. У DaemonSet нет spec.replicas, число Pod задаёт только набор подходящих нод.

Что показывает kubectl get daemonset

kubectl get daemonset node-agent
# NAME         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
# node-agent   1         1         1       1            1           <none>          7s

Число в колонке DESIRED всегда совпадает с числом подходящих нод. Его сверяют с выводом kubectl get nodes.

nodeSelector сужает набор нод

nodeSelector в шаблоне Pod оставляет только ноды с нужными лейблами. Реальный приём: агент для GPU-машин не нужен на обычных.

kubectl patch daemonset node-agent \
  -p '{"spec":{"template":{"spec":{"nodeSelector":{"disk":"ssd-nvme"}}}}}'
kubectl get daemonset node-agent
# node-agent   0         0         0       0            0           disk=ssd-nvme   12s

Если такого лейбла нет ни на одной ноде, DESIRED становится нулём. Pod при этом не висит в Pending и не падает - его просто не создают, потому что создавать некуда. Лейблы нод смотрятся через kubectl get nodes --show-labels.

Убрать поле обратно можно JSON-патчем со значением null:

kubectl patch daemonset node-agent \
  -p '{"spec":{"template":{"spec":{"nodeSelector":null}}}}'

Ноды с taint и tolerations

node-1 · disk=ssd-nvme node-agent node-2 · без лейбла control-plane · taint node-agent + toleration
DESIRED считает ноды, прошедшие оба фильтра: лейбл и taint.

Taint - отметка на ноде, которая отталкивает Pod. Типичный пример: control-plane помечен node-role.kubernetes.io/control-plane:NoSchedule, чтобы туда не заезжали пользовательские приложения. Агенту мониторинга попасть туда как раз надо, поэтому в шаблон добавляют toleration:

tolerations:
  - key: node-role.kubernetes.io/control-plane
    operator: Exists
    effect: NoSchedule

На одноузловом кластере разницы не видно. Знание пригодится на многонодовом, где без toleration DaemonSet тихо пропускает control-plane.

Обновление

Шаблон Pod поменялся - Pod пересоздаются по spec.updateStrategy. По умолчанию это RollingUpdate с maxUnavailable: 1: контроллер гасит один Pod, ждёт готовности нового и берётся за следующую ноду. Значение можно поднять, чтобы раскатка по сотне нод не тянулась часами.

Домашка

Теорию закрепляет задание на своём кластере: 3 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-daemonset     # развернуть стартовое состояние
./run.sh verify k8s-daemonset    # проверить текущий шаг

Коротко

Дрилл · вопросы как на собесе

Проверь себя без подсказок

Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.

01

Зачем нужен DaemonSet?

K8S-008

Прошли материал до конца? Отметьте урок пройденным.