关于 Kubernetes 系列其他文章的传送门
-
《 k8s 中的调度器 – 亲和性、污点和容忍性 》 您当前所在位置

一、k8s 中的调度器¶
k8s 中调度器也是插件化的,可以指定 Pod 使用哪种调度器,默认不指则使用 kube-scheduler 中默认的 default-scheduler 规则。
kube-scheduler 调度器的默认调度逻辑分为 3 个阶段:
- 预选(predicate)阶段,通过一个或一组预选器,挑选出能够符合 Pod 运行环境的节点。
- 优选(priority)阶段,把第一阶段挑选出的节点,逐个代入一组优选函数,而后一项一项进行评分并计算出每个节点的总评分,并排序。如果最优的节点分数相同,则进行下一步;
- 随机(select)阶段,从最优得分相同的 Node 中随机选出一个运行 Pod;
二、高级调度机制¶
自己也可以在外部施加各种条件,来影响调度结果,有两种高级调度机制:
- Node Affinity:节点亲和度。用于定义 Pod 对 Node 的倾向性。
requiredDuringSchedulingIgnoredDuringExecution:硬限制,即必须满足亲和性;nodeSelectorTerms:固定字段matchExpressions:定义匹配规则;
preferredDuringSchedulingIgnoredDuringExecution:软限制,即最好满足亲和性;weight:定义权重;preference:固定字段;matchExpressions:定义匹配规则;
- 后缀中的
IgnoredDuringExecution意思是指:当调度完成后,即使节点标签发生改变而不再符合调度条件时,也不会影响已经调度完成的结果,这类似于 nodeSelector 的工作逻辑。
- Pod Affinity:Pod 亲和度。用于定义 Pod 和 Pod 之间是否运行在一起。
三、Node Affinity 的配置方式¶
- 当同时指定了 NodeSelector 和 Node Affinity,两者之间存在“与”关系,即符合条件的 Node 需要同时满足两个条件;
nodeAffinity中,当nodeSelectorTerms中同时指定多个matchExpressions时,各条目间取“或”关系,即满足其中之一即可;nodeSelectorTerms中,当同一个matchExpressions中的多个key值之间取逻辑“与”关系,即 Node 需要同时满足多个条件;- 定义软限制时,使用
weight可以定义权重,并加入优选值的计算总和;
配置“硬亲和”的示例 1¶
1 | -> # vim required-nodeAffinity-pod.yaml |
配置“硬亲和”的示例 2¶
1 | -> # vim required-nodeAffinity-pod2.yaml |
配置“硬亲和”的示例 3¶
1 | -> # vim required-nodeAffinity-pod2.yaml |
配置“软亲和”的示例 1¶
1 | -> # vim deploy-with-preferred-nodeAffinity.yaml |
四、Pod Affinity 的配置方式¶
定义多个 Pod 间需要运行于同一位置的倾向性,或者不允许运行于同一位置的倾向性。
两个节点是否处于同一位置,取决于 topologyKey 的键值。
Pod 亲和性调度的限制:
- 每次调度 Pod 时,要遍历所有的 Pod 以检测亲和性,因此在集群规模较大时,不建议使用此种调度方式。或不应在较小的颗粒度上定义 Pod 亲和性,而可以使用 Node Affinity 进行调度,并通过为 Node 定义标签达到一样的效果。
- Pod anti-affinity(反亲和)要求集群中的每个节点都针对
topologyKey设置了正确的标签,如果某些或所有节点未设置相应的标签,则可能会导致无法预料的后果。这就要求集群的每个节点都有定义好标签,并在缩容或扩容时规划好每台标签的管理,这在规模较大的集群中不易实现。
Pod “硬-亲和性”示例¶
这里有 Node1、2、3 台节点,先为 1、2 打上相同的标签划分为一个 zone=foo,Node3 为另一个 zone=bar:
1 | -> # kubectl label nodes node1.monster.com zone=foo |
创建一个 Redis Pod,该 Pod 的会自动生值为 app=redis 的标签:
1 | -> # kubectl create deployment redis --image=redis:4-alpine |
创建 Pod 控制器,并定义了此 Deployment 控制器下的 3 个 Pod,在以 zone 标签为范围的拓扑结构区域中,与标签键为 app,值为 db 的 Pod 运行在同一个 zone 中。
1 | -> # vim deploy-with-required-podAffinity.yaml |
创建 Pod:
1 | -> # kubectl apply -f deploy-with-required-podAffinity.yaml |
那么如果 Redis 运行在 Node1 或 2 中,这 3 个 Pod 也会运行于 Node 1 或 2,一定不会被调度至 Node3,因为要保持和 Redis 处于同一个 zone 区域中。
1 | -> # kubectl get pods -o wide |
Pod “硬-反亲和性”示例¶
定义不能与标签键为 app,值为 myapp 的 Pod 运行在同一节点,也就是不能与自己在同一 Node 节点,达到了分散 Pod 的结果。
1 | -> # vim k8s/Kubernetes_Advanced_Practical/chapter12/deploy-with-required-podAntiAffinity.yaml |
Pod “软-亲和性“示例¶
- 如果在标签为
rack的节点范围中,运行着标签键为app,值为db的 Node,那么评分加80; - 如果在标签为
zone的节点范围中,则评分加20; - 如果两者都符合,则加
100。
1 | -> # vim deploy-with-preferred-podAffinity.yaml |
五、Taints and Tolerations 污点与容忍度¶
Node Affinity 是基于 Node 的标签来选择 Node,而 Pod Affinity 是基于 Pod 选 Node,无论哪一种,Node 都是在等待被选择。
而 Taint 则刚好相反,它用于让 Node 排斥 Pod 对象。
可以通过节点规范(NodeSpec)将污染应用于节点,并通过 pod 规范(PodSpec)将容忍度应用于 pod。节点上的污染将指示节点击退所有不容忍污染的 Pod。
Taints 必须结合 Tolerations 才能协同工作,要保证在 Node 上有污点,在 Pod 上有容忍度。否则任何无法容忍污点的 Pod 都无法调度到有污点的 Node。
定义 Taints(污点)的参数¶
定义污点的参数由三部分组成:
key:定义键;value:定义值;effect(效用):如果 Node 上有污点,Pod 也不是一定无法调度,要看这里的效用是如何定义的:NoSchedule:不调度。如果被调度后,污点或容忍度发生变化,无法容忍了,则保持原样不动;PreferNoSchedule:尽量不调度;NoExecute:不执行。如果被调度后,污点或容忍度发生变化,无法容忍了,则驱离 Pod,并可以定义驱离宽限期;
定义 Tolerations(容忍度)的参数¶
容忍度通过以下三个字段的值去匹配污点:key、value、effect,而容忍度的评估方式有两种:
operator:指定操作符:Eqaual:以上三个字段必须都匹配;Exists:key和effect匹配即可;
下图说明了 effect(效用)类型为 NoExecute 时,污点和容忍度的工作流程:

