Развертывание сервисов на узлах с помощью DaemonSet в Kubernetes

KubernetesBeginner
Практиковаться сейчас

Введение

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

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

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

Пометить подходящий узел

На этом шаге вы добавите узлу специальную метку. Метки описывают атрибуты узлов, по которым контроллеры могут выбирать подходящие узлы.

Сначала просмотрите узел и уже существующие метки. Вывод будет довольно широким, поэтому запоминать его не нужно. Достаточно понять, что метки — это пары «ключ–значение», прикреплённые к объекту Node.

cd /home/labex/project/daemonset-workloads
kubectl get nodes --show-labels

Добавьте новую метку. Параметр --overwrite здесь не требуется, поскольку подготовка среды удалила старое значение. Однако kubectl label сообщит о наличии конфликтующего значения, если оно уже существует:

kubectl label node labex-v135 practice-tier=operations
kubectl get node labex-v135 -L practice-tier

Параметр -L practice-tier добавляет эту метку в качестве столбца таблицы. Теперь узел сообщает, что подходит для агента операционного мониторинга.

Вторая команда выводит только нужную информацию вместо очень длинной строки с --show-labels:

NAME         STATUS   ROLES           VERSION   PRACTICE-TIER
labex-v135   Ready    control-plane   v1.35.5   operations

Наличие PRACTICE-TIER=operations подтверждает, что всё выполнено правильно. Сама по себе метка ничего не запускает; значение она приобретёт на следующем шаге, когда рабочая нагрузка начнёт использовать её при выборе узлов.

Развернуть DaemonSet

На этом шаге вы создадите DaemonSet, который выбирает узлы с добавленной меткой.

Перед вводом манифеста рассмотрите его как три связанных решения. Селектор и метка Pod используют app: node-reporter, благодаря чему контроллер может распознавать принадлежащие ему Pod. Затем nodeSelector ограничивает выбор узлами с меткой practice-tier=operations. Наконец, Downward API передаёт значение spec.nodeName выбранного Pod в контейнер через переменную NODE_NAME.

Цикл поддерживает демонстрационный агент в рабочем состоянии. В реальном DaemonSet вместо него мог бы работать сборщик журналов или агент мониторинга.

cat <<'EOF' > node-reporter.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-reporter
  namespace: practice-daemon
spec:
  selector:
    matchLabels:
      app: node-reporter
  template:
    metadata:
      labels:
        app: node-reporter
    spec:
      nodeSelector:
        practice-tier: operations
      containers:
        - name: reporter
          image: busybox:1.36
          imagePullPolicy: IfNotPresent
          command: ["sh", "-c", "while true; do echo node=${NODE_NAME} version=v1; sleep 15; done"]
          env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
EOF

Создайте пространство имён, примените файл и дождитесь завершения развёртывания DaemonSet:

kubectl create namespace practice-daemon
kubectl apply -f node-reporter.yaml
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s
kubectl get daemonset,pods -n practice-daemon -o wide

Downward API через fieldRef предоставляет имя запланированного узла без его жёсткого задания в конфигурации. В этом одноузловом кластере желаемое, текущее и готовое количество должно быть равно единице.

Имя Pod содержит сгенерированный суффикс, но в столбце NODE должно отображаться labex-v135. Это напрямую подтверждает, что правило выбора узла и результат планирования согласуются.

В тестовом кластере с одним узлом важные столбцы выглядели так:

NAME            DESIRED   CURRENT   READY   NODE SELECTOR
node-reporter   1         1         1       practice-tier=operations

NAME                  READY   STATUS    NODE
node-reporter-...      1/1     Running   labex-v135

Читайте первую строку слева направо: один узел соответствует селектору, один Pod создан, и этот Pod готов. В более крупном кластере значения увеличивались бы пропорционально числу подходящих узлов.

Наблюдать соответствие узла и владение Pod

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

Сначала зафиксируйте состояние исправной системы. Пользовательские столбцы связывают сгенерированный Pod с DaemonSet, а журналы подтверждают, что Downward API передал имя узла:

