Введение
Некоторые программы должны запускаться по одному экземпляру на каждом подходящем узле, а не в фиксированном количестве реплик. Сборщики журналов, агенты мониторинга и сетевые компоненты часто используют 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, ориентированным на завершение задач.


