DaemonSet
DaemonSet 确保所有(或部分)节点都运行 Pod 的副本。当节点添加到集群时,Pod 会添加到这些节点上。当节点从集群中移除时,这些 Pod 会被垃圾回收。删除 DaemonSet 会清理其创建的 Pod。
DaemonSet 的一些典型用途包括
- 在每个节点上运行集群存储守护进程
- 在每个节点上运行日志收集守护进程
- 在每个节点上运行节点监控守护进程
在简单情况下,一个覆盖所有节点的 DaemonSet 用于每种类型的守护进程。更复杂的设置可能对同一种守护进程使用多个 DaemonSet,但针对不同的硬件类型使用不同的标志以及/或者不同的内存和 CPU 请求。
编写 DaemonSet Spec
创建 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:v2.5.2
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 需要 apiVersion
、kind
和 metadata
字段。有关使用配置文件的一般信息,请参阅运行无状态应用和使用 kubectl 管理对象。
DaemonSet 对象的名称必须是合法的DNS 子域名。
DaemonSet 还需要一个.spec
节。
Pod 模板
.spec.template
是 .spec
中的一个必需字段。
.spec.template
是一个Pod 模板。它与 Pod 具有完全相同的 schema,只是它嵌套在 DaemonSet 中,并且没有 apiVersion
或 kind
字段。
除了 Pod 的必需字段外,DaemonSet 中的 Pod 模板还必须指定合适的标签(参见Pod 选择器)。
DaemonSet 中的 Pod 模板必须具有等于 Always
的RestartPolicy
,或者未指定,默认为 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 Pod 在每个节点上运行很重要,通常最好将 DaemonSet 的.spec.template.spec.priorityClassName
设置为具有较高优先级的PriorityClass,以确保发生此驱逐。用户可以通过设置 DaemonSet 的 .spec.template.spec.schedulerName
字段来为 DaemonSet 的 Pod 指定不同的调度器。
在评估符合条件的节点时,DaemonSet 控制器会考虑在 .spec.template.spec.affinity.nodeAffinity
字段中指定的原始节点亲和性(如果指定),但在创建的 Pod 上,它会被替换为与符合条件的节点名称匹配的节点亲和性。
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
污点和容忍度
DaemonSet 控制器会自动为 DaemonSet Pod 添加一组容忍度
容忍度键 (Toleration key) | 效果 (Effect) | 详情 (Details) |
---|---|---|
node.kubernetes.io/not-ready | NoExecute | DaemonSet Pod 可以调度到不健康或未准备好接受 Pod 的节点上。运行在此类节点上的任何 DaemonSet Pod 都不会被驱逐。 |
node.kubernetes.io/unreachable | NoExecute | DaemonSet Pod 可以调度到节点控制器无法访问的节点上。运行在此类节点上的任何 DaemonSet Pod 都不会被驱逐。 |
node.kubernetes.io/disk-pressure | NoSchedule | DaemonSet Pod 可以调度到有磁盘压力问题的节点上。 |
node.kubernetes.io/memory-pressure | NoSchedule | DaemonSet Pod 可以调度到有内存压力问题的节点上。 |
node.kubernetes.io/pid-pressure | NoSchedule | DaemonSet Pod 可以调度到有进程压力问题的节点上。 |
node.kubernetes.io/unschedulable | NoSchedule | DaemonSet Pod 可以调度到不可调度的节点上。 |
node.kubernetes.io/network-unavailable | NoSchedule | 仅添加到请求主机网络 (host networking) 的 DaemonSet Pod 中,即 spec.hostNetwork: true 的 Pod。此类 DaemonSet Pod 可以调度到网络不可用的节点上。 |
你也可以通过在 DaemonSet 的 Pod 模板中定义,为 DaemonSet 的 Pod 添加自己的容忍度。
由于 DaemonSet 控制器自动设置 node.kubernetes.io/unschedulable:NoSchedule
容忍度,Kubernetes 可以在标记为 不可调度 (unschedulable) 的节点上运行 DaemonSet Pod。
如果你使用 DaemonSet 提供重要的节点级功能,例如集群网络,Kubernetes 在节点就绪之前将 DaemonSet Pod 放置到节点上是很有帮助的。例如,如果没有这个特殊的容忍度,你可能会陷入僵局:由于网络插件未在该节点上运行,节点未被标记为就绪;与此同时,由于节点尚未就绪,网络插件也未在该节点上运行。
与 Daemon Pod 通信
与 DaemonSet 中的 Pod 通信的一些可能模式包括
- 推送:DaemonSet 中的 Pod 配置为向另一个服务发送更新,例如统计信息数据库。它们没有客户端。
- NodeIP 和已知端口:DaemonSet 中的 Pod 可以使用
hostPort
,以便通过节点 IP 访问 Pod。客户端可以通过某种方式知道节点 IP 列表,并约定端口。 - DNS:使用相同的 Pod 选择器创建无头 Service (headless service),然后使用
endpoints
资源发现 DaemonSet 或从 DNS 中检索多个 A 记录。 - Service:使用相同的 Pod 选择器创建 Service,并使用该 Service 访问随机节点上的守护进程。(无法访问特定节点。)
更新 DaemonSet
如果节点标签被更改,DaemonSet 会立即将 Pod 添加到新匹配的节点上,并从新不再匹配的节点上删除 Pod。
你可以修改 DaemonSet 创建的 Pod。但是,Pod 并非所有字段都允许更新。此外,下次创建节点(即使名称相同)时,DaemonSet 控制器将使用原始模板。
你可以删除 DaemonSet。如果你使用 kubectl
指定 --cascade=orphan
,则 Pod 将保留在节点上。如果你随后创建了一个具有相同选择器的新 DaemonSet,新的 DaemonSet 会接管现有的 Pod。如果任何 Pod 需要替换,DaemonSet 将根据其 updateStrategy
进行替换。
你可以对 DaemonSet 执行滚动更新。
DaemonSet 的替代方案
初始化脚本 (Init scripts)
当然可以直接在节点上启动守护进程(例如使用 init
、upstartd
或 systemd
)。这样做完全可行。但是,通过 DaemonSet 运行此类进程有几个优点
- 以与应用相同的方式监控和管理守护进程的日志。
- 守护进程和应用使用相同的配置语言和工具(例如 Pod 模板、
kubectl
)。 - 在具有资源限制的容器中运行守护进程可以增加守护进程与应用容器之间的隔离。但是,也可以通过在容器而非 Pod 中运行守护进程来实现这一点。
Bare Pods (裸 Pod)
可以直接创建指定在特定节点上运行的 Pod。但是,DaemonSet 会替换因任何原因被删除或终止的 Pod,例如节点故障或破坏性节点维护(如内核升级)的情况。因此,你应该使用 DaemonSet 而不是创建单个 Pod。
Static Pods (静态 Pod)
可以通过将文件写入 Kubelet 监视的特定目录来创建 Pod。这些被称为静态 Pod。与 DaemonSet 不同,静态 Pod 无法通过 kubectl 或其他 Kubernetes API 客户端管理。静态 Pod 不依赖于 apiserver,这使得它们在集群引导场景中很有用。此外,静态 Pod 在未来可能会被弃用。
Deployment
DaemonSet 与Deployment 相似,它们都创建 Pod,并且这些 Pod 中的进程不应该终止(例如 Web 服务器、存储服务器)。
对于无状态服务,例如前端,应使用 Deployment,在这种情况下,扩缩副本数和滚动更新比精确控制 Pod 运行在哪个主机上更重要。当 Pod 的副本必须始终运行在所有或某些主机上时,应使用 DaemonSet,前提是 DaemonSet 提供节点级功能,允许其他 Pod 在特定节点上正常运行。
例如,网络插件通常包含一个以 DaemonSet 形式运行的组件。DaemonSet 组件确保其运行的节点具有正常的集群网络功能。
下一步
- 了解Pod。
- 了解如何使用 DaemonSet
- 对 DaemonSet 执行滚动更新
- 对 DaemonSet 执行回滚(例如,如果滚动更新未按预期进行)。
- 了解Kubernetes 如何将 Pod 分配给节点。
- 了解设备插件和附加组件,它们通常作为 DaemonSet 运行。
DaemonSet
是 Kubernetes REST API 中的一个顶层资源。阅读DaemonSet 对象定义以了解 DaemonSet 的 API。