kubectl get pods -n practice-daemon -l app=node-reporter -o custom-columns='POD:.metadata.name,NODE:.spec.nodeName,OWNER:.metadata.ownerReferences[0].kind,READY:.status.containerStatuses[0].ready'
kubectl logs -n practice-daemon -l app=node-reporter --tail=3

Таблица владения и журналы должны выглядеть примерно так:

POD                   NODE         OWNER       READY
node-reporter-...     labex-v135   DaemonSet   true
node=labex-v135 version=v1

Поле OWNER подтверждает, что Pod управляется контроллером. Журнал показывает, что NODE_NAME получен из фактического spec.nodeName Pod, а не задан в конфигурации вручную.

Временно удалите метку и проследите, как Pod исчезнет:

kubectl label node labex-v135 practice-tier-
kubectl get daemonset node-reporter -n practice-daemon
kubectl wait --for=delete pod -n practice-daemon -l app=node-reporter --timeout=60s

Завершающий символ - удаляет ключ метки. Восстановите соответствие узла и дождитесь, пока контроллер создаст новый Pod:

После удаления метки DaemonSet некоторое время будет показывать следующее устойчивое состояние:

NAME            DESIRED   CURRENT   READY
node-reporter   0         0         0

Это штатная реакция на изменение соответствия, а не ошибка. Сейчас ни один узел не соответствует nodeSelector DaemonSet, поэтому правильное желаемое количество равно нулю.

kubectl label node labex-v135 practice-tier=operations
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s

Сравните имя Pod до и после изменения метки. Новый Pod получает другую идентичность, а имя DaemonSet и желаемое поведение остаются прежними. Так проявляется процесс согласования фактического состояния с желаемым.

Выполнить обновление DaemonSet

На этом шаге вы обновите сохранённый манифест и увидите, как DaemonSet заменит агент на узле. Согласованность файла с объектом в кластере делает желаемое состояние воспроизводимым.

Сначала создайте рабочую копию с помощью cp. Затем примените тот же точечный способ редактирования текста, который использовался в курсе Kubernetes для начинающих: sed -i 's/old/new/' file напрямую заменяет совпадающий текст в файле, а grep -n выводит найденную строку вместе с её номером, чтобы можно было проверить результат перед применением.

cp node-reporter.yaml node-reporter-v2.yaml
sed -i 's/version=v1/version=v2/' node-reporter-v2.yaml
grep -n 'version=' node-reporter-v2.yaml
kubectl apply -f node-reporter-v2.yaml
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s
kubectl rollout history daemonset/node-reporter -n practice-daemon
kubectl logs -n practice-daemon -l app=node-reporter --tail=3

Скопированный файл сохраняет исходный пример с v1 для сравнения. Единственная замена изменяет текст версии внутри команды контейнера. Применение обновлённого файла меняет шаблон Pod, создаёт новую ревизию контроллера и приводит к замене Pod. Теперь в журналах должна появиться строка version=v2.

Команда rollout history подтверждает, что Kubernetes зарегистрировал новую ревизию. Таким образом, DaemonSet поддерживает управляемые обновления шаблона подобно Deployment, однако замена организуется вокруг подходящих узлов, а не количества реплик.

Проверенный вывод содержал две ревизии и новое сообщение журнала:

REVISION  CHANGE-CAUSE
1         <none>
2         <none>

node=labex-v135 version=v2

CHANGE-CAUSE=<none> означает лишь, что понятная человеку аннотация причины изменения не была записана. Ревизия 2 и version=v2 в журнале заменённого Pod — достаточные подтверждения того, что обновление выполнено.

Итоги

Вы использовали метки узлов для управления соответствием DaemonSet, наблюдали согласование по правилу «один Pod на каждый подходящий узел», проследили владение Pod контроллером и выполнили обновление агента узла. Теперь вы можете сравнить DaemonSet с Deployment, ориентированным на количество реплик, и Job, ориентированным на завершение задач.