【云原生|Kubernetes】14-DaemonSet资源控制器详解

【云原生|Kubernetes】14-DaemonSet资源控制器详解

文章目录

简介

​ 在 Kubernetes 中,DaemonSet 是一种用于在节点上运行指定的 Pod 的控制器(Controller)。与 ReplicaSet 或 Deployment 不同,DaemonSet 不是为了扩展 Pod 数量而创建的,而是为了在每个节点上运行一个实例或多个实例的 Pod。

​ DaemonSet 通常用于在 Kubernetes 集群中运行一些系统级别的服务或者网络代理,例如日志收集器、监控代理、网络插件等。通过使用 DaemonSet,可以确保每个节点上都运行了指定的 Pod,从而保证了这些服务或者代理的高可用性和稳定性。

​ 与其他控制器类似,DaemonSet 也会监视 Pod 的状态,并在 Pod 出现故障或者被删除时自动进行替换。当一个新的节点加入到 Kubernetes 集群中时,DaemonSet 也会自动在该节点上创建所需的 Pod。如果需要更新 DaemonSet 中的 Pod 版本或者配置,可以通过更新 DaemonSet 的 YAML 配置文件来实现。

​ 需要注意的是,DaemonSet 中的 Pod 通常会创建在 kube-system 命名空间下,因为这些服务或者代理通常是与 Kubernetes 集群本身相关联的。在创建 DaemonSet 时,可以使用 nodeSelector、tolerations 和 affinity 等方式来控制 DaemonSet 在哪些节点上运行、不在哪些节点上运行以及如何分配 Pod 到节点上。

典型用法

DaemonSet 的一些典型用法:

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

一种简单的用法是为每种类型的守护进程在所有的节点上都启动一个 DaemonSet。 一个稍微复杂的用法是为同一种守护进程部署多个 DaemonSet;每个具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求。

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:
      # 这些容忍度设置是为了让该守护进程集在控制平面节点上运行
      # 如果你不希望自己的控制平面节点运行 Pod,可以删除它们
      - 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
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

与所有其他 Kubernetes 配置一样,DaemonSet 也需要 apiVersionkindmetadata 字段。DaemonSet 对象的名称必须是一个合法的 DNS 子域名;DaemonSet 也需要 .spec 节区。

Pod模板

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

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

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

在 DaemonSet 中的 Pod 模板必须具有一个值为 AlwaysRestartPolicy。 当该值未指定时,默认是 Always

Pod 选择算符

.spec.selector 字段表示 Pod 选择算符,它与 Job的 .spec.selector 的作用是相同的。

你必须指定与 .spec.template 的标签匹配的 Pod 选择算符。 此外,一旦创建了 DaemonSet,它的 .spec.selector 就不能修改。 修改 Pod 选择算符可能导致 Pod 意外悬浮,并且这对用户来说是费解的。

spec.selector 是一个对象,如下两个字段组成:

  • matchLabels - 与 ReplicationController 的 .spec.selector 的作用相同。
  • matchExpressions - 允许构建更加复杂的选择器,可以通过指定 key、value 列表以及将 key 和 value 列表关联起来的 Operator。

当上述两个字段都指定时,结果会按逻辑与(AND)操作处理。.spec.selector 必须与 .spec.template.metadata.labels 相匹配。 如果配置中这两个字段不匹配,则会被 API 拒绝。

在选定的节点上运行 Pod

​ 如果指定了 .spec.template.spec.nodeSelector,DaemonSet 控制器将在能够与 Node 选择算符匹配的节点上创建 Pod。 类似这种情况,可以指定 .spec.template.spec.affinity,之后 DaemonSet 控制器将在能够与节点亲和性匹配的节点上创建 Pod。 如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。

DaemonSet的 Pods 是如何被调度的

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

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

当评估符合条件的节点时,原本在 .spec.template.spec.affinity.nodeAffinity 字段上指定的节点亲和性将由 DaemonSet 控制器进行考量,但在创建的 Pod 上会被替换为与符合条件的节点名称匹配的节点亲和性。

