污点和容忍机制
节点亲和性(affinity),是 pods 的一种属性,可以将 pods 调度到一类节点上去(作为优先选择或者一个硬性要求)。污点(Taints)则相反,它们允许节点排斥一类 pods。
Taints 和 tolerations 一起工作以确保 pods 不调度到不适合的节点上去。一个或者多个 taints 规则应用于节点,这标记节点不会接受任何没有容忍这些 taints 规则的 pods。Tolerations 规则应用于 pods,并且允许(非强制)这些 pods 调度到匹配 taints 规则的节点上。
概念
可以通过 kubectl taint 给节点添加一个 taint 规则。如:
给节点 node1
标记了一个 taint。这个 taint 包含键 key
,值 value
,以及 taint effect NoSchedule
。这意味着没有 pod 能够调度到 node1
上,除非它有匹配的 toleration。
如果要移除刚刚添加的 taint,可以运行:
你可以在 PodSpec 字段指定一个 toleration。以下两个 tolerations 都匹配上面通过 kubectl taint
创建的 taint,因此有任何一个 toleration 都可以调度到 node1
:
这儿有一个 pod 使用 tolerations 的例子:
如果在 key
和 effect
相同的情况下,toleration 则匹配 taint,其中:
operator
是Exists
(在这种情况下不应指定任何value
),或operator
是Equal
或value
相等
如果不指定 operator
,默认为 Equal
。
注意: 这里有两个特殊的案例:
key
为空,operator
是Exists
则匹配所有的键值和效果,意味着可以 tolerate 一切。
一个空的
effect
匹配所有键为key
的效果。
上面的例子使用了 effect
为 NoSchedule
。或者,你可以使用 effect
为 PreferNoSchedule
。这是 NoSchedule
的 “优先选项” 或者 “软” 版本 -- 系统会尝试避免调度一个没有容忍 taint 的 pod 到该节点上,但是这不是强制的。第三种类型的 effect
是 NoExecute
,后面再描述。
你可以在同一个节点上设置多个 taints,也可以在同一个 pod 上设置多个 tolerations。Kubernetes 处理多个 taints 和 tolerations 的方式就像一个过滤器:遍历一个节点上的所有 taints,然后忽略 pod 上有匹配 toleration 的 taints。其它未忽略的 taints 会对 pod 产生作用。特别是:
如果至少有一个
effect
是NoSchedule
的未忽略的 taint,那么 Kubernetes 将不会在该节点上调度这个 pod如果没有
effect
是NoSchedule
的未忽略 taint,但至少有一个effect
是PreferNoSchedule
的未忽略的 taint,那么 Kubernetes 会尝试不让该 pod 调度到此节点上如果有至少一个
effect
是NoExecute
的未忽略 taint,那么 pod 会从该节点上驱离(如果 pod 已经运行在该节点),并且不会被调度到该节点(如果 pod 没有在节点运行)。
举例来说,有个节点有如下 taint:
pod 有两个 tolerations:
这个案例,pod 不会被调度到这个节点上,因为 pod 没有匹配第三个 taint。但是如果在节点添加 taint 的时 pod 已经运行了,那么 pod 会继续在该节点运行(简单说 NoSchedule
只在调度时生效)。
正常情况下,如果一个 effect
是 NoExecute
的 taint 添加到节点,那些没有容忍此 taint 的将会被直接驱逐,然后那些容忍这个 taint 的 pods 将永远不会被驱逐。另外,一个 effect
是 NoExecute
的 toleration 可以指定一个可选的 tolerationSeconds
字段,以指示当节点 taint 被添加之后 pod 运行在节点的时长,如:
意思是 pod 在节点运行时,当一个匹配的 taint 被添加到该节点后,那么这个 pod 将继续在当前节点运行 3600s,之后会被驱逐。如果 taint 在时间到达之前被移除,那么 pod 不会被驱逐。
用例
Taints 和 tolerations 是一种灵活的方式,将 pod 从节点上移除或驱逐不应运行的 pods。
专用节点: 如果你想将一组节点给一类特定的用户使用,你可以在这些节点上添加 taint(也就是说,
kubectl taint nodes nodename dedicated=groupName:NoSchedule
)并且在他们的 pods 上添加 toleration(通过自定义准入控制器会更容易做到)。这些拥有 tolerations 的 pods 将被允许使用 tainted 的节点以及集群中的其它节点。如果你想要专门使用这些节点并确保只会使用这些节点,那么还需要像给这组节点添加 taint 一样添加一个标签(如,kubectl label nodes nodename edicated=groupName
),并且准入控制器还要添加一个节点 affinity,以要求 pods 只能调度到有dedicated=groupName
标签的节点上。拥有特定硬件的节点: 在一小部分节点具有专用硬件(如 GPU)的集群中,最好将不需要专用硬件的 pods 排除在这些节点之外,从而为专用硬件的 pods 留出空间。这个可以通过给特定硬件的节点添加 taint(如
kubectl taint nodes nodename special=true:NoSchedule
或者kubectl taint nodes nodename special=true:PreferNoSchedule
)并在需要使用这些特定硬件的 pods 上添加相应的 toleration。像在专用节点用例中一样,使用自定义准入控制器来应用 tolerations 可能是最简单的。举例来说,推荐使用 Extended Resources 来表示特殊硬件,用扩展资源的名称 taint 你的特定硬件并且运行 ExtendedResourceToleration 准入控制器。现在,因为节点已经被 tainted,没有相应 toleration 的 pods 不会被调度到这些节点,ExtendedResourceToleration
准入控制器会自动的向 pods 添加正确的 toleration,然后 pod 将会被调度在这些特定硬件的节点上。这样可以确保这些特定硬件的节点被请求此类硬件的 pods 使用,而你不需要手动向 pods 中添加 tolerations。通过 taint 驱逐: 节点出现问题时,可以按每个节点配置驱逐行为,这个后面详解。
通过 taint 驱逐
前面我们提到了 NoExecute
taint effect
,它会影响已经运行在节点的 pods:
没有相应 tolerations 的 pods 将会被直接驱逐
有相应 tolerations 并且未指定
tolerationSeconds
的 pods 永远保持运行有相应 tolerations 且指定
tolerationSeconds
的 pods 会在时间到达之后被驱逐
此外,Kubernetes 1.6 时以 alpha 状态引入该功能来支持表示节点问题。换句话说,当满足特定条件时,节点控制器会自动对节点进行 taints。以下为内建的 taints:
node.kubernetes.io/not-ready
:节点没有就绪。对应 NodeConditionReady
为 "False"node.kubernetes.io/unreachable
:从节点控制器无法访问到节点。对应 NodeConditionReady
为Unknown
node.kubernetes.io/out-of-disk
:节点磁盘空间不足node.kubernetes.io/memory-pressure
:节点内部有压力node.kubernetes.io/disk-pressure
:节点磁盘有压力node.kubernetes.io/network-unavailable
:节点网络不可达node.kubernetes.io/unschedulable
:节点不可调度node.cloudprovider.kubernetes.io/uninitialized
:当使用外部 cloud provider 启动 kubelet 时,将节点设置 taint 以标记为不可用。来自 cloud-controller-manager 的控制器初始化此节点后,kubelet 删除此 taint。
如果要驱逐节点,则节点控制器或者 kubelet 会添加具有 NoExecute
的 effect
相关 taints。如果故障情况恢复正常,则 kubelet 或节点控制器会移除相关的 taints。
注意: 为了维持由于节点问题导致驱逐的速率限制行为,系统实际以速率限制的方式添加 taints。 这样可以防止主节点和节点连接中断发生大规模的 pod 驱逐。
该功能和 tolerationSeconds
结合使用,允许一个 pod 指定当一个或者多个问题的时候在节点运行的时间。
例如,一个具有很多本地状态的应用在网络中断事件中像停留一段事件,以期望网络能够恢复,这样可以避免 pod 被驱逐。这个 pod 的 toleration 设置可以如下:
注意 Kubernetes 会自动添加一个 node.kubernetes.io/not-ready
且 tolerationSeconds=300
的 toleration,除非 pod 配置中已经设置 node.kubernetes.io/not-ready
的 toleration。同样的它会添加一个 node.kubernetes.io/unreachable
且 tolerationSeconds=300
的 toleration,除非 pod 配置中已经设置 node.kubernetes.io/unreachable
的 toleration。
这些自动添加的 tolerations 确保在检测到这些问题之后,pod 默认会在当前节点保留运行 5 分钟。这两个默认 tolerations 被 DefaultTolerationSeconds admission controller 添加。
DaemonSet 创建含有 NoExecute
tolerations 的 pods 针对以下 taints 没有 tolerationSeconds
选项:
node.kubernetes.io/unreachable
node.kubernetes.io/not-ready
这样可以确保 DeamonSet pods 不会因为这些问题而被驱逐。
根据节点状态 taint
节点生命周期控制器自动会为对应节点状态的节点创建 effect
为 NoSchedule
的 taints。同样调度器不会检查节点状态,而是检查 taints。这样可以保证节点状态不会影响到已调度的 pods。用户可以通过添加适当的 Pod tolerations 以选择忽略某些节点问题。
从 Kubernetes 1.8 开始,DaemonSet 控制器自动给所有的 daemons 添加 NoSchedule
tolerations,以阻止 DaemonSets 中断。
node.kubernetes.io/memory-pressure
node.kubernetes.io/disk-pressure
node.kubernetes.io/out-of-disk (only for critical pods)
node.kubernetes.io/unschedulable (1.10 or later)
node.kubernetes.io/network-unavailable (host network only)
添加这些 tolerastions 确保向后兼容。你可以向 DaemonSets 中添加任意的 tolerations。
扩展阅读
最后更新于