news 2026/8/8 22:19:41

【Kubernetes从入门到精通】第23篇:DaemonSet——每个节点都要有的“守护者“

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Kubernetes从入门到精通】第23篇:DaemonSet——每个节点都要有的“守护者“

上一篇【第22篇】StatefulSet——有状态应用的“私人管家“
下一篇【第24篇】Job和CronJob——一次性任务和定时任务


摘要

你有没有想过一个问题——10个Node的K8s集群,怎么保证每个Node上都跑着日志收集器(Filebeat)、监控Agent(Prometheus node_exporter)、网络插件(Calico)?用Deployment设replicas=10?万一调度器把两个Pod塞到同一台机器上呢?万一有台机器没分到呢?DaemonSet就是这种场景的标准答案——它保证每个符合条件的Node上都恰好运行一个Pod副本。

这篇文章从DaemonSet的典型应用场景切入,讲清楚它跟Deployment/StatefulSet的本质区别(绕过Scheduler直通kubelet),拆解RollingUpdate和OnDelete两种更新策略的差异,用NodeSelector和Toleration控制部署范围,最后实战部署一个日志收集DaemonSet和监控Agent。


一、DaemonSet的典型场景——“哪里需要哪里搬”

1.1 三大主力场景

【DaemonSet的经典应用场景】 ┌─────────────────────────────────────────────────────────────┐ │ K8s 集群(3个Node) │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Node-1 │ │ Node-2 │ │ Node-3 │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │Filebeat │ │ │ │Filebeat │ │ │ │Filebeat │ │ ← 日志收集 │ │ │收集本机日志│ │ │ │收集本机日志│ │ │ │收集本机日志│ │ │ │ │ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │node_exprt│ │ │ │node_exprt│ │ │ │node_exprt│ │ ← 监控Agent │ │ │采集本机指标│ │ │ │采集本机指标│ │ │ │采集本机指标│ │ │ │ │ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │ CNI 插件 │ │ │ │ CNI 插件 │ │ │ │ CNI 插件 │ │ ← 网络插件 │ │ │(Calico) │ │ │ │(Calico) │ │ │ │(Calico) │ │ │ │ │ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────┘ 共同特点:每个Node一个,不需要更多,不能更少

1.2 具体场景分析

场景类别典型应用为什么必须是DaemonSet
日志收集Filebeat/Fluentd每个Node上所有Pod的日志都写到Node本地磁盘,需要本地Agent把日志推送到ES/Kafka
监控AgentPrometheus node_exporter / Datadog Agent采集Node级别的指标(CPU/内存/磁盘),只能在Node本机上采集
网络插件Calico/Flannel/Cilium每个Node都需要网络代理来处理Pod网络流量
存储插件CSI Node Plugin每个Node上需要存储驱动来挂载远程存储卷
安全审计Falco/Sysdig每个Node上需要内核级事件监控
GPU管理NVIDIA device plugin有GPU的Node需要安装GPU驱动和管理插件

要点:DaemonSet的本质是"守护进程的K8s版本"。在传统运维里,你登录每台机器手动安装filebeat、node_exporter;在K8s里,一个DaemonSet YAML搞定——节点自动加入自动部署,节点离开自动清理。


二、DaemonSet的工作原理——“不走Scheduler,直通kubelet”

2.1 调度差异——DaemonSet为什么不经过Scheduler?

【Deployment调度 vs DaemonSet调度】 Deployment Pod 创建流程: DaemonSet Pod 创建流程: ┌────────────────────┐ ┌────────────────────┐ │ Deployment │ │ DaemonSet │ │ Controller │ │ Controller │ └────────┬───────────┘ └────────┬───────────┘ │ 创建Pod │ 直接指定Node ▼ ▼ ┌────────────────────┐ ┌────────────────────┐ │ Scheduler │ │ 每个Node的 │ │ ┌──────────────┐ │ │ kubelet │ │ │ 打分 → 选出 │ │ ← 跳过! │ │ │ │ 最优Node │ │ │ "来了个DaemonSet │ │ └──────────────┘ │ │ Pod,跑在我身上" │ └────────┬───────────┘ └────────────────────┘ │ 分配给某Node ▼ ┌────────────────────┐ │ kubelet 启动Pod │ └────────────────────┘ 区别: • Deployment:Pod创建后,Scheduler挑一个合适的Node • DaemonSet:每个Node上都跑一个,不需要挑——每个Node都要
# DaemonSet——基本YAMLapiVersion:apps/v1kind:DaemonSetmetadata:name:filebeatlabels:app:filebeatspec:selector:matchLabels:app:filebeattemplate:metadata:labels:app:filebeatspec:containers:-name:filebeatimage:docker.elastic.co/beats/filebeat:8.10.0volumeMounts:-name:varlogmountPath:/var/log/containersreadOnly:true-name:varlibdockercontainersmountPath:/var/lib/docker/containersreadOnly:true-name:configmountPath:/usr/share/filebeat/filebeat.ymlsubPath:filebeat.ymlvolumes:-name:varloghostPath:path:/var/log/containers-name:varlibdockercontainershostPath:path:/var/lib/docker/containers-name:configconfigMap:name:filebeat-config