ScheduleDaemonSetPods 允许你使用默认调度器而不是 DaemonSet 控制器来调度这些 DaemonSet, 方法是将 NodeAffinity 条件而不是 .spec.nodeName 条件添加到这些 DaemonSet Pod。 默认调度器接下来将 Pod 绑定到目标主机。 如果 DaemonSet Pod 的节点亲和性配置已存在,则被替换 (原始的节点亲和性配置在选择目标主机之前被考虑)。 DaemonSet 控制器仅在创建或修改 DaemonSet Pod 时执行这些操作, 并且不会更改 DaemonSet 的 spec.template

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

在这个例子中,Pod 指定了一个 requiredDuringSchedulingIgnoredDuringExecution 的调度限制条件,要求 Pod 只能被调度到带有标签 example-label 并且值为 example-value 的节点上运行。如果没有符合条件的节点,Pod 就无法被调度到节点上运行。

  • requiredDuringSchedulingIgnoredDuringExecution 的调度限制条件,它可以用于指定必须满足的调度要求。具体来说,requiredDuringSchedulingIgnoredDuringExecution 是一个 PodSpec 的字段,它包含一组要求,如果这些要求不能满足,Pod 就无法被调度到节点上运行。

  • 与其他调度限制条件不同,requiredDuringSchedulingIgnoredDuringExecution 是一个硬性要求,即如果不能满足,Pod 就无法被调度到节点上运行。同时,该限制条件在 Pod 运行过程中仍然会被忽略,因此在节点上的运行状态不会受到该限制条件的影响。

污点和容忍度

DaemonSet 控制器会自动将一组容忍度添加到 DaemonSet Pod。

容忍度键名 效果 描述
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/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 仅针对请求主机联网的 DaemonSet Pod 添加此容忍度 ,即 Pod 具有 spec.hostNetwork: true。这些 DaemonSet Pod 可以被调度到网络不可用的节点上。

你也可以在 DaemonSet 的 Pod 模板中定义自己的容忍度并将其添加到 DaemonSet Pod。

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

如果你使用 DaemonSet 提供重要的节点级别功能, 例如集群联网, Kubernetes 在节点就绪之前将 DaemonSet Pod 放到节点上会很有帮助。 例如,如果没有这种特殊的容忍度,因为网络插件未在节点上运行,所以你可能会在未标记为就绪的节点上陷入死锁状态, 同时因为该节点还未就绪,所以网络插件不会在该节点上运行。

DaemonSet更新和回滚

DaemonSet更新策略

DaemonSet 有两种更新策略:

  • OnDelete: 使用 OnDelete 更新策略时,在更新 DaemonSet 模板后,只有当你手动删除老的 DaemonSet pods 之后,新的 DaemonSet Pod 才会被自动创建。跟 Kubernetes 1.6 以前的版本类似。
  • RollingUpdate: 这是默认的更新策略。使用 RollingUpdate 更新策略时,在更新 DaemonSet 模板后, 老的 DaemonSet Pod 将被终止,并且将以受控方式自动创建新的 DaemonSet Pod。 更新期间,最多只能有 DaemonSet 的一个 Pod 运行于每个节点上。

执行滚动更新

