Kubernetes 容器化守护进程的意义:DaemonSet

今天我和你分享的主题是:容器化守护进程的意义之 DaemonSet。

在上一篇文章中,我和你详细分享了使用 StatefulSet 编排“有状态应用”的过程。从中不难看出,StatefulSet 其实就是对现有典型运维业务的容器化抽象。也就是说,你一定有方法在不使用 Kubernetes、甚至不使用容器的情况下,自己 DIY 一个类似的方案出来。但是,一旦涉及到升级、版本管理等更工程化的能力,Kubernetes 的好处,才会更加凸现。

比如,如何对 StatefulSet 进行“滚动更新”(rolling update)?

很简单。你只要修改 StatefulSet 的 Pod 模板,就会自动触发“滚动更新”:

$ kubectl patch statefulset mysql --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"mysql:5.7.23"}]'
statefulset.apps/mysql patched

在这里,我使用了 kubectl patch 命令。它的意思是,以“补丁”的方式(JSON 格式的)修改一个 API 对象的指定字段,也就是我在后面指定的“spec/template/spec/containers/0/image”。

这样,StatefulSet Controller 就会按照与 Pod 编号相反的顺序,从最后一个 Pod 开始,逐一更新这个 StatefulSet 管理的每个 Pod。而如果更新发生了错误,这次“滚动更新”就会停止。此外,StatefulSet 的“滚动更新”还允许我们进行更精细的控制,比如金丝雀发布(Canary Deploy)或者灰度发布,这意味着应用的多个实例中被指定的一部分不会被更新到最新的版本。

这个字段,正是 StatefulSet 的 spec.updateStrategy.rollingUpdate 的 partition 字段。

比如,现在我将前面这个 StatefulSet 的 partition 字段设置为 2:

$ kubectl patch statefulset mysql -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
statefulset.apps/mysql patched

其中,kubectl patch 命令后面的参数(JSON 格式的),就是 partition 字段在 API 对象里的路径。所以,上述操作等同于直接使用 kubectl edit 命令,打开这个对象,把 partition 字段修改为 2。

这样,我就指定了当 Pod 模板发生变化的时候,比如 MySQL 镜像更新到 5.7.23,那么只有序号大于或者等于 2 的 Pod 会被更新到这个版本。并且,如果你删除或者重启了序号小于 2 的 Pod,等它再次启动后,也会保持原先的 5.7.2 版本,绝不会被升级到 5.7.23 版本。

StatefulSet 可以说是 Kubernetes 项目中最为复杂的编排对象,希望你课后能认真消化,动手实践一下这个例子。

而在今天这篇文章中,我会为你重点讲解一个相对轻松的知识点:DaemonSet。

顾名思义,DaemonSet 的主要作用,是让你在 Kubernetes 集群里,运行一个 Daemon Pod。 所以,这个 Pod 有如下三个特征:

  1. 这个 Pod 运行在 Kubernetes 集群里的每一个节点(Node)上,每个节点上只有一个这样的 Pod 实例
  2. 当有新的节点加入 Kubernetes 集群后,该 Pod 会自动地在新节点上被创建出来
  3. 而当旧节点被删除后,它上面的 Pod 也相应地会被回收掉。 

这个机制听起来很简单,但 Daemon Pod 的意义确实是非常重要的。我随便给你列举几个例子: 

  • 各种网络插件的 Agent 组件,都必须运行在每一个节点上,用来处理这个节点上的容器网络
  • 各种存储插件的 Agent 组件,也必须运行在每一个节点上,用来在这个节点上挂载远程存储目录,操作容器的 Volume 目录
  • 各种监控组件和日志组件,也必须运行在每一个节点上,负责这个节点上的监控信息和日志搜集。 

为了弄清楚 DaemonSet 的工作原理,我们还是按照老规矩,先从它的 API 对象的定义说起。 

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

 这个 DaemonSet,管理的是一个 fluentd-elasticsearch 镜像的 Pod。这个镜像的功能非常实用:通过 fluentd 将 Docker 容器里的日志转发到 ElasticSearch 中。

可以看到,DaemonSet 跟 Deployment 其实非常相似,只不过是没有 replicas 字段;它也使用 selector 选择管理所有携带了 name=fluentd-elasticsearch 标签的 Pod。

而这些 Pod 的模板,也是用 template 字段定义的。在这个字段中,我们定义了一个使用 fluentd-elasticsearch:1.20 镜像的容器,而且这个容器挂载了两个 hostPath 类型的 Volume,分别对应宿主机的 /var/log 目录和 /var/lib/docker/containers 目录。

显然,fluentd 启动之后,它会从这两个目录里搜集日志信息,并转发给 ElasticSearch 保存。这样,我们通过 ElasticSearch 就可以很方便地检索这些日志了。

需要注意的是,Docker 容器里应用的日志,默认会保存在宿主机的 /var/lib/docker/containers/{ {. 容器 ID}}/{ {. 容器 ID}}-json.log 文件里,所以这个目录正是 fluentd 的搜集目标。

那么,DaemonSet 又是如何保证每个 Node 上有且只有一个被管理的 Pod 呢?

显然,这是一个典型的“控制器模型”能够处理的问题。

DaemonSet Controller,首先从 Etcd 里获取所有的 Node 列表,然后遍历所有的 Node。这时,它就可以很容易地去检查,当前这个 Node 上是不是有一个携带了 name=fluentd-elasticsearch 标签的 Pod 在运行。 

而检查的结果,可能有这么三种情况:

  1. 没有这种 Pod,那么就意味着要在这个 Node 上创建这样一个 Pod
  2. 有这种 Pod,但是数量大于 1,那就说明要把多余的 Pod 从这个 Node 上删除掉
  3. 正好只有一个这种 Pod,那说明这个节点是正常的。 

其中,删除节点(Node)上多余的 Pod 非常简单,直接调用 Kubernetes API 就可以了。 

猜你喜欢

转载自blog.csdn.net/qq_34556414/article/details/125049403
今日推荐