Kubernetes之DaemonSet
DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
使用 DaemonSet 的一些典型用法:
- 运行集群存储 daemon,例如在每个 Node 上运行 glusterd、ceph。
- 在每个 Node 上运行日志收集 daemon,例如fluentd、logstash。
- 在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、collectd、Datadog 代理、New Relic 代理,或 Ganglia gmond。
创建DaemonSet:
以下是DaemonSet的示例spec文件,运行fluentd-elasticsearch image:
1 |
|
以上DaemonSet中没有RestartPolicy字段,默认为Always。如果有的话,必需将值设置成Always,否则在创建时出现不可用错误。
DaemonSet同样会受到Taint(污点)的抵制,如果不在Pod中配置匹配的Toleration(容忍度),那么DaemonSet不会在拥有Taint(污点)属性的node上部署Pod。上例中有如下内容:
1 |
|
原因就是系统默认为master节点增加了 “node-role.kubernetes.io/master”的Taint(污点),以抵制普通Pod部署在Master节点上,为了使master成为专用节点而添加的Taint(污点)。因为我们预期上例DaemonSet在集群内全局部署,因此需要加入相匹配的Toleration(容忍度)这样Master节点也会部署DaemonSet。
仅在相同的 Node 上运行 Pod:
如果指定了 .spec.template.spec.nodeSelector,则DaemonSet只会在满足条件的node上部署pod。 类似这种情况,可以指定 .spec.template.spec.affinity,然后 DaemonSet Controller 将在能够与 Node Affinity 匹配的节点上创建 Pod。 如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。
总之,可以通过Taint(污点)、Toleration(容忍度)、Affinity(亲和力)、node label控制DaemonSet部署pod的节点范围。
系统如何调度DaemonSet pod(自1.12起默认禁用):
默认情况下DaemonSet在创建pod时如果为其增加.spec.template.spec.nodeName字段,也就是说所创建的pod运行在那个节上在创建阶段就已经确定,所以DaemonSet中的pod实际上没有接受kubernetes scheduler的调度,它不需要调度,因此产生以下两个特性:
- DaemonSet中的pod不遵从节点的unreachable条件,也就是即使节点被系统判定为不可达,DaemonSet仍然试图在其上部署pod。
- 在集群引导阶段,即使kubernetes scheduler还没有部署生效,DaemonSet仍然可以将pod部署到集群中的任何节点,此特性主要是在集群引导阶段使用。
因为DaemonSet不同于常规pod的调度特性,它带来两个问题:
- pod行为不一致。普通pod被创建以后等待调度的阶段称为pending,因为DaemonSet中的pod无需调度,因而无此状态,用户会因此产生迷惑。
- pod优先级特性由kubernetes scheduler实现,DaemonSet无此特性。当系统打开pod优先级功能时,pod优先级特性会被DaemonSet忽略,DaemonSet控制器将自己做出调度决策。
为了解决以上两个问题可以使用ScheduleDaemonSetPods,ScheduleDaemonSetPods允许您使用默认调度器(而不是DaemonSet controller)调度DaemonSets,方法是向DaemonSet pods添加NodeAffinity项,而不是.spec.template.spec.nodeName。然后使用默认调度程序将pod绑定到目标主机。如果DaemonSet pod的节点关联性已经存在,则替换它。DaemonSet controller仅在创建或修改DaemonSet pods时执行这些操作,并且对DaemonSet的spec.template不做任何更改。
1 |
|
其中”target-host-name”就是原来.spec.nodeName的值,这样pod就会被kubernetes scheduler调度。通过以上操作解决了上述两个问题。但DaemonSet的调度有自己因有的特性,在上文中提到的“不受节点unreachable条件限制”,为了使DaemonSet在使用kubernetes scheduler时仍然保持此特性需要打开集群的”TaintNodesByCondition”特性。
如果DaemonSet使用主机网络那么必需在DaemonSet中添加如下的Toleration:
1 |
|
DaemonSet自动添加的Toleration:
系统在某此条件下会自动为节点添加Taint,比如硬盘不足、网络不可达等,以阻止新pod往不满足条件的节点上调度。但DaemonSet的目的是在全部有资格的node上部署,不希望被这种Taint打断,因经系统也默认为DaemonSet上的pod添加Toleration。如下表:
容忍度 | Effect | 版本 | 描述 |
---|---|---|---|
node.kubernetes.io/not-ready | NoExecute | 1.13+ | 当存在诸如网络分区之类的节点问题时,不会驱逐DaemonSet pod。 |
node.kubernetes.io/unreachable | NoExecute | 1.13+ | 当存在诸如网络分区之类的节点问题时,不会驱逐DaemonSet pod。 |
node.kubernetes.io/disk-pressure | NoSchedule | 1.8+ | |
node.kubernetes.io/memory-pressure | NoSchedule | 1.8+ | |
node.kubernetes.io/unschedulable | NoExecute | 1.12+ | DaemonSet pods可以通过默认调度程序容忍不可调度的属性。 |
node.kubernetes.io/unreachable | NoExecute | 1.12+ | 使用主机网络的DaemonSet pod可以通过默认调度程序容忍网络不可用的属性。 |
对 DaemonSet 执行回滚
找到想要 DaemonSet 回滚到的历史版本(revision)
列出 DaemonSet 的所有版本:
1 |
|
该命令返回 DaemonSet 版本列表:
1 |
|
执行以下命令,来查看指定版本的详细信息:
1 |
|
该命令返回相应版本的详细信息:
1 |
|
回滚到指定版本
1 |
|
如果成功,命令会返回:
1 |
|
如果 --to-revision
参数未指定,将选中最近的版本。
观察 DaemonSet 回滚进度kubectl rollout undo daemonset
向服务器表明启动 DaemonSet
回滚。 真正的回滚是在服务器端异步完成的。
执行以下命令,来观察DaemonSet
回滚进度:
1 |
|
回滚完成时,输出形如:
1 |
|