zl程序教程

您现在的位置是:首页 >  后端

当前栏目

k8s学习之路 | k8s 工作负载 DaemonSet

k8s负载学习 工作 DaemonSet
2023-09-14 09:15:27 时间

1. DaemonSet 基础

1.1 什么是 DS

DaemonSet 工作负载,确保了全部(某一些)节点运行一个 Pod 副本

  • 如果有节点加入集群,自动为该节点新增一个 Pod

  • 如果有节点从集群中移除,该节点上的 Pod 就会被回收

  • 删除工作负载 DaemonSet 就会删除它创建的所有节点的 Pod

1.2 DS 的典型用法

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

1.3 如何编写 DS 资源

还是老规矩:kubectl explain ds

apiVersion   <string>
kind <string>
metadata     <Object>
spec <Object>

image-20230307145752337

kubectl explain ds.spec

image-20230307145808351

必须字段

  1. apiVersionkindmetadata
  2. .spec
    • Pod 模块:.spec.template
    • Pod 选择算符:.spec.selector

特定节点运行

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

1.4 DS 示例文件

###ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      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

运行查看一下结果

image-20230307151453931

  • 没有像以前设置 Pod 的副本数多少,因为 DS资源会在每一个节点只运行一个,控制节点除外,好像要特殊设置才行,遇到了我再看看

1.5 DS Pod 是如何被调度的

  1. DaemonSet 控制器为每个符合条件的节点创建一个 Pod,并添加 Pod 的 spec.affinity.nodeAffinity 字段以匹配目标主机:kubectl get ds fluentd-elasticsearch

image-20230307152147922

  1. Pod 创建以后,默认的调度程序通常通过设置 Pod 的 .spec.nodeName 字段来接管 Pod 并将 Pod 绑定到目标主机,如果新的 Pod 无法放在节点上,默认的调度程序可能会根据新 Pod 的优先级抢占某些现存的 Pod

image-20230307153003328

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

image-20230307153100396

关于亲和性、污点、容忍度后续进行一个补充

1.6 更新 DS

  • 如果节点的标签被修改,DaemonSet 将立刻向新匹配上的节点添加 Pod, 同时删除不匹配的节点上的 Pod

  • 你可以修改 DaemonSet 创建的 Pod。不过并非 Pod 的所有字段都可更新。 下次当某节点(即使具有相同的名称)被创建时,DaemonSet 控制器还会使用最初的模板

  • 你可以删除一个 DaemonSet。如果使用 kubectl 并指定 --cascade=orphan 选项, 则 Pod 将被保留在节点上。接下来如果创建使用相同选择算符的新 DaemonSet, 新的 DaemonSet 会收养已有的 Pod。 如果有 Pod 需要被替换,DaemonSet 会根据其 updateStrategy 来替换

  • 可以对 DaemonSet 执行滚动更新操作

1.7 DS 替代方案

参考官网地址:

https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/daemonset/#required-fields

  • init 脚本
  • 裸 Pod
  • 静态 Pod
  • Deploy

1.8 DS 工作负载字段描述

参考官网地址:

https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/

  • apiVersion: apps/v1

  • kind: DaemonSet

  • metadata

    标准的对象元数据

  • spec

    此守护进程集的预期行为

    • selector 必需

      对由守护进程集管理的 Pod 的标签查询。Pod 必须匹配此查询才能被此 DaemonSet 控制。 查询条件必须与 Pod 模板的标签匹配

    • template 必需

      描述将要创建的 Pod 的对象。DaemonSet 将在与模板的节点选择器匹配的每个节点上 (如果未指定节点选择器,则在每个节点上)准确创建此 Pod 的副本

    • minReadySeconds (int32)

      新建的 DaemonSet Pod 应该在没有任何容器崩溃的情况下处于就绪状态的最小秒数,这样它才会被认为是可用的。 默认为 0(Pod 准备就绪后将被视为可用)

    • updateStrategy (DaemonSetUpdateStrategy)

      用新 Pod 替换现有 DaemonSet Pod 的更新策略

    • revisionHistoryLimit (int32)

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

2. DaemonSet 的使用

2.1 每个节点运行一个

我打算每个节点都运行一个基于 nginx 的 Pod

示例文件

###ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-demo
  labels:
    k8s-app: nginx
spec:
  selector:
    matchLabels:
      name: app
  template:
    metadata:
      labels:
        name: app
    spec:
      tolerations:
      #这些容忍度设置是为了让该守护进程集在控制平面节点上运行
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: nginx
        image: nginx:1.23
        imagePullPolicy: Never  ##这个镜像拉取我是真的难受 直接弄本地来吧