2.2 新Node加入——自动部署

【DaemonSet的自动化能力】 时刻T1:集群只有2个Node ┌──────────────┐ ┌──────────────┐ │ Node-1 │ │ Node-2 │ │ [filebeat] │ │ [filebeat] │ └──────────────┘ └──────────────┘ 时刻T2:新Node加入集群 ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Node-1 │ │ Node-2 │ │ Node-3 │ │ [filebeat] │ │ [filebeat] │ │ ???? │ ← 新Node,自动部署 └──────────────┘ └──────────────┘ └──────────────┘ │ 几秒钟后自动完成 ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Node-1 │ │ Node-2 │ │ Node-3 │ │ [filebeat] │ │ [filebeat] │ │ [filebeat] │ ← 自动部署完成! └──────────────┘ └──────────────┘ └──────────────┘

要点:这是DaemonSet最让人省心的地方——不用操心节点扩容。加一个Node,DaemonSet Controller自动检测到新Node,秒级创建一个Pod上去。反过来也一样——Node下线/驱逐,DaemonSet Pod跟着清理。


三、精准控制部署范围——“不是所有Node都要”

3.1 NodeSelector——指定Node标签

apiVersion:apps/v1kind:DaemonSetmetadata:name:gpu-monitorspec:selector:matchLabels:app:gpu-monitortemplate:metadata:labels:app:gpu-monitorspec:nodeSelector:# ← 只在有GPU的Node上部署accelerator:nvidia-tesla-v100containers:-name:gpu-monitorimage:nvidia/dcgm-exporter:latest
# 给Node打标签kubectl label nodes node-1accelerator=nvidia-tesla-v100 kubectl label nodes node-2accelerator=nvidia-tesla-v100# 看效果——只有打了标签的Node上才会跑kubectl get pods-lapp=gpu-monitor-owide# NAME NODE STATUS# gpu-monitor-xxxxx node-1 Running# gpu-monitor-yyyyy node-2 Running# node-3没有这个Pod(没打标签)

3.2 NodeAffinity——更精细的调度策略

【NodeSelector vs NodeAffinity】 NodeSelector(简单): NodeAffinity(灵活): ┌──────────────────┐ ┌──────────────────────────┐ │ 只支持等于匹配 │ │ 支持 In/NotIn/Exists/ │ │ accelerator=nvidia │ │ DoesNotExist/Gt/Lt │ │ │ │ │ │ 硬性要求(必须满足) │ │ 硬性+软性(尽量满足) │ └──────────────────┘ └──────────────────────────┘
spec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:# 硬性要求nodeSelectorTerms:-matchExpressions:-key:node-role.kubernetes.io/workeroperator:Invalues:-"true"-key:disktypeoperator:Invalues:-ssdpreferredDuringSchedulingIgnoredDuringExecution:# 软性偏好-weight:100preference:matchExpressions:-key:zoneoperator:Invalues:-zone-a

3.3 Tolerations——“容忍污点”

有些Node打了"污点"(Taint),普通Pod不调度上去——但DaemonSet Pod可以通过Toleration"容忍"这些污点。

