在 Kubernetes 中,DaemonSet 是一种专门用于在集群所有节点(或指定节点)上运行相同 Pod 副本 的工作负载控制器。它的核心特点是:只要节点存在于集群中,DaemonSet 就会确保该节点上有且仅有一个对应 Pod 在运行(新节点加入时自动部署,节点移除时自动清理),非常适合运行 "节点级服务"。
下面从 "为什么需要 DaemonSet"→核心特性→关键配置→实操案例→与 Deployment 的区别 逐步讲解,帮你快速掌握。
1 为什么需要 DaemonSet?
有些服务必须在集群的每个节点上运行(或指定节点),比如:
- 日志收集:如 Fluentd、Logstash,需要在每个节点上收集容器日志。
- 监控代理:如 Prometheus Node Exporter,需要在每个节点上采集节点指标(CPU、内存等)。
- 网络插件:如 Calico、Flannel,需要在每个节点上运行以提供网络功能。
- 存储插件:如 Ceph 客户端,需要在节点上运行以挂载分布式存储。
这些服务的核心需求是 "覆盖集群所有节点 ",而普通的 Deployment(通过replicas
指定副本数)无法满足:
- 若集群节点数量变化(新增 / 删除节点),Deployment 不会自动调整副本分布(可能导致新节点上没有服务,旧节点上有多个)。
- 无法保证 "每个节点只运行一个副本"(Deployment 可能在一个节点上调度多个 Pod)。
DaemonSet 正是为解决这些问题设计的 ------ 它直接与节点绑定,确保 "节点在,Pod 在;节点不在,Pod 清"。
2 DaemonSet 的核心特性(必懂)
- 节点全覆盖 :默认在集群所有节点上运行一个 Pod 副本(可通过配置限制在特定节点)。
- 自动扩缩容:
- 新节点加入集群时,DaemonSet 自动在新节点上创建 Pod。
- 节点从集群移除时,DaemonSet 自动删除该节点上的 Pod。
- 单节点单副本:每个节点上最多运行一个该 DaemonSet 的 Pod(避免资源浪费或冲突)。
- 更新策略:支持滚动更新(默认)或替换更新,确保节点级服务升级时不中断。
3 DaemonSet 的关键配置(核心属性)
定义 DaemonSet 时,核心是控制 "哪些节点运行 Pod" 和 "如何更新 Pod",关键配置如下:
3.1 节点选择:控制 Pod 运行在哪些节点
通过以下配置限制 Pod 仅在符合条件的节点上运行(默认无限制,所有节点均运行):
配置项 | 作用 | 示例 |
---|---|---|
spec.template.spec.nodeSelector |
节点标签选择器(仅在带指定标签的节点上运行) | disk: ssd (仅在有disk=ssd 标签的节点上运行) |
spec.template.spec.affinity.nodeAffinity |
更复杂的节点亲和性规则(如 "排除某类节点""优先选某类节点") | 见下文示例 |
spec.template.spec.tolerations |
容忍节点污点(允许 Pod 运行在有污点的节点上,如 master 节点) | 见下文示例 |
3.2 更新策略:控制 Pod 如何升级
当 DaemonSet 的 Pod 模板(spec.template
)更新时(如镜像版本变更),通过updateStrategy
控制更新方式:
策略类型 | 作用 | 适用场景 |
---|---|---|
RollingUpdate (默认) |
逐个节点更新:先删除旧 Pod,再创建新 Pod,确保服务不中断 | 生产环境(需持续提供服务) |
OnDelete |
仅在手动删除旧 Pod 后,才会创建新 Pod(需手动触发更新) | 测试环境(需严格控制更新时机) |
4 实操案例:部署一个 DaemonSet(监控节点指标)
以 "在所有节点上运行 Prometheus Node Exporter(监控节点指标)" 为例,完整步骤如下:
步骤 1:创建 DaemonSet
yaml
# 保存为daemonset-node-exporter.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter # DaemonSet名称
namespace: monitoring # 放在monitoring命名空间
spec:
selector:
matchLabels:
app: node-exporter # 匹配Pod的标签
template:
metadata:
labels:
app: node-exporter # Pod标签
spec:
hostNetwork: true # 使用节点网络(方便采集主机端口指标)
hostPID: true # 允许访问节点的PID命名空间(方便采集进程指标)
# 容忍master节点的污点(默认master节点有污点,阻止普通Pod调度)
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
operator: Exists
# 节点选择器(可选:仅在有"monitor=yes"标签的节点上运行)
# nodeSelector:
# monitor: "yes"
containers:
- name: node-exporter
image: prom/node-exporter:v1.5.0 # 监控镜像
args:
- --path.procfs=/host/proc # 挂载节点的proc目录
- --path.sysfs=/host/sys # 挂载节点的sys目录
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc # 节点的/proc目录
- name: sys
hostPath:
path: /sys # 节点的/sys目录
# 更新策略:滚动更新(默认)
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 最多允许1个节点的Pod不可用(控制更新速度)
步骤 2:部署并验证
bash
# 创建命名空间(如果不存在)
kubectl create namespace monitoring
# 部署DaemonSet
kubectl apply -f daemonset-node-exporter.yaml
# 查看DaemonSet
kubectl get daemonset -n monitoring
# 输出示例(DESIRED和CURRENT等于节点数):
# NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
# node-exporter 3 3 3 3 3 <none> 1m
# 查看Pod(每个节点上有一个,NAME包含节点名)
kubectl get pods -n monitoring -o wide
# 输出示例(3个节点,3个Pod,分别运行在不同节点):
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
# node-exporter-2f4x9 1/1 Running 0 1m 10.244.1.5 k8s-node-1 <none>
# node-exporter-5k7d3 1/1 Running 0 1m 10.244.2.3 k8s-node-2 <none>
# node-exporter-8s9z7 1/1 Running 0 1m 10.244.0.6 k8s-master <none> # 因为配置了tolerations,所以master节点也有
步骤 3:验证 "自动适应节点变化"
- 新增节点 :向集群添加一个新节点(如
k8s-node-3
),等待几分钟后查看 Pod,会发现自动新增node-exporter-xxx
运行在k8s-node-3
上。 - 删除节点 :从集群移除
k8s-node-2
,查看 Pod,node-exporter-5k7d3
会自动被删除。
5 DaemonSet vs Deployment(核心区别)
特性 | DaemonSet | Deployment |
---|---|---|
副本调度目标 | 每个节点(或指定节点)1 个副本 | 不绑定节点,按replicas 指定总副本数 |
扩缩容方式 | 随节点数量自动扩缩容(节点增减→Pod 增减) | 手动或 HPA 调整replicas (与节点数量无关) |
适用场景 | 节点级服务(日志、监控、网络插件) | 无状态服务(Web、API、微服务) |
节点亲和性 | 核心功能(默认覆盖所有节点,可限制节点) | 可选功能(仅用于优化调度,不强制节点分布) |
6 常见问题与排错
-
DaemonSet 的 Pod 在某些节点上未运行:
- 原因 1:节点有污点(Taint),而 Pod 没有对应的容忍(Toleration)。例如 master 节点默认有
node-role.kubernetes.io/master:NoSchedule
污点,需在 DaemonSet 中添加容忍(如案例中的tolerations
配置)。 - 原因 2:节点标签不匹配(如配置了
nodeSelector: {monitor: yes}
,但节点没有该标签)。 - 排查:
kubectl describe pod <pod名称> -n <命名空间>
,查看Events
中的调度失败原因(如 "node (s) had taint {xxx}, that the pod didn't tolerate")。
- 原因 1:节点有污点(Taint),而 Pod 没有对应的容忍(Toleration)。例如 master 节点默认有
-
更新 DaemonSet 后 Pod 未刷新:
- 原因:使用了
OnDelete
更新策略,需手动删除旧 Pod 才会创建新 Pod。 - 解决:切换为
RollingUpdate
(默认),或手动删除旧 Pod(kubectl delete pod <旧Pod名称>
)。
- 原因:使用了
-
需要限制 DaemonSet 的资源使用:
-
解决:在 Pod 模板中添加
resources.limits
和requests
,避免 Pod 占用节点过多资源:yamlresources: limits: cpu: "100m" memory: "128Mi" requests: cpu: "50m" memory: "64Mi"
-
7 总结
DaemonSet 的核心价值是 "节点级服务全覆盖",它的典型使用场景:
- 日志收集(Fluentd、Filebeat);
- 节点监控(Node Exporter、Grafana Agent);
- 网络插件(Calico、Flannel、Weave);
- 存储插件(Ceph-CSI、GlusterFS 客户端);
- 安全代理(节点级防火墙、入侵检测)。