导读:本期聚焦于小伙伴创作的《Kubernetes DaemonSet 是怎么保证每个节点都运行一个 Pod 的?》,敬请观看详情。为什么在集群里部署日志采集器或网络插件时,总能在每台机器上看到一模一样的 Pod?这背后是 DaemonSet 控制器在起作用。它和 Deployment 不同,不按副本数调度,而是监听节点变化,为新加入的节点自动创建专属 Pod,节点删除时同步清理。底层依赖 OwnerReference 与节点选择器完成绑定,并通过滚动更新策略控制版本切换。理解它的调谐循环与污点容忍机制,能帮你在边缘节点或异构硬件环境下精准控制守护进程的覆盖范围,避免资源浪费或监控盲区。

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

Kubernetes DaemonSet 是怎么保证每个节点都运行一个 Pod 的?

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-readynode.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 提供了两种更新策略:OnDeleteRollingUpdate。在 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

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。