在 Kubernetes 集群中,有些业务组件必须在每一个计算节点上运行,比如日志代理、节点级监控探针以及容器网络插件。DaemonSet 就是专门解决这类问题的原生工作负载对象。它并不像 Deployment 那样依靠期望副本数去随机分发 Pod,而是以节点为粒度,确保符合选择条件的每台机器上始终存在一个对应的 Pod 实例。当集群扩容、节点重建或者标签发生变化时,DaemonSet 控制器会持续调谐实际状态,使二者达成一致。

DaemonSet 的控制器调谐原理
DaemonSet 的核心是一个独立的控制器,它运行在 kube-controller-manager 内部。控制器通过 Informer 机制监听 Node 与 Pod 两类资源的变化事件。每当节点列表发生变更,控制器就会执行一轮调谐循环:先列出当前集群中所有节点,再根据 DaemonSet 定义的节点选择器、亲和性以及容忍规则进行过滤,得出目标节点集合。随后控制器查询已存在的 Pod,通过 OwnerReference 字段判断哪些节点已经拥有隶属该 DaemonSet 的 Pod。
对于没有对应 Pod 的目标节点,控制器会基于 DaemonSet 模板构造 Pod 对象,并将 spec.nodeName 直接指定为目标节点,以此绕过普通调度器,实现节点绑定。相反,如果某节点不再满足条件(例如被打了排斥性污点且 DaemonSet 未容忍,或节点被移除),控制器会删除该节点上的关联 Pod。这种声明式调谐让 DaemonSet 具备了自我修复能力,即使控制面短暂故障,恢复后也会重新对齐状态。
从代码层面看,调谐逻辑中关键的一步是 nodeShouldRunDaemonPod 函数,它会综合节点标签、污点容忍和亲和性表达式得出布尔值。只有返回 true 的节点才会进入 Pod 创建队列。下面是一段简化版伪代码,展示过滤与创建的核心思路:
func reconcile(ds *appsv1.DaemonSet, nodes []v1.Node, pods []v1.Pod) {
nodeToPod := map[string]*v1.Pod{}
for _, pod := range pods {
if pod.Spec.NodeName != "" {
nodeToPod[pod.Spec.NodeName] = pod
}
}
for _, node := range nodes {
if !nodeShouldRunDaemonPod(ds, node) {
continue
}
if _, ok := nodeToPod[node.Name]; !ok {
newPod := makePodForDaemonSet(ds, node.Name)
createPod(newPod)
}
}
}
节点调度与污点容忍机制
普通 Pod 依靠调度器打分后落地,而 DaemonSet Pod 在大部分版本中是由控制器直接设置 nodeName 字段,因此不会经过默认调度流程。但这不意味着它可以无视节点状态。DaemonSet 在创建 Pod 时,会自动注入对节点常见污点的容忍规则,例如 node.kubernetes.io/not-ready 与 node.kubernetes.io/unreachable,保证在节点初始化或网络异常阶段也能启动关键守护进程。
如果用户希望限制 DaemonSet 的覆盖范围,可以使用 spec.template.spec.nodeSelector 或者 affinity 字段。例如只为带有 disktype=ssd 标签的节点部署磁盘巡检代理。与此同时,若集群中存在master节点且带有 node-role.kubernetes.io/control-plane:NoSchedule 污点,默认 DaemonSet 若未显式容忍,则不会在其上运行,这也是为什么很多监控组件需要额外配置容忍才能采集控制面指标。
以下示例展示了一个带节点选择与污点容忍的 DaemonSet 片段,它只在 worker 节点运行,并容忍磁盘压力污点:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: disk-checker
spec:
selector:
matchLabels:
app: disk-checker
template:
metadata:
labels:
app: disk-checker
spec:
nodeSelector:
node-role.kubernetes.io/worker: ""
tolerations:
- key: node.kubernetes.io/disk-pressure
operator: Exists
effect: NoSchedule
containers:
- name: checker
image: ipipp.com/disk-checker:v1
滚动更新与版本管理策略
当 DaemonSet 模板发生变更时,控制器需要把旧 Pod 替换为新版本。Kubernetes 提供了两种更新策略:OnDelete 与 RollingUpdate。在 OnDelete 模式下,只有手动删除旧 Pod 后,控制器才会创建新 Pod,适合对变更极度敏感的场景。而 RollingUpdate 则是默认方式,它通过 maxUnavailable 参数控制同时不可用的节点数量,实现逐台平滑升级。
滚动更新期间,控制器会按照节点顺序删除旧 Pod 并立即创建新 Pod,如果某节点上的新 Pod 启动失败,更新会在该节点阻塞,不会影响其他已成功节点。此外,DaemonSet 还支持历史版本留存,通过 revisionHistoryLimit 设定保留数量,配合 kubectl rollout undo 可快速回退。在大规模集群中,建议将 maxUnavailable 设为百分比,避免一次性重启过多节点导致监控断点。
下面是一段展示回滚操作的命令与对应状态说明,帮助理解版本控制的实际效果:
# 查看 DaemonSet 更新状态 kubectl rollout status daemonset/disk-checker # 回退到上一个版本 kubectl rollout undo daemonset/disk-checker # 查看历史 revision kubectl rollout history daemonset/disk-checker
通过上述机制,DaemonSet 不仅解决了每个节点运行单一实例的调度难题,还提供了完善的容错与发布能力。在设计与运维集群级组件时,充分理解其调谐循环、污点处理与更新策略,才能构建稳定可靠的节点守护层。
KubernetesDaemonSet节点调度修改时间:2026-08-14 01:00:34