# Master/Control-Plane节点默认有污点kubectl describenodemaster-node|grepTaints# Taints: node-role.kubernetes.io/control-plane:NoSchedule# DaemonSet想跑在Master上?加Toleration:
spec:template:spec:tolerations:-key:node-role.kubernetes.io/control-planeoperator:Existseffect:NoSchedule# 容忍这个污点# 监控Agent需要跑在所有Node上——包括Master
【Taint + Toleration —— "你不嫌我脏,我就让你上"】 Node打上污点(Taint): Pod声明容忍(Toleration): ┌────────────────────────┐ ┌────────────────────────┐ │ Node: master-node │ │ Pod: monitoring-agent │ │ Taint: │ │ Toleration: │ │ control-plane: │ ←→ │ control-plane: │ │ NoSchedule │ 匹配! │ Exists │ │ │ │ │ │ "我是控制节点, │ │ "我不介意你是控制节点" │ │ 别随便往我身上调度" │ │ │ └────────────────────────┘ └────────────────────────┘

要点:Toleration是让DaemonSet"全身覆盖"的关键手段。监控Agent、日志收集器、网络插件这些基础设施通常需要跑在所有Node上——包括打了污点的Master/Control-Plane节点。如果不加Toleration,Master节点就成盲区了。

3.4 部署范围控制总结

机制作用场景举例
nodeSelector简单标签匹配只在GPU节点部署GPU监控
nodeAffinity复杂条件匹配只在SSD节点的Zone-A部署
tolerations容忍Node污点让DaemonSet跑在Master节点上

四、更新策略——“怎么安全地升级所有Node”

4.1 RollingUpdate——滚动更新(默认)

【DaemonSet RollingUpdate 流程——一个Node一个Node更新】 Node-1 [Filebeat v1] ─┬─ 删除 v1 ─┬─ 创建 v2 ─┬─ v2 Ready │ │ │ Node-2 [Filebeat v1] ─│── 等待… ──│── 删除v1 ─│── 创建v2 ─┬─ v2 Ready │ │ │ │ Node-3 [Filebeat v1] ─│── 等待… ──│── 等待… ──│── 等待… ──│── 删除v1 ─┬─ v2 Ready │ │ │ │ │ ────────────────────────┴───────────┴───────────┴───────────┴───────────┘ 一次只更新一个Node,等新Pod Ready再更新下一个
apiVersion:apps/v1kind:DaemonSetmetadata:name:filebeatspec:updateStrategy:type:RollingUpdaterollingUpdate:maxUnavailable:1# 最多一个Node不可用maxSurge:0# DaemonSet不支持surge(跟Deployment不同!)template:spec:containers:-name:filebeatimage:docker.elastic.co/beats/filebeat:8.11.0# 最新版

4.2 OnDelete——"手动挡"更新

spec:updateStrategy:type:OnDelete# 不自动更新——等你手动删Pod才更新
# OnDelete策略下:更新DaemonSet模板后,已有的Pod不会变kubectl edit daemonset filebeat# 改镜像版本# Pod还是旧版本!kubectl get pods-lapp=filebeat-ojsonpath='{.items[*].spec.containers[*].image}'# filebeat:8.10.0 filebeat:8.10.0 filebeat:8.10.0# 手动删一个Pod——它重建后变成新版本kubectl delete pod filebeat-xxxxx# 删Node-1上的# 重建后:filebeat:8.11.0# 一个一个手动删除,逐个更新——完全由你掌控节奏
策略自动化风险控制适用场景
RollingUpdate✅ 自动逐个更新maxUnavailable控制常规更新——推荐
OnDelete❌ 手动删除Pod才更新完全手动控制谨慎场景——更新前需要手动验证

要点:DaemonSet的RollingUpdate有一个重要限制——不支持maxSurge(跟Deployment不同)。原因很简单:每个Node上只能跑一个DaemonSet Pod,不能像Deployment那样"先创一个新的再删旧的"。所以DaemonSet的更新是删除旧Pod→创建新Pod,中间有短暂的空窗期。


五、实战:部署一个完整的日志收集DaemonSet

5.1 Filebeat DaemonSet——收集所有Pod日志