运行查看一下

image-20230307163300030

  • 控制节点也是可以运行的,因为我加了一个东西
  • 每个节点都只运行一个 Pod

尝试删除一个 Pod

##尝试删除一下 k8s-02上面的pod,跟着一下状态
kubectl delete pod ds-demo-dlzh4

image-20230307163544294

  • 可以看到最终还是会再该节点启动一个 Pod

2.2 DS 更新策略

DaemonSet 有两种更新策略:

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

kubectl explain ds.spec.updateStrategy

image-20230307165119899

2.3 滚动更新

我要对上面的资源更新一个镜像,修改一下 yaml 文件

###ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-demo
  labels:
    k8s-app: nginx
spec:
  selector:
    matchLabels:
      name: app
  updateStrategy:  ## 更新
    type: RollingUpdate  ## 更新策略
    rollingUpdate:  ##更新参数,仅在 type 值为 "RollingUpdate" 时出现
      maxUnavailable: 1 ##更新期间不可用的 DaemonSet Pod 的最大数量
  template:
    metadata:
      labels:
        name: app
    spec:
      tolerations:
      #这些容忍度设置是为了让该守护进程集在控制平面节点上运行
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: nginx
        image: nginx:1.23.3
        imagePullPolicy: Never  ##这个镜像拉取我是真的难受 直接弄本地来吧

更新一下,并跟踪状态

  • 停一个,更新一个;停一个,更新一个;停一个;更新一个

image-20230307170135739

查看更新状态

[root@k8s-01 k8s-yaml]# kubectl rollout status ds ds-demo
daemon set "ds-demo" successfully rolled out
[root@k8s-01 k8s-yaml]#

2.4 OnDelete 更新

我们再更新一次,换一种方式

###ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-demo
  labels:
    k8s-app: nginx
spec:
  selector:
    matchLabels:
      name: app
  updateStrategy:  ## 更新
    type: OnDelete   ## 更新策略
  template:
    metadata:
      labels:
        name: app
    spec:
      tolerations:
      #这些容忍度设置是为了让该守护进程集在控制平面节点上运行
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: nginx
        image: nginx:1.23
        imagePullPolicy: Never  ##这个镜像拉取我是真的难受 直接弄本地来吧

更新运行看状态kubectl apply -f ds.yaml

  • 可以看到更新方式改变了,所以这次更新没反应

image-20230307170505019

杀死一个 Pod 试试

[root@k8s-01 k8s-yaml]# kubectl get pod -owide
NAME            READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
ds-demo-6fxtx   1/1     Running   0          6m44s   192.168.0.135   k8s-02   <none>           <none>
ds-demo-8zlpb   1/1     Running   0          6m29s   192.168.0.74    k8s-01   <none>           <none>
ds-demo-9r7hv   1/1     Running   0          6m18s   192.168.0.7     k8s-03   <none>           <none>
[root@k8s-01 k8s-yaml]# kubectl delete pod ds-demo-8zlpb
pod "ds-demo-8zlpb" deleted
[root@k8s-01 k8s-yaml]#

image-20230307170652752

看一下是否更新完成:镜像是否改变 kubectl describe pod ds-demo-qgd49

  • 可以看到镜像已经更新了
  • 这种类型的更新细节就是:只有当你手动删除老的 DaemonSet pods 之后,新的 DaemonSet Pod 才会被自动创建。

image-20230307170734065

2.6 更新回滚

DS 修订版本

kubectl explain ds.spec 中的 [revisionHistoryLimit] 确认了版本保留的数量,默认就是10

查看 DS 的所有版本

kubectl rollout history ds ds-demo

image-20230307172409541

查看指定版本的详细信息

kubectl rollout history ds ds-demo --revision=2

image-20230307172605686

回滚到指定版本

kubectl rollout undo ds ds-demo --to-revision=2

查看更新结果

因为我之前改过更新策略,我必须杀死 Pod 后,才能回退成功

image-20230307172916918

查看回滚进度

kubectl rollout status ds ds-demo

  • 看提示是因为我的更新策略不适用这种查询方式
[root@k8s-01 k8s-yaml]# kubectl rollout status ds ds-demo
error: rollout status is only available for RollingUpdate strategy type
[root@k8s-01 k8s-yaml]#

2.5 故障排查

如果 DS 更新卡住的话,可能有以下一些原因:

  • 节点可用资源耗尽
  • 不完整的滚动更新
  • 时钟偏差:如果在 DaemonSet 中指定了 .spec.minReadySeconds,主控节点和工作节点之间的时钟偏差会使 DaemonSet 无法检测到正确的滚动更新进度

image-20230307173358512