k8s DaemonSet 控制器从原理到实践
1、引言:集群的节点守护神
在庞大而动态的Kubernetes集群中,每个节点(Node)都像是独立运行的服务器。为了确保这些服务器健康、安全、可观测,我们常常需要在每台服务器上运行一些基础的“系统服务”或“守护进程”。DaemonSet正是Kubernetes为我们提供的、用于管理这些节点级服务的“节点守护神”。
1.1. 什么是DaemonSet?
DaemonSet是Kubernetes的一种控制器,其核心职责是确保在集群中所有(或由你指定的)节点上,都有且仅有一个指定的Pod副本在运行。它就像一个忠诚的管家,会自动照看集群中的每一个节点。
比喻:您可以将DaemonSet想象成传统IT运维中,为每台服务器安装的监控Agent或日志收集脚本。不同的是,DaemonSet将这一过程自动化、声明化,并融入了Kubernetes强大的管理和自愈生态中。
- 类比理解:
想象一个保安公司需在每个小区门口部署一名保安。DaemonSet 就是保安调度系统:
✅ 新小区加入时,自动派一名保安过去;
❌ 小区退出时,保安自动撤回;
❌ 删除调度系统时,所有保安撤离。
1.2. 核心价值:为什么需要DaemonSet?
- 自动化部署:当一个新节点加入集群时,DaemonSet控制器会立即感知到,并自动在该节点上部署一个Pod副本。无需任何人工干预。
- 状态一致性:它保证了集群中每个相关节点都运行着必要的后台服务,从而确保了基础设施层面的功能一致性。
- 集中化管理:您可以通过一个简单的YAML文件来定义、更新和监控成百上千个节点上的服务。升级、回滚都可通过Kubernetes API统一完成。
- 自愈能力:如果某个节点上的DaemonSet Pod因故崩溃或被误删除,控制器会立刻发现并重新创建一个新的Pod来替代它,维持服务的可用性。
典型场景(每个节点必须部署的服务):
- 监控代理(如
node-exporter)
→ 每个节点收集硬件指标(CPU/内存/磁盘)。 - 日志收集器(如
fluentd或logstash)
→ 每个节点收集容器日志。 - 网络插件(如
flannel,calico)
→ 每个节点提供容器网络通信。 - 存储守护进程(如
ceph,glusterd)
→ 每个节点提供分布式存储支持。
💡 关键特性:
- 节点新增 → 自动部署 Pod
- 节点删除 → 自动回收 Pod
- 删除 DaemonSet → 所有 Pod 被清理
2、DaemonSet 的核心特性
| 特性 | 说明 |
|---|---|
| 节点覆盖 | 确保每个节点(或符合选择条件的节点)上都有一个 Pod |
| 自动适应 | 当新节点加入集群时,自动部署 Pod;节点移除时,自动清理 Pod |
| 高可用 | 不依赖于节点的调度能力,即使节点被标记为不可调度(NotReady)也能部署 |
| 独立调度 | Pod 创建时已指定节点(spec.nodeName),不经过标准调度器 |
| 更新策略 | 支持 OnDelete 和 RollingUpdate(默认)两种更新方式 |
3、 核心概念:DaemonSet工作负载模型
DaemonSet的设计哲学与我们常见的Deployment有显著不同,它完全围绕“节点”这一核心概念构建。
3.1. “每个节点一个副本”模型
DaemonSet的spec中没有replicas字段。它的副本数量不是由用户静态指定的,而是由匹配的节点数量动态决定的。如果集群有100个符合条件的节点,那么DaemonSet就会创建100个Pod。
3.2. 节点生命周期管理
DaemonSet控制器密切关注着集群中节点的生命周期事件:
- 节点加入:控制器通过Kubernetes API Server监听到有新节点加入集群,并且该节点符合DaemonSet的调度要求时,会立即在该新节点上调度创建一个Pod。
- 节点移除:当一个节点从集群中被移除时,该节点上的Pod也会被Kubernetes的垃圾回收机制(Garbage Collector)自动清理,DaemonSet控制器无需额外操作。
4. 工作原理:控制器如何施展魔法