要启用 DaemonSet 的滚动更新功能,必须设置 .spec.updateStrategy.typeRollingUpdate

  • updateStrategy.type (string)

    守护进程集更新的类型。可以是 "RollingUpdate" 或 "OnDelete"。默认为 RollingUpdate。

  • updateStrategy.rollingUpdate (RollingUpdateDaemonSet)

    滚动更新配置参数。仅在 type 值为 "RollingUpdate" 时出现。

    用于控制守护进程集滚动更新的预期行为的规约。

    • updateStrategy.rollingUpdate.maxSurge (IntOrString)

      对于拥有可用 DaemonSet Pod 的节点而言,**在更新期间可以拥有更新后的 DaemonSet Pod 的最大节点数。**属性值可以是绝对数量(例如:5)或所需 Pod 的百分比(例如:10%)。 如果 maxUnavailable 为 0,则该值不能为 0。绝对数是通过四舍五入从百分比计算得出的,最小值为 1。 默认值为 0。示例:当设置为 30% 时,最多为节点总数的 30% 节点上应该运行守护进程 Pod (即 status.desiredNumberScheduled) 可以在旧 Pod 标记为已删除之前创建一个新 Pod。更新首先在 30% 的节点上启动新的 Pod。 一旦更新的 Pod 可用(就绪时长至少 minReadySeconds 秒),该节点上的旧 DaemonSet pod 就会被标记为已删除。 如果旧 Pod 因任何原因变得不可用(Ready 转换为 false、被驱逐或节点被腾空), 则会立即在该节点上创建更新的 Pod,而不考虑激增限制。 允许激增意味着如果就绪检查失败,任何给定节点上的守护进程集消耗的资源可能会翻倍, 因此资源密集型守护进程集应该考虑到它们可能会在中断期间导致驱逐。

      IntOrString 是一种可以容纳 int32 或字符串的类型。在 JSON 或 YAML 编组和解组中使用时,它会生成或使用内部类型。 例如,这允许你拥有一个可以接受名称或数字的 JSON 字段。

    • updateStrategy.rollingUpdate.maxUnavailable (IntOrString)

      **更新期间不可用的 DaemonSet Pod 的最大数量。**值可以是绝对数(例如:5)或更新开始时 DaemonSet Pod 总数的百分比(例如:10%)。 绝对数是通过四舍五入的百分比计算得出的。如果 maxSurge 为 0,则此值不能为 0 默认值为 1。 例如:当设置为 30% 时,最多节点总数 30% 的、应该运行守护进程的节点总数(即 status.desiredNumberScheduled) 可以在任何给定时间停止更新。更新首先停止最多 30% 的 DaemonSet Pod, 然后在它们的位置启动新的 DaemonSet Pod。 一旦新的 Pod 可用,它就会继续处理其他 DaemonSet Pod,从而确保在更新期间至少 70% 的原始 DaemonSet Pod 数量始终可用。

      IntOrString 是一种可以保存 int32 或字符串的类型。在 JSON 或 YAML 编组和解组中使用时,它会生成或使用内部类型。例如,这允许你拥有一个可以接受名称或数字的 JSON 字段。

  • revisionHistoryLimit (int32)

    用来允许回滚而保留的旧历史记录的数量。此字段是个指针,用来区分明确的零值和未指定的指针。默认值是 10。

  1. 下面的 YAML 包含一个 DaemonSet,其更新策略为 'RollingUpdate':
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  annotations: 
    kubernetes.io/change-cause: "fluentd version is latest"
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # 这些容忍度设置是为了让该守护进程集在控制平面节点上运行
      # 如果你不希望自己的控制平面节点运行 Pod,可以删除它们
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      ## 用于指定 Pod 被删除后等待多长时间再强制终止。
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
  • 创建DaemonSet的Pod

    [root@master daemonset]# kubectl apply -f fluentd-daemonset.yaml
    daemonset.apps/fluentd-elasticsearch configured
    [root@master daemonset]#

  • 查看daemonset和pod

    [root@master daemonset]# kubectl get daemonset -n kube-system
    NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
    fluentd-elasticsearch 3 3 3 3 3 <none> 14m
    [root@master daemonset]#
    [root@master daemonset]# kubectl get pod -n kube-system -o wide
    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    fluentd-elasticsearch-bjh69 1/1 Running 0 2m35s 10.244.0.51 192.168.194.128 <none> <none>
    fluentd-elasticsearch-j59h8 1/1 Running 0 2m33s 10.244.1.112 192.168.194.130 <none> <none>
    fluentd-elasticsearch-jnvfk 1/1 Running 0 2m26s 10.244.2.162 192.168.194.131 <none> <none>
    [root@master daemonset]#

  • 检查 DaemonSet 的滚动更新策略

    [root@master daemonset]# kubectl get ds/fluentd-elasticsearch -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}' -n kube-system
    RollingUpdate
    [root@master daemonset]#

  • 更新DaemonSet

    [root@master daemonset]# kubectl edit -n kube-system ds fluentd-elasticsearch
    daemonset.apps/fluentd-elasticsearch edited
    [root@master daemonset]#

