Что такое DaemonSet и когда его использовать
DaemonSet – это контроллер Kubernetes, который гарантирует запуск и поддержку копии вашего Pod на каждом узле кластера. Его основная задача – развертывание системных сервисов, тесно связанных с инфраструктурой узла. Если ваш сервис должен быть представлен на каждом узле и взаимодействует с его ресурсами, вы используете DaemonSet.
Типичные сценарии применения включают агенты сбора логов, такие как Fluentd или Filebeat, системы мониторинга вроде Prometheus node-exporter, сетевые плагины (Calico, Cilium) и драйверы хранилищ. Эти сервисы выполняют фоновые задачи уровня операционной системы узла.
DaemonSet vs Deployment: сравнительная таблица и правило выбора
Ошибка выбора контроллера ведет к неоптимальной архитектуре. Используйте простое правило: DaemonSet для сервисов, привязанных к узлу, Deployment для масштабируемых сервисов, независимых от узлов.
| Параметр | DaemonSet | Deployment |
|---|---|---|
| Цель | Запуск Pod на каждом узле | Управление набором идентичных Pod |
| Связь с узлами | Прямая, один Pod на узел | Косвенная, Pod размещаются по доступности ресурсов |
| Масштабирование | Автоматически по числу узлов | Ручное или через HPA |
| Типовой use-case | Агенты логирования, мониторинга | Веб-приложения, API, микросервисы |
Попытка использовать Deployment для задач уровня узла, например для сбора логов с каждой ноды, приведет к ручному управлению количеством реплик и сложностям с гарантированным покрытием всех узлов.
Для более глубокого сравнения всех типов контроллеров Kubernetes, включая StatefulSet и Job, обратитесь к нашему практическому руководству: Выбор контроллера Kubernetes: Deployment, StatefulSet, DaemonSet и Job.
Создание базового DaemonSet: готовый манифест и его применение
Для создания DaemonSet используется YAML-манифест. Ниже приведен минимальный рабочий пример для версии Kubernetes 1.30 (apiVersion: apps/v1).
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: example-daemonset
namespace: default
spec:
selector:
matchLabels:
app: example-app
template:
metadata:
labels:
app: example-app
spec:
containers:
- name: busybox
image: busybox:latest
command: ["sh", "-c", "sleep 3600"]
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
Ключевые секции манифеста:
- apiVersion: Для DaemonSet всегда используйте apps/v1.
- spec.selector: Должен соответствовать меткам в spec.template.metadata.labels.
- spec.template: Определяет Pod, который будет запущен на каждом узле.
- updateStrategy: Задает стратегию обновления Pod. По умолчанию RollingUpdate.
Чтобы применить манифест и проверить статус, выполните команды:
kubectl apply -f daemonset.yaml
kubectl get daemonset -n default
kubectl get pods -l app=example-app -o wide
Команда kubectl get pods -o wide покажет, что Pod запущен на каждом узле кластера. Для работы с более сложными манифестами Pod и Deployment изучите основы их структуры в нашем практическом гайде по манифестам Kubernetes.
Управление размещением Pod: запуск DaemonSet не на всех узлах
Часто требуется запускать системный сервис не на всех узлах, а только на master-нодах, узлах с GPU или с определенной меткой. Для этого Kubernetes предоставляет три механизма: nodeSelector, nodeAffinity и Tolerations.
nodeSelector: базовый выбор узлов по меткам
Это самый простой метод. Сначала добавьте метку узлу:
kubectl label node <node-name> node-type=monitoring
Затем укажите эту метку в секции spec.template.spec манифеста DaemonSet:
spec:
template:
spec:
nodeSelector:
node-type: monitoring
containers:
- name: monitoring-agent
image: prom/node-exporter:latest
Pod будет запущен только на узлах с меткой node-type=monitoring. Метод nodeSelector подходит для простых правил, но не поддерживает операторы типа «или», «не равно».
nodeAffinity и Tolerations: продвинутый контроль размещения
nodeAffinity предлагает более гибкие правила. Например, можно требовать запуск на узлах с определенной меткой или предпочитать узлы с GPU.
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/master
operator: Exists
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: accelerator
operator: In
values:
- gpu
Этот пример требует запуска на master-узлах (метка node-role.kubernetes.io/master) и предпощает узлы с меткой accelerator=gpu.
Tolerations работают в паре с Taints (загрязнениями узлов). Если узел имеет taint, Pod без соответствующего toleration на нем не запустится. Это полезно для выделения узлов под специфичные задачи.
Допустим, узел помечен taint: kubectl taint nodes node1 dedicated=monitoring:NoSchedule. Чтобы DaemonSet мог на нем работать, добавьте tolerations:
spec:
template:
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "monitoring"
effect: "NoSchedule"
Теперь Pod сможет быть запланирован на узле node1.
Практические примеры: развертывание системных агентов
DaemonSet для мониторинга: развертывание node-exporter
Prometheus node-exporter – стандартный инструмент для сбора метрик с узлов. Его развертывание через DaemonSet идеально.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true
hostPID: true
containers:
- name: node-exporter
image: prom/node-exporter:latest
ports:
- containerPort: 9100
hostPort: 9100
name: metrics
securityContext:
runAsNonRoot: true
runAsUser: 65534
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
- name: root
mountPath: /host/root
readOnly: true
args:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/host/root
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
- name: root
hostPath:
path: /
Ключевые моменты:
- hostPath: Позволяет контейнеру получать доступ к системным директориям хоста (
/proc,/sys). - securityContext: Запуск от непривилегированного пользователя (nobody, UID 65534) повышает безопасность.
- hostNetwork: true: Позволяет Pod использовать сетевой стек хоста, что упрощает доступ к метрикам по порту 9100 напрямую с узла.
DaemonSet для логирования: пример с Fluentd
Для сбора логов со всех контейнеров и системных журналов используйте агент вроде Fluentd.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: logging
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
serviceAccountName: fluentd
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch.logging.svc.cluster.local"
resources:
limits:
memory: 500Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: fluentd-config
mountPath: /fluentd/etc
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: fluentd-config
configMap:
name: fluentd-config
Этот DaemonSet монтирует директории логов хоста (/var/log, /var/lib/docker/containers) и отправляет логи в Elasticsearch. Tolerations разрешают запуск на master-узлах, которые часто имеют taint NoSchedule. Для управления подобными production-приложениями ознакомьтесь с полным руководством по Deployment в Kubernetes.
Обновление и управление жизненным циклом DaemonSet
Обновление системных агентов на всех узлах должно быть безопасным и контролируемым.
Стратегии обновления: RollingUpdate vs OnDelete
DaemonSet поддерживает две стратегии обновления, задаваемые в spec.updateStrategy.type:
- RollingUpdate (по умолчанию): Kubernetes автоматически, по одному, удаляет старые Pod и создает новые на каждом узле. Параметр
maxUnavailableопределяет максимальное число Pod, которые могут быть недоступны во время обновления. Это предпочтительная стратегия для минимизации простоя. - OnDelete: Обновление происходит только после ручного удаления Pod пользователем. Kubernetes не создает новые Pod автоматически. Эта стратегия подходит для критичных сервисов, где обновление требует дополнительных проверок.
Пошаговый алгоритм безопасного обновления и отката
- Проверка текущего состояния. Убедитесь, что все Pod в рабочем состоянии:
kubectl get daemonset -o wide && kubectl get pods -l app=<ваше_приложение>. - Изменение манифеста. Отредактируйте YAML-файл: обновите версию образа (
image: my-agent:v2.1) или конфигурацию. - Применение изменений. Выполните команду:
kubectl apply -f daemonset.yaml. - Мониторинг процесса. Отслеживайте прогресс обновления:
kubectl rollout status daemonset/<имя-daemonset>. Командаkubectl get pods -wпокажет, как Pod пересоздаются на узлах. - Откат в случае проблем. Если новая версия работает некорректно, выполните откат к предыдущей ревизии:
kubectl rollout undo daemonset/<имя-daemonset>.
Важный нюанс: обновление происходит узел за узлом. На каждом узле старый Pod будет удален только после того, как новый Pod перейдет в состояние Ready (если определены readinessProbe). Всегда проверяйте корректность синтаксиса YAML перед применением. Ошибки в отступах или структуре могут заблокировать обновление. Рекомендации по написанию безошибочных манифестов собраны в нашем руководстве по синтаксису YAML для Kubernetes.
Резюме и лучшие практики
DaemonSet – специализированный инструмент для развертывания системных сервисов уровня узла. Следуйте этим практикам для надежной работы:
- Используйте DaemonSet для агентов логирования, мониторинга, сетевых плагинов и драйверов хранилищ.
- Контролируйте размещение Pod с помощью nodeSelector для простых правил и nodeAffinity/Tolerations для сложных сценариев (например, работа на master-узлах или нодах с GPU).
- Для обновления в production предпочитайте стратегию RollingUpdate с настройкой maxUnavailable.
- Всегда задавайте securityContext для контейнеров, особенно при использовании hostPath. Запускайте от непривилегированного пользователя, где это возможно.
- Определяйте запросы и лимиты ресурсов (requests/limits) для Pod DaemonSet, чтобы они не конфликтовали с основными приложениями.
- Перед применением манифестов в production проверяйте их в тестовой среде. Актуальный синтаксис всегда сверяйте с официальной документацией Kubernetes.
DaemonSet решает четкий круг задач. Правильное его применение упрощает управление инфраструктурой кластера. Для комплексного подхода к администрированию Linux и Kubernetes-сред изучите наш сборник практических руководств для DevOps.