Deployment是 Kubernetes 中用于处理无状态服务的资源,而StatefulSet是用于支持有状态服务的资源,这两种不同的资源从状态的角度对服务进行了划分,而 DaemonSet 从不同的维度解决了集群中的问题 — 如何同时在集群中的所有节点上提供基础服务和守护进程。
我们在这里将介绍 DaemonSet 如何进行状态的同步、Pod 与节点(Node)之间的调度方式和滚动更新的过程以及实现原理。
概述
DaemonSet 可以保证集群中所有的或者部分的节点都能够运行同一份 Pod 副本,每当有新的节点被加入到集群时,Pod 就会在目标的节点上启动,如果节点被从集群中剔除,节点上的 Pod 也会被垃圾收集器清除;DaemonSet 的作用就像是计算机中的守护进程,它能够运行集群存储、日志收集和监控等『守护进程』,这些服务一般是集群中必备的基础服务。
Google Cloud 的 Kubernetes 集群就会在所有的节点上启动 fluentd 和 Prometheus 来收集节点上的日志和监控数据,想要创建用于日志收集的守护进程其实非常简单,我们可以使用如下所示的代码:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
containers:
- name: fluentd-elasticsearch
image: k8s.gcr.io/fluentd-elasticsearch:1.20
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
YAML
当我们使用 kubectl apply -f
创建上述的 DaemonSet 时,它会在 Kubernetes 集群的 kube-system
命名空间中创建 DaemonSet 资源并在所有的节点上创建新的 Pod:
$ kubectl get daemonsets.apps fluentd-elasticsearch --namespace kube-system
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
fluentd-elasticsearch 1 1 1 1 1 <none> 19h
$ kubectl get pods --namespace kube-system --label name=fluentd-elasticsearch
NAME READY STATUS RESTARTS AGE
fluentd-elasticsearch-kvtwj 1/1 Running 0 19h
Go
由于集群中只存在一个 Pod,所以 Kubernetes 只会在该节点上创建一个 Pod,如果我们向当前的集群中增加新的节点时,Kubernetes 就会创建在新节点上创建新的副本,总的来说,我们能够得到以下的拓扑结构:
集群中的 Pod 和 Node 一一对应,而 DaemonSet 会管理全部机器上的 Pod 副本,负责对它们进行更新和删除。
实现原理
所有的DaemonSet 都是由控制器负责管理的,与其他的资源一样,用于管理 DaemonSet 的控制器是 DaemonSetsController
,该控制器会监听 DaemonSet、ControllerRevision、Pod 和 Node 资源的变动。
大多数的触发事件最终都会将一个待处理的 DaemonSet 资源入栈,下游 DaemonSetsController
持有的多个工作协程就会从队列里面取出资源进行消费和同步。
删除
与Deployment、ReplicaSet 和 StatefulSet一样 ,DaemonSet 的删除也会导致它持有的 Pod 的删除,如果我们使用如下的命令删除该对象,我们能观察到如下的现象:
$ kubectl delete daemonsets.apps fluentd-elasticsearch --namespace kube-system
daemonset.apps "fluentd-elasticsearch" deleted
$ kubectl get pods --watch --namespace kube-system
fluentd-elasticsearch-wvffx 1/1 Terminating 0 14s
Bash
这部分的工作就都是由 Kubernetes 中的垃圾收集器完成的,读者可以阅读[垃圾收集器][Link 1]一文了解集群中的不同对象是如何进行关联的以及在删除单一对象时如何触发级联删除的原理。
总结
DaemonSet 其实就是 Kubernetes 中的守护进程,它会在每一个节点上创建能够提供服务的副本,很多云服务商都会使用 DaemonSet 在所有的节点上内置一些用于提供日志收集、统计分析和安全策略的服务。
在研究DaemonSet 的调度策略的过程中,我们其实能够通过一些历史的 issue 和 PR 了解到 DaemonSet 调度策略改动的原因,也能让我们对于 Kubernetes 的演进过程和设计决策有一个比较清楚的认识