大家好啊,咱们的Kubernetes学习笔记时隔两月终于又迎来了更新,前面咱们介绍的Deployment、Service、Statefulset 相信看过文章的同学都已经明白他们各自的能力和使用场景了,如果已经没啥印象了或者是还没看过的同学,推荐看一下之前讲他们三个的文章。

K8s里的Deployment、Service、Statefulset这三个控制器离我们的应用层最近所以接触到的机会比较多,今天我来给大家介绍另外一个控制器 DaemonSet,它堪称是集群幕后的英雄。

我做个比喻大家就马上能明白DaemonSet的作用,假如K8s集群是一个大House,Deployment、Service、Statefulset 他们几个就是给屋子(Node)搞软装的,你可以用他们把屋子搞成餐厅、客厅、卧室等各种功能房,而DamonSet就是给屋子搞水电网、刷墙这些硬装的,而对于K8s集群来说它的水电网不就是--网络、存储、监控等等这些吗?

好了,明白了 DaemonSet 就是给 K8s 集群搞硬装的这个角色后,接下来咱们就展开来说一下它的特性和怎么使用它。

什么是DaemonSet

DaemonSet的作用是,确保可用节点上都能运行一个守护进程类的 Pod,这个 Pod 如下三个特点

  1. 这个 Pod 运行在 K8s 集群里的每一个节点(Node)上。

  2. 每个节点上有且只有一个被指定DamonSet创建的 Pod实例(当然我们可以创建不同作用的DamonSet,每个都会在节点上创建一个对应的Pod实例) 。

  3. 当有新的节点加入 Kubernetes 集群后,该 Pod 会自动地在新节点上被创建出来,而当旧节点被删除后,它上面的 Pod 也相应地会被回收掉。

DaemonSet 是 K8s 集群必不可少的组成部分,它便于集群管理员跨所有节点或部分节点轻松配置服务(pod)。

DaemonSet的使用场景

DaemonSets 可以通过在所有节点上部署 Pod 来分配维护集群和支持服务类的任务,从而提高 K8s 集群的性能。它非常适合用于长时间运行的服务,例如监控或日志收集。以下是 DaemonSet 的一些使用场景:

  • 在每个节点上挂载集群存储例如 glusterd 和 ceph,操作容易的Volume目录。

  • 在每个节点上运行一个守护进程来收集日志,例如 Fluentd 和 logstash。

  • 在每个节点上运行一个守护进程来监控节点,例如 Prometheus Node Exporter、collectd 或 Datadog(AWS上的服务)的Agent。

DaemonSet Pod的调度

默认情况下,Pod 运行在哪个节点上由 K8s 调度程序决定。但是,DaemonSet pod 是由 DaemonSet 控制器创建和调度的。使用 DaemonSet 控制器会导致 Pod 行为不一致和 Pod 优先级抢占的问题。

为了解决这个问题,K8s 允许用户通过给DaemonSet Pod 设置 NodeAffinity (节点亲密性)来使用 K8s 调度器把DaemonSet Pod调度到目标节点上。

下面是一个示例 NodeAffinity 配置:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd            
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

上面我们通过配置 NodeAffinity 让Pod只能调度到持有"disktype=ssd"标签的节点上去。

  • requiredDuringSchedulingIgnoredDuringExecution:它的意思是说,这个 nodeAffinity 必须在每次调度的时候予以考虑,你也可以设置在某些情况下不考虑这个 NodeAffinity。

  • nodeSelectorTerms 里指定的 disktype In (ssd) 表示:这个 Pod,将来只允许运行在"metadata.lables.disktype=ssd"的节点上。

节点亲密性更详细的解释可以去看一下我之前写的文章 玩转K8s Pod滚动更新里关注NodeAffinity章节的内容。

此外,DaemonSet 还会给 Pod 容忍度 (tolerations)自动加上容忍node.kubernetes.io/unschedulable:NoSchedule这个污点的配置。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  tolerations:
  - key: node.kubernetes.io/unschedulable
    operator: Exists
    effect: NoSchedule

K8s 集群中新加入的节点在未完成准备工作之前都会被标记上这个污点(taints),不允许Pod调度到节点上来,而DaemonSet 自动给它Pod加上容忍这个污点的配置,就让它创建的Pod有机会提前入场,在节点上搭建好各种"硬装"后再供集群进行调度。

创建DaemonSet的YAML模板

跟 K8s 里的其他组件一样,DaemonSets 也是使用 YAML 文件配置的。我们来看看 DaemonSet 配置文件的结构。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: test-daemonset
  namespace: test-daemonset-namespace
  Labels:
    app-type: test-app-type
spec:
  template:
    metadata:
      labels:
        name: test-daemonset-container
        image: "image to use for container"
  selector:
    matchLabels:
      name: test-daemonset-container