# ConfigMap——Filebeat配置apiVersion:v1kind:ConfigMapmetadata:name:filebeat-confignamespace:kube-systemdata:filebeat.yml:|filebeat.inputs: - type: container paths: - /var/log/containers/*.log processors: - add_kubernetes_metadata: host: ${NODE_NAME} matchers: - logs_path: logs_path: "/var/log/containers/"output.elasticsearch:hosts:['${ELASTICSEARCH_HOST:elasticsearch:9200}']index:"filebeat-%{[agent.version]}-%{+yyyy.MM.dd}"logging.level:infologging.to_files:truelogging.files:path:/var/log/filebeatname:filebeatkeepfiles:7---# DaemonSetapiVersion:apps/v1kind:DaemonSetmetadata:name:filebeatnamespace:kube-systemlabels:app:filebeatspec:selector:matchLabels:app:filebeatupdateStrategy:type:RollingUpdaterollingUpdate:maxUnavailable:1template:metadata:labels:app:filebeatspec:serviceAccountName:filebeatterminationGracePeriodSeconds:30hostNetwork:truednsPolicy:ClusterFirstWithHostNettolerations:-key:node-role.kubernetes.io/control-planeoperator:Existseffect:NoSchedulecontainers:-name:filebeatimage:docker.elastic.co/beats/filebeat:8.10.0args:-"-c"-"/usr/share/filebeat/filebeat.yml"-"-e"env:-name:ELASTICSEARCH_HOSTvalue:"elasticsearch.logging.svc.cluster.local:9200"-name:NODE_NAMEvalueFrom:fieldRef:fieldPath:spec.nodeNameresources:requests:memory:"200Mi"cpu:"100m"limits:memory:"500Mi"cpu:"200m"securityContext:runAsUser:0volumeMounts:-name:configmountPath:/usr/share/filebeat/filebeat.ymlsubPath:filebeat.yml-name:varlogmountPath:/var/log/containersreadOnly:true-name:varlibdockercontainersmountPath:/var/lib/docker/containersreadOnly:true-name:datamountPath:/usr/share/filebeat/datavolumes:-name:configconfigMap:name:filebeat-configdefaultMode:0644-name:varloghostPath:path:/var/log/containers-name:varlibdockercontainershostPath:path:/var/lib/docker/containers-name:datahostPath:path:/var/lib/filebeat-datatype:DirectoryOrCreate---# RBAC——Filebeat需要读取K8s API获取Pod元数据apiVersion:v1kind:ServiceAccountmetadata:name:filebeatnamespace:kube-system---apiVersion:rbac.authorization.k8s.io/v1kind:ClusterRolemetadata:name:filebeatrules:-apiGroups:[""]resources:["pods","namespaces"]verbs:["get","list","watch"]---apiVersion:rbac.authorization.k8s.io/v1kind:ClusterRoleBindingmetadata:name:filebeatsubjects:-kind:ServiceAccountname:filebeatnamespace:kube-systemroleRef:kind:ClusterRolename:filebeatapiGroup:rbac.authorization.k8s.io

5.2 Prometheus node_exporter——每个Node的监控Agent

apiVersion:apps/v1kind:DaemonSetmetadata:name:node-exporternamespace:monitoringlabels:app:node-exporterspec:selector:matchLabels:app:node-exporterupdateStrategy:type:RollingUpdaterollingUpdate:maxUnavailable:1template:metadata:labels:app:node-exporterspec:hostNetwork:true# 直接使用Node网络hostPID:true# 访问Node的进程信息tolerations:-operator:Exists# 容忍所有污点containers:-name:node-exporterimage:prom/node-exporter:v1.7.0args:---path.procfs=/host/proc---path.sysfs=/host/sys---path.rootfs=/host/root---collector.filesystem.mount-points-exclude=^/(dev|proc|sys|var/lib/docker/.+)($|/)---collector.filesystem.fs-types-exclude=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefds|securityfs|sysfs|tracefs)$ports:-containerPort:9100hostPort:9100name:metricsvolumeMounts:-name:procmountPath:/host/procreadOnly:true-name:sysmountPath:/host/sysreadOnly:true-name:rootmountPath:/host/rootreadOnly:truemountPropagation:HostToContainervolumes:-name:prochostPath:path:/proc-name:syshostPath:path:/sys-name:roothostPath:path:/
# 部署验证kubectl apply-fnode-exporter-daemonset.yaml# 看——每个Node一个Podkubectl get pods-nmonitoring-lapp=node-exporter-owide# NAME NODE STATUS# node-exporter-abc12 master-node Running# node-exporter-def34 worker-node-1 Running# node-exporter-ghi56 worker-node-2 Running# 测试metrics接口kubectlexec-nmonitoring node-exporter-abc12 --wget-qO- http://localhost:9100/metrics|head

