DaemonSet特征
DaemonSet
的主要作用是在Kubernetes
集群里运行一个Daemon Pod
时,这个Pod
具有3个特征:
- 1,每个
Pod
在Kubernetes
集群里的每一个节点上运行; - 2,每个节点上只有一个这样的
Pod
实例; - 3,当有新节点加入
Kubernetes
集群后,该Pod
会自动地在新节点上被创建出来;而当旧节点被删除后,它上面的Pod
也会相应地被回收。
DaemonSet工作原理
API
对象定义:
1 | application: apps/v1 |
可以看到,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
文件里。
DaemonSet是如何保证每个节点上有且仅有一个被管理的Pod?
DaemonSet Controller
首先从etcd
里获取所有的节点列表,然后遍历所有节点。这时去检查当前这个节点是否有一个携带了name: fluentd-elasticsearch
标签的Pod
在运行。检查结果可能有3种情况:
- 1,没有这种
Pod
,这就意味着要在该节点上创建这样一个Pod
; - 2,有这种
Pod
,但是数量大于1,说明要删除该节点上多余的Pod
(删除节点上多余的 Pod直接调用 Kubernetes API 就可以了。); - 3,正好只有一个这种
Pod
,说明该节点是正常的。
如何在指定的 Node 上创建新 Pod 呢?
用 nodeSelector,选择 Node 的名字即可。
1 | nodeSelector: |
不过,在 Kubernetes 项目里,nodeSelector 其实已经是一个将要被废弃的字段了。因为现在有了一个新的、功能更完善的字段可以代替它,即:nodeAffinity
。
1 | apiVersion: v1 |
所以,我们的 DaemonSet Controller 会在创建 Pod 的时候,自动在这个 Pod 的 API对象里,加上这样一个 nodeAffinity 定义。其中,需要绑定的节点名字,正是当前正在遍历的这个 Node。
当然,DaemonSet 并不需要修改用户提交的 YAML 文件里的 Pod 模板,而是在向Kubernetes 发起请求之前,直接修改根据模板生成的 Pod 对象。
此外,DaemonSet 还会给这个 Pod 自动加上另外一个与调度相关的字段,叫作tolerations。
这个字段意味着这个 Pod,会“容忍”(Toleration)某些 Node 的“污点”(Taint)。
而 DaemonSet 自动加上的 tolerations 字段,格式如下所示:
1 | apiVersion: v1 |
而在正常情况下,被标记了 unschedulable“污点”的 Node,是不会有任何 Pod 被调度上去的(effect: NoSchedule)。可是,DaemonSet 自动地给被管理的 Pod 加上了这个特殊的 Toleration,就使得这些 Pod 可以忽略这个限制,继而保证每个节点上都会被调度一个 Pod。
当然,如果这个节点有故障的话,这个 Pod 可能会启动失败,而 DaemonSet则会始终尝试下去,直到 Pod 启动成功。
因此,DaemonSet 的“过人之处”,其实就是依靠Toleration 实现的。
假如当前 DaemonSet 管理的,是一个网络插件的 Agent Pod,那么你就必须在这个DaemonSet 的 YAML 文件里,给它的 Pod 模板加上一个能够“容忍”node.kubernetes.io/network-unavailable“污点”的 Toleration。
例如:
1 | ... |
在 Kubernetes 项目中,当一个节点的网络插件尚未安装时,这个节点就会被自动加上名node.kubernetes.io/network-unavailable
的“污点”。而通过这样一个 Toleration,调度器在调度这个 Pod 的时候,就会忽略当前节点上的“污点”,从而成功地将网络插件的 Agent 组件调度到这台机器上启动起来。
这种机制,正是我们在部署 Kubernetes 集群的时候,能够先部署 Kubernetes 本身、再部署网络插件的根本原因:因为当时我们所创建的 Weave 的 YAML,实际上就是一个DaemonSet。
总结
- 相比于
Deployment
,DaemonSet
只管理Pod
对象,然后通过nodeAffinity
和Toleration
这两个调度器的小功能,保证了每个节点上有且只有一个 Pod。