对DaemonSet执行回滚

在创建Daploymen,DaemonSet等等可以回滚的资源类型的时候,一定要添加 annotations信息,该信息是你定义资源简介的,便于你分辨该资源是做什么的,用的镜像版本,等等。

metadata:
  name: fluentd-elasticsearch
  annotations:
    kubernetes.io/change-cause: "fluentd version is latest"
  • 查看DaemonSet使用的镜像版本

    [root@master daemonset]# kubectl -n kube-system get ds fluentd-elasticsearch -o wide
    NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
    fluentd-elasticsearch 3 3 2 1 2 <none> 2m23s fluentd-elasticsearch quay.io/fluentd_elasticsearch/fluentd:v2.5.2 name=fluentd-elasticsearch
    [root@master daemonset]#

  • 查看DaemonSet的历史版本

    [root@master daemonset]# kubectl -n kube-system rollout history ds fluentd-elasticsearch
    daemonset.apps/fluentd-elasticsearch
    REVISION CHANGE-CAUSE
    1 fluentd version is latest
    2 fluentd version is 2.6.0
    3 fluentd version is 2.5.2
    [root@master daemonset]#

说明: 注意 DaemonSet 修订版本只会正向变化。也就是说,回滚完成后,所回滚到的 ControllerRevision 版本号 (.revision 字段) 会增加。 例如,如果用户在系统中有版本 1 和版本 2,并从版本 2 回滚到版本 1, 带有 .revision: 1ControllerRevision 将变为 .revision: 3

  • --to-revision指导回滚到指定版本

说明: 如果 --to-revision 参数未指定,将选中最近的版本。

[root@master daemonset]# kubectl -n kube-system rollout undo --to-revision=1 ds fluentd-elasticsearch
daemonset.apps/fluentd-elasticsearch rolled back
[root@master daemonset]#
  • 再次确认版本(回滚正常)

    [root@master daemonset]# kubectl -n kube-system get ds fluentd-elasticsearch -o wide
    NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
    fluentd-elasticsearch 3 3 3 3 3 <none> 5m31s fluentd-elasticsearch quay.io/fluentd_elasticsearch/fluentd name=fluentd-elasticsearch
    [root@master daemonset]#

相关推荐
皮锤打乌龟5 小时前
(干货)Jenkins使用kubernetes插件连接k8s的认证方式
运维·kubernetes·jenkins
南猿北者6 小时前
docker Network(网络)
网络·docker·容器
sam-1237 小时前
k8s上部署redis高可用集群
redis·docker·k8s
Fanstay9857 小时前
在Linux中使用Nginx和Docker进行项目部署
linux·nginx·docker
ggaofeng9 小时前
通过命令学习k8s
云原生·容器·kubernetes
death bell9 小时前
Docker基础概念
运维·docker·容器
天幕繁星10 小时前
docker desktop es windows解决vm.max_map_count [65530] is too low 问题
windows·elasticsearch·docker·docker desktop
想学习java初学者11 小时前
Docker Compose部署Kafka(非Zookeeper)
docker·容器·kafka
尝尝你的优乐美12 小时前
Docker部署Vue项目原来可以那么好用
前端·nginx·docker
qq_道可道12 小时前
K8S升级到1.24后,切换运行时导致 dind 构建镜像慢根因定位与解决
云原生·容器·kubernetes