当使用多个污点时:
可以给一个节点添加多个 taint,也可以给一个 pod 添加多个 toleration;
Kubernetes 在处理多个 taint 和 toleration 时就像一个过滤器:从一个节点的所有污点开始遍历,过滤掉那些 Pod 中存在与之相匹配的容忍度的污点。余下未被过滤的污点的 effect 值决定了 Pod 是否会被分配到该节点,特别是以下情况:
- 如果存在一个以上
effect值为NoSchedule的 taint,则 Kubernetes 不会将 pod 分配到该节点。 - 如果不存在
effect值为NoSchedule的 taint,但是存在effect值为PreferNoSchedule的 taint,则 Kubernetes 会 尝试 将 pod 分配到该节点。 - 如果存在一个以上
effect值为NoExecute的 taint,则 Kubernetes 不会将 pod 分配到该节点(如果 pod 还未在节点上运行),或者将 pod 从该节点驱逐(如果 pod 已经在节点上运行):- 不能容忍相应 taint 的 Pod 将会立即遭到驱逐;
- 可以容忍相关的 taint,但没有指定
tolerationSeconde的 Pod 可一直运行于相应的节点; - 可以容忍相关的 taint,且指定了
tolerationSeconde的 Pod 可于相应的节点运行此字段指定的时长。
管理污点和容忍度¶
给节点添加 Taint¶
语法:
1 | kubectl taint nodes NAME_KEY_1=VAL_1:TAINT_EFFECT_1 ... ... |
使用命令 kubectl taint 给节点增加一个污点:
1 | # 给节点 node1 增加一个污点,它的键名是 key1,键值是 value1,效果是 NoSchedule。 |
移除节点的 Taint¶
语法:
1 | # 移除名称为 KEY,且配置了指定的 EFFECT 的 taint |
若要移除上述命令所添加的污点,你可以执行:
1 | kubectl taint nodes node1 key:NoSchedule- |
为 Pod 添加 Toleration¶
operator 的默认值是 Equal。
一个容忍度和一个污点相“匹配”是指它们有一样的键名和效果,并且:
- 如果
operator是Exists(此时容忍度不能指定 value); - 如果
operator是Equal,则它们的value应该相等。
注意:存在两种特殊情况:
- 如果一个容忍度的 key 为空且
operator为Exists, 表示这个容忍度与任意的 key 、value 和 effect 都匹配,即这个容忍度能容忍任意 taint。- 如果
effect为空,则可以与相同键名 key 的所有effect效果相匹配。
示例:在 PodSpec 中定义 Pod 的容忍度。
下面两个容忍度均与上面例子中使用 kubectl taint 命令创建的污点是相匹配的。
因此如果 Pod 只要有下面两个任意一个,就满足对 node1 的容忍度,就能够被分配到 node1 上。
Eqaual 类型,需要全匹配。
1 | spec: |
Exists 类型,key 和 effect 匹配即可。
1 | spec: |