DaemonSet — удобный способ гарантировать, что нужный под запустится на каждом узле кластера. В этой статье разберём, когда и как использовать DaemonSet, какие есть подводные камни и какие приёмы помогают управлять развертыванием надёжно и предсказуемо.

Что такое DaemonSet и зачем он нужен

DaemonSet — это объект Kubernetes, который обеспечивает создание копии пода на каждом подходящем узле кластера. В отличие от Deployment, который масштабируется количеством реплик, DaemonSet ориентирован на «по одному на узел» и служит для задач, тесно связанных с инфраструктурой.

Типичные примеры — агент мониторинга, сборщик логов, сетевой плагин и службы безопасности, которые должны присутствовать локально. Такой подход упрощает доступ к node-level ресурсам — сетевым интерфейсам, файловой системе узла и метаданным хоста.

Поведение DaemonSet в кластере

Когда вы создаёте DaemonSet, контроллер наблюдает за списком нод и создаёт под на каждой ноде, соответствующей селекторам и допускающей запуск. Новые узлы автоматически получают под, а при удалении ноды соответствующие поды удаляются вместе с ней.

Важно понимать, что Kubernetes не гарантирует синхронного запуска на всех узлах одновременно. Кроме того, DaemonSet наследует политики обновления и ограничения пода: если узел помечен как unschedulable, новый под на нём не появится до изменения статуса.

Типичные сценарии использования

DaemonSet хорошо подходит для сервисов, которые работают локально и требуют доступа к ресурсам узла. Ниже перечислены самые распространённые случаи.

  • Сбор логов и метрик: Fluentd, Filebeat, node-exporter.
  • Сетевые компоненты: CNI-плагины, прокси с hostNetwork.
  • Инструменты безопасности: агенты IDS/IPS, сканеры целостности.
  • Утилиты обслуживания: резервное копирование узлов, прокси для доступа к локальным устройствам.

Я сам несколько раз разворачивал Fluentd через DaemonSet в продакшене: однажды пришлось учитывать, что у некоторых узлов ограничено disk I/O. Приходилось ставить request/limit и отдельные nodeSelector, чтобы отправлять более «тяжёлые» агенты только на узлы с нужными характеристиками.

Пример простого DaemonSet

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

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: my-log-agent
spec:
  selector:
    matchLabels:
      name: my-log-agent
  template:
    metadata:
      labels:
        name: my-log-agent
    spec:
      serviceAccountName: log-agent-sa
      containers:
      - name: agent
        image: myregistry/log-agent:1.0
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
          type: Directory

Важные моменты: hostPath позволяет агенту читать логи с узла, serviceAccount даёт внешние права, а селектор matchLabels связывает DaemonSet с подами. В реальной ситуации добавьте securityContext и ресурсы для контроля безопасности и потребления.

Стратегии обновления и управление релизами

DaemonSet поддерживает поле updateStrategy, которое задаёт поведение при обновлении образа. Возможны режимы RollingUpdate и OnDelete. В RollingUpdate можно ограничить скорость обновления через maxUnavailable, чтобы не перегрузить инструментарий или сеть.

При использовании RollingUpdate контролируйте совместимость версии агента: если новая версия требует изменения hostPath или права, учтите откат. Я рекомендую сначала тестировать на отдельной группе узлов через nodeSelector, а затем переключать весь DaemonSet.

Как управлять распределением по узлам

По умолчанию поды создаются на всех nодах, но это поведение можно корректировать с помощью nodeSelector, nodeAffinity и tolerations. Они позволяют исключать узлы с особыми ролями или запускать агенты только там, где есть нужные ресурсы.

Применение taints и tolerations помогает предотвратить запуск системных подов на нодах с критическими задачами или выделенными ролями. Часто удобно пометить узлы с high-IO и направлять тяжёлые агрегаторы туда, оставив lightweight-агенты на остальных.

Частые ошибки и способы их решения

При работе с DaemonSet можно столкнуться с несколькими повторяющимися проблемами: контейнеры не стартуют из-за прав доступа, конфликты портов на хосте при hostPort, и проблемы с SELinux или AppArmor при использовании hostPath.

Ниже — краткая таблица с распространёнными проблемами и мерами по их устранению.

Проблема Причина Решение
Поды не запускаются на некоторых нодах taint/taint mismatch или нода unschedulable Добавить tolerations или снять taint; проверить статусы нод
Конфликт портов нескольким подам нужен тот же hostPort перенести на hostNetwork или назначить разные порты; использовать DaemonSet только там, где порты свободны
Проблемы с доступом к файловой системе SELinux/AppArmor, неправильный hostPath type проверить контекст безопасности, использовать securityContext и правильные типы hostPath

Безопасность и ограничения прав

Поды DaemonSet часто требуют повышенных прав для доступа к хосту, и это создаёт риск. Не торопитесь давать привилегии: сначала попробуйте минимальный набор прав и сервисный аккаунт с конкретными разрешениями.

Используйте securityContext для ограничения возможностей контейнера, например запрещайте привилегированные режимы, если в них нет объективной необходимости. Там, где нужен доступ к ядру или NET_ADMIN, документируйте причины и минимизируйте объем прав.

Наблюдение и отладка

Для контроля статуса DaemonSet полезны команды kubectl get daemonset и kubectl describe daemonset. Они показывают, сколько подов должно быть и сколько фактически готово. Для проверки конкретного узла используйте kubectl get pods -o wide и фильтр по ноде.

Логи подов остаются основным источником информации о проблемах запуска. Если агент не видит локальные ресурсы, сначала проверьте монтирование volume и затем права доступа на хосте. В нескольких случаях мне помогло сравнение окружения успешного и неуспешного узла через ssh и просмотр /var/log/syslog.

Практическая проверка перед вводом в эксплуатацию

Перед масштабированием на весь кластер выполните серию тестов: разверните DaemonSet на тестовой группе нод, проверьте обновление через RollingUpdate, имитируйте отказ узла и оцените восстановление. Это уменьшит вероятность сюрпризов в продакшене.

Важно также отслеживать потребление ресурсов и сетевой трафик. Агент, работающий на каждом узле, может в сумме создать значительную нагрузку. Наглядное правило — измерить baseline и учесть его при планировании ресурсов кластера.

Внедрение и масштабирование: практический план

Реальная последовательность внедрения может выглядеть так: подготовка образа с минимальными правами, тестирование на выделенных нодах, настройка updateStrategy и мониторинга, запуск на всех узлах с последующей ревизией метрик. Такой подход снижает риск ошибок и позволяет быстро откатиться при необходимости.

Когда всё отлажено, автоматизируйте процесс через CI/CD: сборка образов, проверка манифестов и применение в несколько этапов. Это гарантирует предсказуемость и помогает избежать ручных действий, которые обычно приводят к ошибкам в конфигурации.