DaemonSet: агент на каждом узле
DaemonSet гарантирует ровно один под на каждом узле — это способ запускать фоновых агентов: сбор логов, метрик, сетевые плагины.
DaemonSet — контроллер, который держит по одному поду на каждом подходящем узле кластера. Добавили узел — под появился автоматически; вывели узел — под исчез вместе с ним.
Deployment и StatefulSet отвечают на вопрос «сколько реплик приложения мне нужно». DaemonSet отвечает на другой: «что должно работать на каждой машине». Это принципиально иная модель размещения. Вы не задаёте число подов — оно равно числу узлов и меняется само, когда кластер растёт или сжимается.
Такая модель нужна инфраструктурным агентам, которые обслуживают сам узел, а не пользовательский трафик: сборщику логов, который читает файлы контейнеров на диске узла; экспортёру метрик, снимающему загрузку CPU и памяти конкретной машины; сетевому плагину (CNI), настраивающему маршруты; агенту безопасности. Всем им важно присутствовать везде и иметь доступ к ресурсам своего узла.
Зачем это на практике
Классический пример — сбор логов. Контейнеры пишут stdout в файлы на диске узла (обычно под /var/log/). Чтобы собрать эти логи централизованно, на каждой машине должен крутиться агент (Fluent Bit, Vector, Promtail), который читает локальные файлы и отправляет их в хранилище. Запускать его Deployment-ом бессмысленно: три реплики на пяти узлах оставят два узла без сборщика, а сам Kubernetes волен ставить реплики куда угодно. DaemonSet же гарантирует: на каждом узле — ровно один сборщик, и новый узел получит его автоматически.
Типичные сценарии для DaemonSet:
- Логи: Fluent Bit, Fluentd, Vector, Promtail читают логи всех контейнеров узла.
- Мониторинг: node-exporter (Prometheus) снимает метрики «железа» каждого узла.
- Сеть: CNI-плагины (Calico, Cilium) и kube-proxy настраивают сеть на узлах.
- Хранилище и безопасность: агенты CSI, сканеры уязвимостей, средства аудита.
Манифест и доступ к ресурсам узла
Манифест похож на Deployment, но kind: DaemonSet и нет поля replicas — число подов определяется числом узлов. Агенту обычно нужен hostPath-том, чтобы читать файлы прямо с диска узла:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
spec:
selector:
matchLabels:
app: fluent-bit
template:
metadata:
labels:
app: fluent-bit
spec:
containers:
- name: fluent-bit
image: fluent/fluent-bit:3.0
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log # читаем логи с диска самого узла
Проверяем: подов столько же, сколько узлов, и они «размазаны» по разным машинам.
kubectl apply -f fluent-bit.yaml
# Колонки DESIRED и CURRENT равны числу узлов
kubectl get daemonset -n logging
# NAME DESIRED CURRENT READY NODE SELECTOR
# fluent-bit 3 3 3 <none>
# По одному поду на узел — смотрим распределение
kubectl get pods -n logging -o wide
Запуск только на части узлов
Иногда агент нужен не везде, а на определённых узлах — например, только на тех, где есть GPU. Это задаётся через nodeSelector по меткам узлов: DaemonSet поставит поды лишь туда, где метка совпала.
spec:
nodeSelector:
hardware: gpu # под только на узлах с этой меткой
Чтобы запускаться и на управляющих узлах (control-plane), которые по умолчанию закрыты taint-ом, DaemonSet добавляет соответствующий toleration — поэтому многие системные агенты есть и на мастерах.
Как это работает под капотом
Контроллер DaemonSet постоянно сравнивает список узлов кластера со списком уже запущенных подов. Алгоритм прост: для каждого узла, подходящего по nodeSelector, affinity и taints/tolerations, должен существовать под — если его нет, контроллер его создаёт. Поды DaemonSet жёстко привязаны к своему узлу: планировщик не «размазывает» их, а контроллер сразу проставляет целевой узел.
Когда в кластер добавляется новый узел, контроллер замечает его и создаёт под автоматически — без вашего вмешательства. Когда узел выводится из кластера, его под исчезает вместе с ним и нигде не пересоздаётся, потому что под был привязан именно к этой машине. Поэтому у DaemonSet не бывает «лишних» реплик: их число всегда равно числу подходящих узлов.
Обновление образа в DaemonSet идёт по стратегии RollingUpdate (по умолчанию), но с поправкой на «один под на узел»: за раз обновляется ограниченное число узлов, которым управляет параметр maxUnavailable (по умолчанию 1). Контроллер удаляет старый под на узле, дожидается готовности нового и переходит к следующему узлу. Есть и стратегия OnDelete — тогда новый образ применяется к узлу только после ручного удаления его пода.
Частые ошибки
- Указание
replicasв DaemonSet. Поля нет: число подов задаётся числом узлов. Попытка «масштабировать» DaemonSet через replicas ничего не даст. - Использование Deployment там, где нужен агент на каждом узле. Deployment не гарантирует присутствие на всех узлах и не среагирует на добавление нового — часть машин останется без агента.
- Забытый
tolerationдля control-plane. Если агент должен мониторить и управляющие узлы, без подходящего toleration он туда не попадёт из-за taint-ов. - Чрезмерные права и ресурсы. Агент работает на каждом узле, поэтому утечка памяти или жадные лимиты бьют по всему кластеру разом. Для DaemonSet особенно важно выставлять аккуратные
requests/limits.
Итоги
DaemonSetдержит по одному поду на каждом подходящем узле; число подов равно числу узлов.- Новый узел получает под автоматически, выведенный — теряет его вместе с собой.
- Применяется для логов, метрик узла, сетевых плагинов и других инфраструктурных агентов.
- В отличие от Deployment, не имеет
replicasи гарантирует присутствие на каждом узле, а не заданное число копий. - Ограничить узлы можно через
nodeSelector/affinity; обновление —RollingUpdateсmaxUnavailableилиOnDelete.