跟其他组件的配置一样,apiVersion、kind 和 metadata 是每个 K8s 组件配置中的必填字段。

  • template:也叫Pod模板,在Deployment、StatefulSet的配置里我们都已经见过了,这里是要部署到每个节点上的Pod的定义。DaemonSet 中的 pod 模板必须将其 RestartPolicy 设置为“Always”,如果没有指定 RestartPolicy,默认情况下它就是“Always”。

  • selector: DaemonSet 管理的 Pod 的标签选择器。该值必须是 Pod 模板中指定的标签。(在上面的例子中,我们使用了名称:test-daemonset-container 作为选择器。)这个值是固定的,在初始创建 DaemonSet 后不能更改。

其他可选的配置字段有:

  • template.spec.affinity – 配置Pod的节点亲密性,文章开头说过,可以通过 NodeAffinity 配置限定DaemonSet控制器创建的Pod只被调度器调度到满足Affinity配置的节点上。

创建 DaemonSet

现在让我们创建一个示例的DaemonSet。它将管理一个使用"fluentd-elasticsearch"镜像运行容器的Pod,它创建的Pod会在 K8s 集群的每个节点上运行,通过 fluentd 将节点上 Docker 容器里的日志转发到 ElasticSearch 中。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch-test
  namespace: default # Name Space
  labels:
    k8s-app: fluentd-logging
spec:
  selector: # Selector
    matchLabels: 
      name: fluentd-elasticsearch-test-deamonset
  template: # Pod Template
    metadata:
      labels:
        name: fluentd-elasticsearch-test-deamonset
    spec:
      tolerations: # Tolerations
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers: # Container Details
      - 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
        - 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

有了 DaemonSet 的YAML配置文件后,接下来,让我们使用 kubectl create 命令创建 DaemonSet 并检索 DaemonSet 和它创建的 Pod 信息:

创建DaemonSet

➜  ✗ kubectl apply -f daemonset.yaml 
daemonset.apps/fluentd-elasticsearch-test created

查看是否创建成功

➜ ✗ kubectl get pods
NAME                               READY   STATUS              RESTARTS   AGE
fluentd-elasticsearch-test-pb5qw   0/1     ContainerCreating   0          18s


➜ ✗ kubectl describe pod fluentd-elasticsearch-test-pb5qw
......
Events:
  Type    Reason     Age        From                     Message
  ----    ------     ----       ----                     -------
  Normal  Scheduled  <unknown>                           Successfully assigned default/fluentd-elasticsearch-test-pb5qw to docker-desktop
  Normal  Pulling    32s        kubelet, docker-desktop  Pulling image "quay.io/fluentd_elasticsearch/fluentd:v2.5.2"
  Normal  Pulled     6s         kubelet, docker-desktop  Successfully pulled image "quay.io/fluentd_elasticsearch/fluentd:v2.5.2" in 25.3910795s
  Normal  Created    6s         kubelet, docker-desktop  Created container fluentd-elasticsearch
  Normal  Started    5s         kubelet, docker-desktop  Started container fluentd-elasticsearch
  
  
➜ ✗ kubectl get pod -o wide
NAME                               READY   STATUS    RESTARTS   AGE    IP          NODE             NOMINATED NODE   READINESS GATES
fluentd-elasticsearch-test-pb5qw   1/1     Running   0          5m7s   10.1.0.38   docker-desktop   <none>           <none>

从上面的输出可以看出,我们的 DaemonSet 已经部署成功。可以看到我们在定义文件里并没有像Deployment那样通过 replicas 指定Pod的数量,那是因为 DaemonSet 会根据集群上可用的节点,将 Pod 自动扩展到配置里指定的可用节点上。这里因为我是在电脑上Docker桌面应用自带的K8s集群,只有一个节点,所以DaemonSet 只创建出了一个Pod。

更新和删除DaemonSet

更新和删除DaemonSet的方法跟其他组件没有什么两样,这里就不再多说了,直接上命令

## 更新完配置文件后直接apply
kubectl apply -f daemonset.yaml 
## 删除
kubectl delete daemonset <<daemonset-name>>

总结

好了,这篇介绍 DaemonSet 的文章就到这里,如果不是搞 K8s 相关工作的,DaemonSet 平常可能接触不到,这篇文章也算是一个科普,记住我那个比喻:Deployment 和 StatefulSet 这些控制器是给 K8s 集群搞软装的,而 DaemonSet 是给集群这个大 House 的屋子搞硬装的,所以 DaemonSet 会在节点这个"屋子"准备好之前先入场"装修"完,后面才能让 Deployment 它们搞"软装"

- END -

扫码关注公众号「网管叨bi叨」

给网管个星标,第一时间吸我的知识 👆

网管为大家整理了一本超实用的《Go 开发参考书》收集了70多条开发实践。去公众号回复【gocookbook】即刻领取!

觉得有用就点个在看  👇👇👇

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