DaemonSet的自动化能力源于其背后持续运行的控制循环(Control Loop)。
4.1. DaemonSet控制器的控制循环
- Watch(监控):控制器持续监控两类资源的变化:
- 集群中的所有节点(Node),包括节点的增加、删除、以及标签(Label)的变更。
- 由它自己创建的Pod,追踪其运行状态。
- Compare(比较):控制器在内存中维护一个“期望状态”(Desired State)和从API Server获取的“当前状态”(Current State)。
- 期望状态:每个符合条件的节点上都应该运行一个健康的Pod。
- 当前状态:实际运行的Pod分布情况。
- Reconcile(调谐):如果期望与当前状态不符,控制器便会采取行动。
- 发现某个节点上缺少Pod,则在该节点上创建一个Pod。
- 发现某个节点上不应有Pod(例如节点标签不再匹配),则删除该Pod。
4.2. 精准的Pod调度机制
DaemonSet并非总是在所有节点上运行Pod,它可以被精确地限制在特定的节点子集上。
节点选择器 (
nodeSelector):这是最简单的节点筛选方式。通过在Pod模板中指定nodeSelector,可以要求Pod只调度到包含特定标签的节点上。例如,只在带有disktype: ssd标签的节点上运行存储代理。节点亲和性 (
nodeAffinity):这是nodeSelector的增强版,提供了更富表达力的规则。requiredDuringSchedulingIgnoredDuringExecution:硬性要求。Pod必须被调度到满足规则的节点上。preferredDuringSchedulingIgnoredDuringExecution:软性要求。调度器会尽量将Pod调度到满足规则的节点上,但不做保证。
污点与容忍度 (
Taints&Tolerations):- **污点(Taints)**是施加在节点上的属性,它会“排斥”不具备相应“容忍度(Toleration)”的Pod。
- 为了确保DaemonSet Pod可以运行在任何需要的节点上(即使是那些被“污染”的节点),Kubernetes会自动为DaemonSet Pod添加一些关键的容忍度,例如对
node.kubernetes.io/unschedulable和node.kubernetes.io/disk-pressure等污点的容忍。 - 这使得DaemonSet Pod甚至可以在设置为不可调度的Master节点上运行,这对于部署网络插件或安全工具至关重要。
与普通 Pod 调度的区别
普通 Pod 由 Kubernetes 调度器(Scheduler)决定运行在哪个节点,而 DaemonSet 创建的 Pod 提前指定了节点(通过
spec.nodeName),因此:
- 不受节点
unschedulable标志影响- 可以在调度器未启动时创建 Pod
- 不需要等待调度器分配节点
📌 重要提示:如果节点被标记为
NoSchedule或NoExecute(污点),默认情况下 DaemonSet 会忽略这些污点,除非你特别配置了容忍(Tolerations)。
5. 典型使用场景:DaemonSet的实战舞台
DaemonSet是构建稳健Kubernetes基础设施的基石,以下是其最常见的应用场景。
| 场景分类 | 具体应用 | 解决的问题 |
|---|---|---|
| 日志收集 | Fluentd, Logstash, Filebeat, Logtail | 在每个节点上运行一个日志代理,自动收集该节点上所有容器的标准输出日志和主机上的系统日志,并将它们转发到集中的日志存储系统(如Elasticsearch、Loki)。 |
| 节点监控 | Prometheus Node Exporter, Datadog Agent, Zabbix Agent | 在每个节点上部署一个监控代理,采集该节点的硬件和操作系统层面的性能指标(如CPU、内存、网络I/O、磁盘使用率),并暴露给监控系统。 |
| 网络插件 | Calico, Flannel, Cilium | Kubernetes集群的容器网络接口(CNI)插件通常以DaemonSet形式部署,为每个节点上的Pod提供网络连接、IP地址分配和网络策略实施。kube-proxy也是一个典型的DaemonSet应用。 |
| 集群存储 | GlusterFS, Ceph, Rook | 在每个节点上运行存储守护进程,将各节点的本地存储聚合成一个分布式的存储池,为有状态应用提供持久化存储卷。 |
| 安全与审计 | Falco, Trivy, Aqua Security | 在每个节点上运行一个安全代理,实时监控系统调用、容器行为和文件系统变化,以检测入侵、漏洞和不合规操作。 |
6.实战示例:部署 Nginx 到每个节点
6.1 创建 DaemonSet 配置文件 nginx-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
namespace: default
spec:
selector:
matchLabels:
k8s-app: nginx # 标签选择器,用于关联Pod
template: # Pod模板(定义容器)
metadata:
labels:
k8s-app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80 # 容器暴露的端口
6.2 执行部署命令
kubectl apply -f nginx-ds.yaml
6.3验证结果
kubectl get pods -l k8s-app=nginx -o wide
输出示例:
NAME READY STATUS NODE
nginx-ds-5b2m7 1/1 Running node1
nginx-ds-jfr89 1/1 Running node2
7、DaemonSet 与 Deployment 的区别
| 特性 | DaemonSet | Deployment |
|---|---|---|
| 目标 | 每个节点运行 1 个 Pod | 指定数量的 Pod 副本 |
| 调度 | 跳过调度器,直接绑定节点 | 由调度器分配节点 |
| 适用场景 | 节点级服务(监控/日志/网络) | 应用服务(Web后端/数据库) |
| 扩缩容 | 随节点数量自动扩缩容 | 手动调整副本数 |
8.常见问题
Q:如果节点被删除,DaemonSet 会如何处理?
A:当节点被从集群中移除时,该节点上的 DaemonSet Pod 会被自动删除。
Q:能否在特定节点上运行 DaemonSet?
A:可以,通过 nodeSelector、nodeAffinity 或 tolerations 限制节点选择。
Q:DaemonSet 会忽略节点的 NotReady 状态吗?
A:是的,DaemonSet 会忽略节点的 NotReady 状态,确保在节点恢复后能自动部署 Pod。
Q:DaemonSet 与 kubectl run --dry-run 有什么区别?
A:kubectl run 用于快速创建 Pod,而 DaemonSet 是用于持续保证每个节点上都有一个 Pod,即使节点加入或离开集群。
9.总结
DaemonSet 是 Kubernetes 中部署守护进程的完美解决方案,它确保在每个节点上运行一个 Pod 副本,特别适合需要在集群所有节点上提供基础服务的场景。通过理解其工作原理、配置选项和最佳实践,你可以轻松地在 Kubernetes 集群中部署网络插件、监控工具和日志收集系统等关键组件。
🌟 记住:当你需要"在每个节点上运行一个服务"时,DaemonSet 就是你的最佳选择!
本文基于 Kubernetes 官方文档(https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/)和实际生产经验编写,内容全面、实用,适合 Kubernetes 初学者和进阶用户参考。