要点:node_exporter需要直接访问Node的/proc/sys文件系统——这些是宿主机的数据,不是Pod内部的。所以用hostPath挂载,而且设置了hostNetwork: truehostPID: true让Pod直接使用宿主机的网络和进程命名空间。securityContext里需要privileged: true或者特定的capabilities才能访问内核数据。


六、DaemonSet常用命令和调试

# 查看所有DaemonSetkubectl get daemonset --all-namespaces# 查看某个DaemonSet详情kubectl describe daemonset filebeat-nkube-system# 看每个Node上的DaemonSet Pod分布kubectl get pods-nkube-system-lapp=filebeat-owide# 查看DaemonSet状态——关键字段kubectl get daemonset filebeat-nkube-system# NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR# filebeat 3 3 3 3 3 <none>## DESIRED: 应该运行Pod的Node数(符合条件的所有Node)# CURRENT: 当前运行的Pod数# READY: 就绪的Pod数# 滚动更新kubectlsetimage daemonset/filebeatfilebeat=filebeat:8.11.0-nkube-system# 查看更新进度kubectl rollout status daemonset/filebeat-nkube-system# 回滚到上一个版本kubectl rollout undo daemonset/filebeat-nkube-system# 查看更新历史kubectl rollouthistorydaemonset/filebeat-nkube-system
# 调试——为什么某些Node上没有DaemonSet Pod?kubectl get nodes --show-labels# 检查Node标签是否匹配nodeSelectorkubectl describenode<node-name>|grepTaints# 检查Taint是否被Toleration覆盖kubectl get events-nkube-system --field-selectorinvolvedObject.name=<daemonset-pod-name># 看事件日志定位调度失败原因

本篇小结

DaemonSet是K8s里最"自动化"的资源控制器:

  1. 核心价值:保证每个符合条件的Node上正好跑一个Pod,不多不少——Node加入自动部署,Node离开自动清理
  2. 三大场景:日志收集(Filebeat/Fluentd)、监控Agent(node_exporter/Datadog)、基础设施(CNI/CSI)
  3. 调度差异:绕过Scheduler直通kubelet——因为不需要"选Node",每个Node都要
  4. 部署控制:NodeSelector简单筛选,NodeAffinity复杂匹配,Toleration容忍污点覆盖Master节点
  5. 更新策略:RollingUpdate逐个替换(不支持maxSurge),OnDelete手动掌控节奏
  6. 安全要点:DaemonSet Pod通常需要特权访问(hostPath/hostNetwork),RBAC和securityContext要配好

下一篇咱们聊Job和CronJob——一次性任务和定时任务。数据库备份、数据清洗、批量处理这些"跑完就停"的任务在K8s里怎么搞?


上一篇【第22篇】StatefulSet——有状态应用的“私人管家“
下一篇【第24篇】Job和CronJob——一次性任务和定时任务


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/8 22:19:18

提升MiniMax-H3-Turbo-Lora-ComfyUI生成质量的10个实用技巧

PointNet多GPU训练指南&#xff1a;如何高效利用计算资源加速模型训练 【免费下载链接】pointnet2 PointNet: Deep Hierarchical Feature Learning on Point Sets in a Metric Space 项目地址: https://gitcode.com/gh_mirrors/po/pointnet2 PointNet是一个基于深度学习…

作者头像 李华
网站建设 2026/8/8 22:11:38

VimGolf终极指南:如何通过游戏化训练成为Vim编辑器高手

VimGolf终极指南&#xff1a;如何通过游戏化训练成为Vim编辑器高手 【免费下载链接】vimgolf Real Vim ninjas count every keystroke - do you? 项目地址: https://gitcode.com/gh_mirrors/vi/vimgolf 你想成为真正的Vim编辑器高手吗&#xff1f;VimGolf是一个创新的在…

作者头像 李华
网站建设 2026/8/8 22:07:37

如何3步完成配置?Bililive-go直播录制工具的快速入门秘籍

如何3步完成配置&#xff1f;Bililive-go直播录制工具的快速入门秘籍 【免费下载链接】bililive-go 一个直播录制工具 项目地址: https://gitcode.com/gh_mirrors/bi/bililive-go 你是否经常错过心爱主播的直播&#xff1f;Bililive-go就是你一直在寻找的直播录制神器&a…

作者头像 李华