DaemonSet

DaemonSet 定义了提供节点本地功能的 Pod。这些 Pod 可能是集群运行的基础,例如网络辅助工具,或作为附加组件的一部分。

_DaemonSet_ 确保所有(或部分)节点运行 Pod 的副本。当节点添加到集群时,Pod 会添加到这些节点上。当节点从集群中移除时,这些 Pod 会被垃圾回收。删除 DaemonSet 会清理其创建的 Pod。

DaemonSet 的一些典型用途是:

  • 在每个节点上运行集群存储守护进程
  • 在每个节点上运行日志收集守护进程
  • 在每个节点上运行节点监控守护进程

在简单情况下,每种类型的守护进程会使用一个 DaemonSet,覆盖所有节点。更复杂的设置可能会为单一类型的守护进程使用多个 DaemonSet,但针对不同的硬件类型使用不同的标志和/或不同的内存和 CPU 请求。

编写 DaemonSet 规范

创建 DaemonSet

你可以在 YAML 文件中描述一个 DaemonSet。例如,下面的 daemonset.yaml 文件描述了一个运行 fluentd-elasticsearch Docker 镜像的 DaemonSet。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # these tolerations are to have the daemonset runnable on control plane nodes
      # remove them if your control plane nodes should not run pods
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v5.0.1
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      # it may be desirable to set a high priority class to ensure that a DaemonSet Pod
      # preempts running Pods
      # priorityClassName: important
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

根据 YAML 文件创建 DaemonSet

kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml

必填字段

与所有其他 Kubernetes 配置一样,DaemonSet 需要 apiVersionkindmetadata 字段。有关配置文件的通用信息,请参阅运行无状态应用使用 kubectl 进行对象管理

DaemonSet 对象的名称必须是有效的DNS 子域名

DaemonSet 还需要一个 .spec 部分。

Pod 模板

.spec.template.spec 中必填字段之一。

.spec.template 是一个Pod 模板。它的 schema 与 Pod 完全相同,只是它是嵌套的,并且没有 apiVersionkind

除了 Pod 的必填字段外,DaemonSet 中的 Pod 模板必须指定适当的标签(请参阅Pod 选择器)。

DaemonSet 中的 Pod 模板必须将 RestartPolicy 设置为 Always,或者未指定(默认为 Always)。

Pod 选择器

.spec.selector 字段是一个 Pod 选择器。它的工作方式与 Job.spec.selector 相同。

你必须指定一个与 .spec.template 的标签匹配的 Pod 选择器。此外,一旦创建了 DaemonSet,其 .spec.selector 就不能被修改。修改 Pod 选择器可能会导致 Pod 被意外地孤立,这被发现对用户来说是令人困惑的。

.spec.selector 是一个包含两个字段的对象:

  • matchLabels - 工作方式与 ReplicationController.spec.selector 相同。
  • matchExpressions - 允许通过指定键、值列表以及关联键和值的运算符来构建更复杂的选择器。

当两者都指定时,结果是进行 AND 运算。

.spec.selector 必须与 .spec.template.metadata.labels 匹配。这两个不匹配的配置将被 API 拒绝。

在选定节点上运行 Pod

如果你指定 .spec.template.spec.nodeSelector,则 DaemonSet 控制器将在匹配该节点选择器的节点上创建 Pod。同样,如果你指定 .spec.template.spec.affinity,则 DaemonSet 控制器将在匹配该节点亲和性的节点上创建 Pod。如果你两者都不指定,则 DaemonSet 控制器将在所有节点上创建 Pod。

Daemon Pod 的调度方式

DaemonSet 可用于确保所有符合条件的节点都运行 Pod 的副本。DaemonSet 控制器为每个符合条件的节点创建一个 Pod,并添加 Pod 的 spec.affinity.nodeAffinity 字段以匹配目标主机。Pod 创建后,默认调度器通常会接管,然后通过设置 .spec.nodeName 字段将 Pod 绑定到目标主机。如果新 Pod 无法适应节点,默认调度器可能会根据新 Pod 的优先级抢占(驱逐)一些现有 Pod。

用户可以通过设置 DaemonSet 的 .spec.template.spec.schedulerName 字段,为 DaemonSet 的 Pods 指定不同的调度器。

DaemonSet 控制器在评估符合条件的节点时会考虑 .spec.template.spec.affinity.nodeAffinity 字段中指定的原始节点亲和性(如果已指定),但在创建的 Pod 上,它会被替换为与符合条件的节点名称匹配的节点亲和性。

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name
        operator: In
        values:
        - target-host-name

污点和容忍度

DaemonSet 控制器会自动为 DaemonSet Pods 添加一组容忍度

