DaemonSet确保在所有(或部分)Node节点上运行Pod的副本。随着新的Node被添加到群集中的同时,会将Pod添加到新Node中。随着节点从群集中删除,垃圾收集器也将会删除这些Pod。DaemonSet的一些典型场景和用法:
- 集群存储:在每个Node节点上,运行集群存储守护程序,例如glusterd,ceph。
- 日志收集:在每个Node节点上,运行日志收集守护程序,例如fluentd或logstash。
- 节点监控:在每个Node节点上,运行节点监控守护程序,例如Prometheus Node Exporter
,collectd
,Dynatrace OneAgent,Datadog agent,New Relic agent,Ganglia gmond或者Instana agent。
1、编写DaemonSet Spec
1.1 创建一个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 |
基于YAML文件创建DaemonSet:
# kubectl create -f https://k8s.io/examples/controllers/daemonset.yaml
1.2 必填字段
与Kubernetes中其它的对象一样,DaemonSet必须包含apiVersion,kind和metadata字段。同时,DaemonSet还需要spec字段部分的内容。
1.3 Pod模板
.spec.template是.spec的必填字段。.spec.template用来定义Pod模板。DaemonSet中的Pod模板必须设置RestartPolicy 等于Always,未指定的默认值即为Always。
1.4 Pod选择器
通过.spec.selector字段定义Pod选择器。从Kubernetes 1.8开始,必须指定一个与.spec.template标签相匹配选择器。一旦创建了DaemonSet,就不能对.spec.selector进行修改,改变Pod选择器可能会导致Pod成为孤儿。
.spec.selector是一个由两个字段组成的对象:
- matchLabels– 与ReplicationController的.spec.selector字段同样的工作机制。
- matchExpressions – 允许通过指定键,值列表以及与键和值相关的运算符来构建更复杂的选择器。
如果同时指定了两者时,结果取两者的和。如果指定了.spec.selector,则必须匹配.spec.template.metadata.labels,如果不匹配将会被API拒绝。
1.5 仅在某些节点上运行Pod
如果指定了.spec.template.spec.nodeSelector,则DaemonSet控制器将在与该节点选择器匹配的Node节点上部署Pod 。同样,如果指定了.spec.template.spec.affinity,则DaemonSet控制器将在与该节点关联相匹配的Node节点上创建Pod 。如果您未指定上述两个字段,则DaemonSet控制器将会在所有的Node节点上创建Pod。
2 调度Daemon Pods
2.1 由DaemonSet控制器调度(自1.12版本起,默认禁用)
通常,由Kubernetes调度器选择Pod所运行的机器。但是,由DaemonSet控制器创建的Pod,在创建是就已经为Pod 选择了机器(在创建Pod时指定.spec.nodeName,因此调度器会忽略它)。因此:
- DaemonSet控制器将不会考虑unschedulable的Node节点。
- 即使尚未启动调度器,DaemonSet控制器也可以生成Pod,这可以帮助集群引导程序。
2.2 由默认调度器调度(自1.12版本起,默认启用)
特性状态: Kubernetes v1.13 beta
DaemonSet确保所有符合条件的节点都运行Pod的副本。通常,由Kubernetes调度器选择Pod所运行的Node节点。但是,DaemonSet Pods是由DaemonSet控制器所创建和调度的。这就产生了以下的问题:
- 不一致的Pod行为:正常的Pod,在创建是处于Pending状态;但DaemonSet Pod在创建时,并不是处于Pending 状态。这使用户感到困惑。
- Pod抢占由默认调度器处理。启用抢占后,DaemonSet控制器将在不考虑Pod优先级和抢占的情况下制定调度决策。
ScheduleDaemonSetPods允许使用默认调度器而不是DaemonSet控制器来调度DaemonSet,方法是将NodeAffinity术语添加到DaemonSet Pods,而不是使用.spec.nodeName术语。默认调度器将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容忍会自动添加到DaemonSet Pods。在调度DaemonSet Pod时,默认调度器会忽略unschedulable的Node节点。
2.3 污点和容忍
根据相关特性,DaemonSet Pods会自动添加以下的容忍度。
容忍建 | 影响 | 版本 | 描述 |
---|---|---|---|
node.kubernetes.io/not-ready | NOEXECUTE | 1.13+ | 当存在诸如网络分区之类的节点问题时,不会驱逐DaemonSet pod。 |
node.kubernetes.io/unreachable | NOEXECUTE | 1.13+ | 当存在诸如网络分区之类的节点问题时,不会驱逐DaemonSet pod。 |
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可以通过默认调度程序容忍不可调度的属性。 |
node.kubernetes.io/network-unavailable | NoSchedule | 1.12+ | 使用主机网络的DaemonSet pod可以通过默认调度程序容忍网络不可用的属性。 |
3 与Daemon Pods进行通信
下面是与DaemonSet中Pod进行通信的一些可能模式:
- 推送:DaemonSet中的Pod配置为将更新发送给另一个服务,例如统计数据库。他们没有客户。
- NodeIP和已知端口:DaemonSet中的Pod可以使用hostPort,以便可以通过Node节点IP访问Pod。客户端以某种方式知道节点IP列表,并按知道端口。
- DNS:使用相同的Pod选择器创建无头服务(headless service),然后使用该endpoints资源发现DaemonSets 或从DNS检索多个记录。
- 服务:使用相同的Pod选择器创建服务,并使用该服务在随机Node节点上访问守护程序。(无法到达特定节点。)
4 更新DaemonSet
如果更改了Node节点标签,DaemonSet会立即将Pod添加到新匹配的Node节点,并从不匹配的Node节点中删除Pod。可以修改DaemonSet创建的Pod。但是,不允许更新Pod所有字段。此外,DaemonSet控制器将在下次创建节点(即使具有相同名称)时使用原始模板。可以删除DaemonSet,如果通过kubectl指定了–cascade=false,则Pod会保留在Node节点上。可以使用不同的模板创建新的DaemonSet,具有不同模板的新DaemonSet将所有现有Pod识别为具有匹配标签。尽管Pod模板不匹配,它也不会修改或删除它们,需要通过删除Pod或删除节点来强制创建新的Pod。
参考资料
1.《DaemonSet》地址:https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
作者简介:
季向远,北京神舟航天软件技术有限公司。本文版权归原作者所有。