Kubernetes-守护进程(DaemonSet)应用

DaemonSet确保在所有(或部分)Node节点上运行Pod的副本。随着新的Node被添加到群集中的同时,会将Pod添加到新Node中。随着节点从群集中删除,垃圾收集器也将会删除这些Pod。DaemonSet的一些典型场景和用法:

  • 集群存储:在每个Node节点上,运行集群存储守护程序,例如glusterdceph
  • 日志收集:在每个Node节点上,运行日志收集守护程序,例如fluentdlogstash
  • 节点监控:在每个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,kindmetadata字段。同时,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/

作者简介:
季向远,北京神舟航天软件技术有限公司。本文版权归原作者所有。

K8S中文社区微信公众号

评论 抢沙发

登录后评论

立即登录