DaemonSet Pod 的容忍度
容忍度键效果详情
node.kubernetes.io/not-readyNoExecuteDaemonSet Pod 可以调度到不健康或未准备好接受 Pod 的节点上。运行在此类节点上的任何 DaemonSet Pod 都不会被驱逐。
node.kubernetes.io/unreachableNoExecuteDaemonSet Pod 可以调度到节点控制器无法访问的节点上。运行在此类节点上的任何 DaemonSet Pod 都不会被驱逐。
node.kubernetes.io/disk-pressureNoScheduleDaemonSet Pod 可以调度到存在磁盘压力问题的节点上。
node.kubernetes.io/memory-pressureNoScheduleDaemonSet Pod 可以调度到存在内存压力问题的节点上。
node.kubernetes.io/pid-pressureNoScheduleDaemonSet Pod 可以调度到存在进程压力问题的节点上。
node.kubernetes.io/unschedulableNoScheduleDaemonSet Pod 可以调度到不可调度的节点上。
node.kubernetes.io/network-unavailableNoSchedule仅为请求主机网络的 DaemonSet Pod 添加,即具有 spec.hostNetwork: true 的 Pod。此类 DaemonSet Pod 可以调度到网络不可用的节点上。

你也可以通过在 DaemonSet 的 Pod 模板中定义这些容忍度,为 DaemonSet 的 Pods 添加自己的容忍度。

由于 DaemonSet 控制器会自动设置 node.kubernetes.io/unschedulable:NoSchedule 容忍度,Kubernetes 可以在标记为_不可调度_的节点上运行 DaemonSet Pod。

如果你使用 DaemonSet 来提供重要的节点级功能,例如集群网络,那么 Kubernetes 在节点准备好之前将 DaemonSet Pod 放置到节点上是很有帮助的。例如,如果没有这个特殊的容忍度,你可能会陷入死锁情况:节点未标记为就绪,因为网络插件未在该节点上运行;同时网络插件未在该节点上运行,因为节点尚未就绪。

与守护进程 Pod 通信

与 DaemonSet 中的 Pod 通信的一些可能模式是:

  • 推送:DaemonSet 中的 Pod 被配置为向其他服务(例如统计数据库)发送更新。它们没有客户端。
  • 节点 IP 和已知端口:DaemonSet 中的 Pod 可以使用 hostPort,这样可以通过节点 IP 访问 Pod。客户端以某种方式知道节点 IP 列表,并根据约定知道端口。
  • DNS:使用相同的 Pod 选择器创建一个无头服务,然后使用 endpoints 资源发现 DaemonSet 或从 DNS 中检索多个 A 记录。
  • Service:使用相同的 Pod 选择器创建一个服务,并使用该服务来访问随机节点上的守护进程。使用服务内部流量策略将其限制到同一节点上的 Pod。

更新 DaemonSet

如果节点标签发生更改,DaemonSet 将立即向新匹配的节点添加 Pod,并从新不匹配的节点删除 Pod。

你可以修改 DaemonSet 创建的 Pod。但是,Pod 不允许更新所有字段。此外,DaemonSet 控制器下次创建节点(即使名称相同)时,将使用原始模板。

你可以删除一个 DaemonSet。如果你使用 kubectl 并指定 --cascade=orphan,则 Pod 将保留在节点上。如果你随后创建一个具有相同选择器的新 DaemonSet,则新 DaemonSet 会接管现有 Pod。如果任何 Pod 需要替换,DaemonSet 会根据其 updateStrategy 替换它们。

你可以对 DaemonSet执行滚动更新

DaemonSet 的替代方案

初始化脚本

直接在节点上启动守护进程(例如,使用 initupstartdsystemd)当然是可行的。这完全没有问题。然而,通过 DaemonSet 运行此类进程有几个优点:

  • 能够以与应用程序相同的方式监视和管理守护进程的日志。
  • 守护进程和应用程序使用相同的配置语言和工具(例如 Pod 模板、kubectl)。
  • 在具有资源限制的容器中运行守护进程可以增加守护进程与应用程序容器之间的隔离。然而,这也可以通过在容器中运行守护进程但不将其放入 Pod 中来实现。

裸 Pod

可以直接创建指定在特定节点上运行的 Pod。然而,DaemonSet 会替换因任何原因删除或终止的 Pod,例如节点故障或破坏性节点维护(如内核升级)的情况。因此,你应该使用 DaemonSet 而不是创建单独的 Pod。

静态 Pod

可以通过将文件写入 Kubelet 监视的特定目录来创建 Pod。这些被称为静态 Pod。与 DaemonSet 不同,静态 Pod 不能通过 kubectl 或其他 Kubernetes API 客户端进行管理。静态 Pod 不依赖于 apiserver,这使得它们在集群引导情况下非常有用。此外,静态 Pod 在将来可能会被弃用。

部署

DaemonSet 与 Deployments 相似,因为它们都创建 Pod,并且这些 Pod 中的进程预期不会终止(例如,Web 服务器、存储服务器)。

对于无状态服务(例如前端),当扩展副本数量和滚动更新比精确控制 Pod 运行在哪个主机上更重要时,请使用 Deployment。当 Pod 的副本始终运行在所有或某些主机上很重要时,如果 DaemonSet 提供节点级功能,使其他 Pod 能够在该特定节点上正确运行,请使用 DaemonSet。

例如,网络插件通常包含一个作为 DaemonSet 运行的组件。该 DaemonSet 组件确保其运行的节点具有正常工作的集群网络。

下一步

上次修改于 2025 年 8 月 10 日太平洋标准时间晚上 10:50:在 Daemon Pod 通信中提及服务内部流量策略 (6c39c2bbbb)