概念

Edit This Page

DaemonSet

DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时, 也会为他们新增一个 Pod 。当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。

使用 DaemonSet 的一些典型用法:

一个简单的用法是在所有的节点上都启动一个 DaemonSet,将被作为每种类型的 daemon 使 用。 一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志, 和/或对不同硬件类型具有不同的内存、CPU要求。

编写 DaemonSet 规约

创建 DaemonSet

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

controllers/daemonset.yaml
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:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: k8s.gcr.io/fluentd-elasticsearch:1.20
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

必需字段

和其它所有 Kubernetes 配置一样,DaemonSet 需要 apiVersionkindmetadata 字段。有关配置文件的基本信息,详见文档 部署应用配置容器使用kubectl进行对象管理

DaemonSet 也需要一个 .spec 配置段。

Pod 模板

.spec 唯一必需的字段是 .spec.template

.spec.template 是一个 Pod 模板。它与 Pod 具有相同的 schema,除了它是嵌套的,而且不具有 apiVersionkind 字段。

除了 Pod 必需字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签(查看 Pod Selector)。

在 DaemonSet 中的 Pod 模板必须具有一个值为 AlwaysRestartPolicy,或者未指定它的值,默认是 Always

Pod Selector

.spec.selector 字段表示 Pod Selector,它与 Job.spec.selector 的作用是相同的。

从 Kubernetes 1.8开始,您必须指定与 .spec.template 的标签匹配的 pod selector。当不配置时,pod selector 将不再有默认值。selector 默认与 kubectl apply 不兼容。 此外,一旦创建了 DaemonSet,它的 .spec.selector 就不能修改。修改 pod selector 可能导致成为 孤儿Pod,并且这对用户来说是困惑的。

spec.selector 表示一个对象,它由如下两个字段组成:

当上述两个字段都指定时,结果表示的是 AND 关系。

如果指定了 .spec.selector,必须与 .spec.template.metadata.labels 相匹配。如果与它们配置的不匹配,则会被 API 拒绝。

此外,您通常不应该创建任何 pods,它们的 label 与 selector 匹配,或者直接创建,或者通过另一个 DaemonSet、或者其他控制器,比如 ReplicaSet。否则,DaemonSet 控制器会认为这些 Pod 是由它创建的。Kubernetes 不会阻止你这样做。 您可能希望这样做的一种情况是在节点上手动创建具有不同值的 Pod 以进行测试。

仅在某些节点上运行 Pod

如果指定了 .spec.template.spec.nodeSelector,DaemonSet Controller 将在能够与 Node Selector 匹配的节点上创建 Pod。类似这种情况,可以指定 .spec.template.spec.affinity,然后 DaemonSet Controller 将在能够与 node Affinity 匹配>的节点上创建 Pod。 如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。

如何调度 Daemon Pods

由 DaemonSet 控制器调度(从v1.12 开始默认禁用)

正常情况下,Pod 运行在哪个机器上是由 Kubernetes 调度器来选择的。然而,由 DaemonSet Controller 创建的 Pod 已经确定了在哪个机器上(Pod 创建时指定了 .spec.nodeName,调度器会忽略它),因此:

由默认 scheduler 调度(从v1.12开始默认开启)

FEATURE STATE: Kubernetes v1.14 beta
该功能目前处于 beta 状态,意味着:

  • 版本名称包含 beta (例如 v2beta3)。
  • 代码经过了充分测试,启用该功能被认为是安全的。默认情况下被启用。
  • 对整体功能的支持在未来不会被移除,尽管细节上可能会做更改。
  • 在后续的 beta 或稳定版本中,对象的模式、语义可能以不兼容的方式发生变化。当这种情况发生时,我们将提供迁移到下一个版本的说明。这可能需要删除、编辑和重建 API 对象,编辑过程可能需要一些思考。这可能导致依赖该功能的应用程序停机一段时间。
  • 建议仅在非业务关键场景使用该功能,因为在后续版本中可能会发生不兼容的更改。如果您有多个可以独立升级的集群,那么您可能可以放松这个限制。
  • 请尝试使用我们的 beta 版功能,并给出反馈!在它们退出 beta 测试阶段之后,我们将很难去做更多的更改。

DaemonSet 确保所有符合条件的节点都运行一个 Pod 的副本。通常,运行 Pod 的节点由 Kubernetes scheduler 选择。然而,DaemonSet pods 由 DaemonSet controller 创建和调度。这将引入以下问题:

