深色模式
DaemonSet 守护进程部署
摘要:本文面向平台/SRE 工程师,讲解 DaemonSet 如何在(部分)节点上常驻一份 Pod,以及它与 Deployment 的边界、滚动更新与排障。覆盖 Kubernetes v1.28+。
适用版本与前提
- Kubernetes:v1.28+
- 工具:
kubectl - 前提:理解节点污点、亲和性、优先级
背景与问题
有些进程必须在每台(或特定)节点上运行一份:容器运行时日志采集器(Fluent Bit)、节点监控(node-exporter)、网络插件(Calico/ Cilium 的 agent)。它们不是“无状态多副本服务”,而是“节点级基础设施”。如果用手动裸 Pod,节点故障或维护后 Pod 不会自愈;用 Deployment 又无法保证每节点恰好一份。DaemonSet 正是为此而生:它确保每个(符合条件的)节点上恰好运行一个该 Pod 副本。
核心机制
DaemonSet 控制器为符合条件的每个节点创建一个 Pod,并通过 spec.affinity.nodeAffinity 锁定目标主机(metadata.name 匹配)。之后由默认调度器绑定 spec.nodeName。节点加入集群即自动新增,节点移除即被垃圾回收。
yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
labels:
app: fluent-bit
spec:
selector:
matchLabels:
app: fluent-bit
template:
metadata:
labels:
app: fluent-bit
spec:
nodeSelector:
kubernetes.io/os: linux
tolerations:
- operator: Exists
effect: NoSchedule
priorityClassName: system-node-critical
containers:
- name: fluent-bit
image: fluent/fluent-bit:3.0
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
memory: 200Mi1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
调度到指定节点
nodeSelector/affinity:只在与条件匹配的节点上创建 Pod。不指定则覆盖所有节点。- 自动容忍:DaemonSet 控制器自动给其 Pod 添加一组 toleration,使其能调度到
not-ready、unreachable、disk-pressure、memory-pressure、unschedulable等节点上,并不被驱逐。这使得网络插件等能在节点 Ready 之前就先跑起来,避免“节点不 Ready→网络插件不跑→节点更不 Ready”的死锁。 hostNetwork: true的 DaemonSet 额外容忍network-unavailable。
建议
对提供节点级关键功能(如网络、日志)的 DaemonSet,设置 priorityClassName: system-node-critical 或较高优先级,确保节点资源紧张时优先抢占、不被普通 Pod 挤掉。
更新策略
yaml
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 滚动更新时最多不可用节点数(默认1)1
2
3
4
5
2
3
4
5
RollingUpdate:逐节点滚动替换,受maxUnavailable约束(不能设为百分比时的语义同 Deployment)。OnDelete:修改模板后不自动更新,需手动删除旧 Pod 才替换,适合谨慎变更。
注意
DaemonSet Pod 不是全部字段都可更新(Pod 本身有不可变字段限制),且更新模板后控制面用原始模板重建 Pod。用 --cascade=orphan 删除 DaemonSet 会保留节点上 Pod,新建同名 DaemonSet 会接管它们。
与 Deployment 的边界
| 维度 | DaemonSet | Deployment |
|---|---|---|
| 目标 | 每节点/特定节点一份 | 多副本无差别 |
| 扩容方式 | 随节点增减 | 手动 replicas |
| 适用 | 节点级基础设施(日志/监控/网络) | 无状态业务服务 |
| 关注点 | 是否“在每台机器上” | 副本数与滚动 |
版本相关
DaemonSet 的滚动更新与 maxUnavailable 已是稳定能力(v1.21+ 即稳定)。老集群若仍使用 extensions/v1beta1 等已移除 API,需迁移到 apps/v1。
生产实践
- 强制资源限制:DaemonSet 在每个节点都跑,无限制会造成“每节点都超卖”,应设
requests/limits,尤其是内存。 - 安全上下文最小化:以只读根文件系统、
runAsNonRoot运行采集器,降低攻击面。 - 更新前先灰度:先对少量节点验证新版本 DaemonSet(可用节点池 label 缩小
nodeSelector范围)。 - 关键 DaemonSet 配 PDB:节点维护(drain)时避免一次性摘掉太多日志/监控 Pod 影响可观测性(见《Pod 中断预算 PDB》)。
生产危险
误删 DaemonSet 会清除节点上所有对应 Pod,包括网络插件 agent,可能直接导致节点网络中断。删除前确认影响范围,必要时用 --cascade=orphan 保留 Pod。
故障排查
| 现象 | 原因 | 处理 |
|---|---|---|
| 某节点没有 DaemonSet Pod | nodeSelector/污点不匹配、资源不足 | 查节点 label 与 kubectl describe |
Pod 一直在 FailedScheduling | 资源请求超节点可用 | 调小 requests 或扩容 |
| 滚动更新卡住 | maxUnavailable 受限且某节点 Pod 不退出 | 检查节点/kubelet 状态 |
常见坑
- 忘记给 DaemonSet Pod 加对
node.kubernetes.io/unschedulable:NoSchedule之外的业务污点容忍,导致关键节点(如带专用污点)上没跑起来。 - 把 DaemonSet 当 Deployment 用(需要精确副本数/对外服务),错配语义。
替代方案与权衡
- 传统
systemd/init直接跑守护进程也可行,但失去统一日志、资源限制、声明式管理。 - 裸 Pod 指定
nodeName能固定节点,但无自愈,节点故障不重建——故优先 DaemonSet。
FAQ
Q:DaemonSet 能跑在有污点的节点吗? A:默认已自动容忍多种系统污点;对于业务自定义污点,需在模板中显式添加 tolerations。
Q:如何临时停止某节点上的 DaemonSet Pod? A:给该节点加 node.kubernetes.io/unschedulable 不会移除已运行 Pod;需 cordon+drain 或手动删除(DaemonSet 会重建,除非用 OnDelete 且不再重建)。
参考资料
- DaemonSet - Kubernetes 官方文档,访问日期:2026-10-08。
- Performing a Rolling Update on a DaemonSet - Kubernetes 官方文档,访问日期:2026-10-08。
- Taints and Tolerations - Kubernetes 官方文档,访问日期:2026-10-08。