ScheduleDaemonSetPods 允许您使用默认 scheduler 而不是 DaemonSet 控制器来调度 DaemonSets,方法是将 NodeAffinity 添加到 DaemonSet pods,而不是 .spec.nodeName。 然后使用默认 scheduler 将 pod 绑定到目标主机。 如果 DaemonSet pod的亲和节点已存在,则替换它。 DaemonSet 控制器仅在创建或修改 DaemonSet pods 时执行这些操作,并且不对 DaemonSet的 spec.template 进行任何更改。

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

此外,node.kubernetes.io/unschedulable:NoSchedule toleration 会自动添加到 DaemonSet Pods。 在调度DaemonSet Pod 时,默认调度器会忽略 unschedulable节点。

Taints and Tolerations

尽管 Daemon Pods 尊重taints and tolerations,根据相关特性,会自动将以下 tolerations 添加到 DaemonSet Pods 中。

Toleration Key Effect Version Description
node.kubernetes.io/not-ready NoExecute 1.13+ DaemonSet pods will not be evicted when there are node problems such as a network partition.
node.kubernetes.io/unreachable NoExecute 1.13+ DaemonSet pods will not be evicted when there are node problems such as a network partition.
node.kubernetes.io/disk-pressure NoSchedule 1.8+
node.kubernetes.io/memory-pressure NoSchedule 1.8+
node.kubernetes.io/unschedulable NoSchedule 1.12+ DaemonSet pods tolerate unschedulable attributes by default scheduler.
node.kubernetes.io/network-unavailable NoSchedule 1.12+ DaemonSet pods, who uses host network, tolerate network-unavailable attributes by default scheduler.

与 Daemon Pods 通信

与 DaemonSet 中的 Pod 进行通信,几种可能的模式如下:

更新 DaemonSet

如果修改了节点标签(Label),DaemonSet 将立刻向新匹配上的节点添加 Pod,同时删除不能够匹配的节点上的 Pod。

您可以修改 DaemonSet 创建的 Pod。然而,不允许对 Pod 的所有字段进行更新。当下次 节点(即使具有相同的名称)被创建时,DaemonSet Controller 还会使用最初的模板。

您可以删除一个 DaemonSet。如果使用 kubectl 并指定 --cascade=false 选项,则 Pod 将被保留在节点上。然后可以创建具有不同模板的新 DaemonSet。具有不同模板的新 DaemonSet 将能够通过标签匹配并识别所有已经存在的 Pod。它不会修改或删除它们,即使是错误匹配了 Pod 模板。通过删除 Pod 或者删除节点,可以强制创建新的 Pod。

在 Kubernetes 1.6 或以后版本,可以在 DaemonSet 上 执行滚动升级

DaemonSet 的可替代选择

init 脚本

我们很可能希望直接在一个节点上启动 daemon 进程(例如,使用 initupstartd、或 systemd)。这非常好,但基于 DaemonSet 来运行这些进程有如下一些好处:

裸 Pod

可能要直接创建 Pod,同时指定其运行在特定的节点上。然而,DaemonSet 替换了由于任何原因被删除或终止的 Pod,例如节点失败、例行节点维护、内核升级。由于这个原因,我们应该使用 DaemonSet 而不是单独创建 Pod。

静态 Pod

可能需要通过在一个指定目录下编写文件来创建 Pod,该目录受 Kubelet 所监视。这些 Pod 被称为 静态 Pod。 不像 DaemonSet,静态 Pod 不受 kubectl 和其它 Kubernetes API 客户端管理。静态 Pod 不依赖于 apiserver,这使得它们在集群启动的情况下非常有用。而且,未来静态 Pod 可能会被废弃掉。

Deployments

DaemonSet 与 Deployments非常类似,它们都能创建 Pod,这些 Pod 对应的进程都不希望被终止掉(例如,Web 服务器、存储服务器)。 为无状态的 Service 使用 Deployments,比如前端 Frontend 服务,实现对副本的数量进行扩缩容、平滑升级,比基于精确控制 Pod 运行在某个主机上要重要得多。 需要 Pod 副本总是运行在全部或特定主机上,并需要先于其他 Pod 启动,当这被认为非常重要时,应该使用 Daemon Controller。

反馈