v1.19.5
亲和就是在一起运行的配置。
反亲和就是不在一起的配置。
节点亲和用来配置pod运行在哪些节点,强制或者优先。
pod亲和用来配置pod之间的亲和关系,强制或者优先。
都是通过匹配label来实现的。
关键字描述
affinity
亲和性配置主关键字。
nodeAffinity
设置节点亲和, 节点的反亲和也是这个,只不过条件设置成不匹配罢了。
podAffinity
设置pod间亲和。
podAntiAffinity
设置pod间反亲和。
与节点相比有单独的反亲和关键字,是因为节点反亲和某节点,就是亲和其它节点,没啥影响。但是pod就不行了,如一个pod不想跟nginx运行在一起, app!=nginx
,但是没有其它app
标签了,结果就会匹配失败。
requiredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution
第一个是强制的,如果没有符合条件的就不调度,pod就一直是Pending
状态。
第二个不是强制的,没有符合条件的也会调度,还可以为匹配条件设置不同优先级,实现pod在同一个服务器,同一个机柜,同一个机房运行。
如果一起写,它们是AND的关系,只不过第二个不匹配也没关系,是一个节点偏好。
关键字有点长,主要由三部分组成:
required
与preferred
:
表示调度方式,强制还是优先。
DuringScheduling
表示调度期间,没啥好理解的,跟下面的一对比就明白了。
IgnoredDuringExecution
表示忽略执行期间。 就是在pod正常运行的情况下,一些条件不在满足时,pod不会被驱逐,还在原来节点正常运行。
官方网站说以后会添加requiredDuringSchedulingRequiredDuringExecution
,跟requiredDuringSchedulingIgnoredDuringExecution
差不多,只是会在条件不符合以后,pod会被驱逐。
preferred
调度相关
匹配出来的节点权重分数越大,优先级越高, 越偏向于哪个节点。
因为不是强制性的,会根据多个算法,如安全性、性能相关的,综合判断出调度到哪些节点。只要实例够多,就算是完全不匹配的节点,也会运行实例。甚至同样的配置每次应用,分配的节点,节点运行的实例数量,都是不同的。
节点亲和
节点亲和性相对来说容易配置,因为功能也是比较单一。
注意里面匹配的都是节点的label。
官方的例子:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: k8s.gcr.io/pause:2.0
节点亲和用到的关键字也就这么多。
例子的意思是:
节点必须满足kubernetes.io/e2e-az-name
等于 (e2e-az1
或 e2e-az2
)。 强制条件。
如果节点也能满足another-node-label-key
等于 another-node-label-value
则优先考虑。
requiredDuringSchedulingIgnoredDuringExecution
nodeSelectorTerms
是固定的。 包含一个用来匹配节点的列表。
DESCRIPTION:
Required. A list of node selector terms. The terms are ORed.
A null or empty node selector term matches no objects. The requirements of
them are ANDed. The TopologySelectorTerm type implements a subset of the
NodeSelectorTerm.
FIELDS:
matchExpressions <[]Object>
A list of node selector requirements by node's labels.
matchFields <[]Object>
A list of node selector requirements by node's fields.
matchExpressions
匹配label,这里也是固定的只能用这个匹配label,没有matchLabels
。
还有一个用来匹配字段的matchFields
,用的少。
preferredDuringSchedulingIgnoredDuringExecution
包含一个列表,里面是不同权重的节点匹配规则。
FIELDS:
preference <Object> -required-
A node selector term, associated with the corresponding weight.
weight <integer> -required-
Weight associated with matching the corresponding nodeSelectorTerm, in the
range 1-100.
preference
包含一个node selector的配置,与nodeSelectorTerms
不同的是,没有包含一个配置列表,因为需要跟weight
权重相关联。 跟权重一起相当于是一组配置。
weight
权重,数字越大权重越高。 取值范围 1-100.
调度规则
摘的官网的,就上面网页里面的。
如果你同时指定了 nodeSelector 和 nodeAffinity,两者必须都要满足,才能将 pod 调度到候选节点上。
如果你指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms,则如果其中一个 nodeSelectorTerms 满足的话,pod将可以调度到节点上。
也就是OR的关系, 例子3
如果你指定了多个与 nodeSelectorTerms 关联的 matchExpressions,则只有当所有 matchExpressions 满足的话,pod 才会可以调度到节点上。
也就是AND的关系, 例子4
如果你修改或删除了 pod 所调度到的节点的标签,pod 不会被删除。换句话说,亲和选择只在 pod 调度期间有效。
preferredDuringSchedulingIgnoredDuringExecution 中的 weight 字段值的范围是 1-100。对于每个符合所有调度要求(资源请求,RequiredDuringScheduling 亲和表达式等)的节点,调度器将遍历该字段的元素来计算总和,并且如果节点匹配对应的MatchExpressions,则添加“权重”到总和。然后将这个评分与该节点的其他优先级函数的评分进行组合。总分最高的节点是最优选的
例子2
requiredDuringSchedulingIgnoredDuringExecution
与 preferredDuringSchedulingIgnoredDuringExecution
是 AND 的关系,虽然preferred
不是强制的,但逻辑关系确实是AND, 或者是相加的关系。
例子1
只匹配node1
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values: ['k8snode1']
node2与node3也有实例。
[root@k8smaster1 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7f69fbf687-2ktrh 1/1 Running 0 23s 10.1.0.10 k8snode1 <none> <none>
nginx-7f69fbf687-5d5sj 1/1 Running 0 25s 10.1.0.9 k8snode1 <none> <none>
nginx-7f69fbf687-6cg5g 1/1 Running 0 25s 10.1.0.238 k8snode2 <none> <none>
nginx-7f69fbf687-6t6sp 1/1 Running 0 23s 10.1.0.11 k8snode1 <none> <none>
nginx-7f69fbf687-8jx49 1/1 Running 0 25s 10.1.1.75 k8snode3 <none> <none>
nginx-7f69fbf687-96m4z 1/1 Running 0 25s 10.1.0.8 k8snode1 <none> <none>
nginx-7f69fbf687-hxd7z 1/1 Running 0 23s 10.1.0.12 k8snode1 <none> <none>
nginx-7f69fbf687-nr8rf 1/1 Running 0 22s 10.1.0.13 k8snode1 <none> <none>
nginx-7f69fbf687-rdxnb 1/1 Running 0 25s 10.1.0.7 k8snode1 <none> <none>
nginx-7f69fbf687-rtzkd 1/1 Running 0 23s 10.1.1.76 k8snode3 <none> <none>
例子2
第一个匹配k8snode1; 第二三个都是匹配k8snode2, 总的优先级权重比第一个高。
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values: ['k8snode1']
- weight: 30
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values: ['k8snode2']
- weight: 30
preference:
matchExpressions:
- key: rule
operator: In
values: ['dmz']
node2比较多,完全不匹配的node3也有实例运行:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-f68fb4b64-2gbbd 1/1 Running 0 3m27s 10.1.0.3 k8snode1 <none> <none>
nginx-f68fb4b64-475fm 1/1 Running 0 3m26s 10.1.0.4 k8snode1 <none> <none>
nginx-f68fb4b64-55zpw 1/1 Running 0 3m27s 10.1.0.231 k8snode2 <none> <none>
nginx-f68fb4b64-8zlrx 1/1 Running 0 3m26s 10.1.0.232 k8snode2 <none> <none>
nginx-f68fb4b64-bk956 1/1 Running 0 3m28s 10.1.0.229 k8snode2 <none> <none>
nginx-f68fb4b64-btj9n 1/1 Running 0 3m29s 10.1.1.71 k8snode3 <none> <none>
nginx-f68fb4b64-dcrt6 1/1 Running 0 3m29s 10.1.0.228 k8snode2 <none> <none>
nginx-f68fb4b64-jj7ff 1/1 Running 0 3m27s 10.1.0.230 k8snode2 <none> <none>
nginx-f68fb4b64-k69np 1/1 Running 0 3m29s 10.1.0.126 k8snode1 <none> <none>
nginx-f68fb4b64-vgtw7 1/1 Running 0 3m28s 10.1.0.2 k8snode1 <none> <none>
例子3
nodeSelectorTerms
多个元素是OR的关系
不是说有多个nodeSelectorTerms
关键字, 而是这个关键字里有多个元素。毕竟nodeSelectorTerms
可是字典的key,写多了也没用,下面的会覆盖上面的。
多个matchExpressions
是OR的关系。
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values: ['k8snode1']
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values: ['k8snode2']
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values: ['k8snode3']
3个节点都有实例。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-fd4679bbf-2nx9z 1/1 Running 0 14s 10.1.0.249 k8snode2 <none> <none>
nginx-fd4679bbf-44zs4 1/1 Running 0 11s 10.1.0.26 k8snode1 <none> <none>
nginx-fd4679bbf-57vz9 1/1 Running 0 14s 10.1.0.250 k8snode2 <none> <none>
nginx-fd4679bbf-98ssf 1/1 Running 0 14s 10.1.0.251 k8snode2 <none> <none>
nginx-fd4679bbf-9cdtk 1/1 Running 0 12s 10.1.0.252 k8snode2 <none> <none>
nginx-fd4679bbf-9k5d4 1/1 Running 0 11s 10.1.1.97 k8snode3 <none> <none>
nginx-fd4679bbf-kqf9h 1/1 Running 0 12s 10.1.0.253 k8snode2 <none> <none>
nginx-fd4679bbf-m9rnk 1/1 Running 0 14s 10.1.0.25 k8snode1 <none> <none>
nginx-fd4679bbf-sp5lh 1/1 Running 0 14s 10.1.1.96 k8snode3 <none> <none>
nginx-fd4679bbf-xtf2k 1/1 Running 0 10s 10.1.0.27 k8snode1 <none> <none>
例子4
matchExpressions
关键字的元素有多个
是AND的关系, 必须同时满足才行。
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values: ['k8snode1']
- key: kubernetes.io/hostname
operator: NotIn
values: ['k8snode2']
- key: kubernetes.io/hostname
operator: In
values: ['k8snode3']
因为第三个元素不满足,所以pod无法调度。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7dd9d85d6-246wh 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-hbnjp 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-n2s2b 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-qqb2n 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-s8mfw 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-sjplc 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-swf2q 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-xn6h6 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-xxn4j 0/1 Pending 0 6s <none> <none> <none> <none>
nginx-7dd9d85d6-zd48w 0/1 Pending 0 6s <none> <none> <none> <none>
pod间亲和与反亲和
注意匹配的是pod的label。
podAffinity
: 亲和性配置
podAntiAffinity
: 反亲和性配置
亲和与反亲和除了podAffinity
与podAntiAffinity
关键字不一样,其它的关键字都一样。
Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度。我们不建议在超过数百个节点的集群中使用它们。
Pod 反亲和需要对节点进行一致的标记,即集群中的每个节点必须具有适当的标签能够匹配 topologyKey。如果某些或所有节点缺少指定的 topologyKey 标签,可能会导致意外行为。
pod亲和与反亲和的过程:
- 匹配目标pod label。确定目标pod所在节点。
- 确定目标节点指定的label的值。这个label就是
topologyKey
指定的。 - 确定拥有相同label值得节点。
- 根据亲和还是反亲和,调度到确定的节点还是其它节点。
官方例子:
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: topology.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: topology.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: k8s.gcr.io/pause:2.0
上面的意思是:
亲和性设置: 与security
等于S1
的POD在同一区域(topology.kubernetes.io/zone)的节点,强制性的。
反亲和性设置:尽可能避开security
等于S2
的POD区域(topology.kubernetes.io/zone)的节点。
labelSelector
: 表示开始匹配pod label,包含的是匹配的方式(matchExpressions
, matchLabels
)
topologyKey
: 一致性参照。
例子中不包含的关键字:
matchLabels: 基于等式的Label匹配,包含一个label匹配的字典, 一般资源里用的都是这个。
matchExpressions`是基于集合的。
namespaces
: 与labelSelector同级。 指定namespace, 默认跟当前pod一样。pod的匹配只匹配对应namespace的。
topologyKey
限制
原则上,topologyKey 可以是任何合法的标签键。然而,出于性能和安全原因,topologyKey 受到一些限制:
对于亲和与 requiredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,topologyKey 不允许为空。
对于 requiredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,准入控制器 LimitPodHardAntiAffinityTopology 被引入来限制 topologyKey 不为 kubernetes.io/hostname。如果你想使它可用于自定义拓扑结构,你必须修改准入控制器或者禁用它。
对于 preferredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,空的 topologyKey 被解释为“所有拓扑结构”(这里的“所有拓扑结构”限制为 kubernetes.io/hostname,topology.kubernetes.io/zone 和 topology.kubernetes.io/region 的组合)。
除上述情况外,topologyKey 可以是任何合法的标签键。
调度规则
所有与 requiredDuringSchedulingIgnoredDuringExecution 亲和与反亲和关联的 matchExpressions 必须满足,才能将 pod 调度到节点上。
总之就是没有OR关系的, 全部都是AND关系。
preferredDuringSchedulingIgnoredDuringExecution
这个里面其实也都是AND关系,只不过不是强制的,但也都是会计算。
总结就是:pod亲和与反亲和里面都是AND关系。必须满足所有条件才行。
例子1:
运行在同一节点, 当前部署的deployment。
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ['nginx']
topologyKey: kubernetes.io/hostname
例子2:
分散部署pod, 不能在同一节点.
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ['nginx']
topologyKey: kubernetes.io/hostname
例子3:
必须在同一节点,必须在有ssd盘的节点。
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ['nginx']
topologyKey: kubernetes.io/hostname
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk
operator: In
values: ['ssd']
例子4:
多个labelSelector
,需要都满足,AND关系。
下面的例子无法调度.
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ['nginx']
topologyKey: kubernetes.io/hostname
- labelSelector:
matchExpressions:
- key: app
operator: NotIn
values: ['nginx']
topologyKey: kubernetes.io/hostname
例子5:
matchExpressions
多个元素也是都要满足
AND关系。下面的例子无法调度.
template:
metadata:
labels:
app: nginx
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ['nginx']
- key: app
operator: NotIn
values: ['nginx']
topologyKey: kubernetes.io/hostname
其它
affinity
下面的podAffinity
, podAntiAffinity
, nodeAffinity
之间也是AND关系。
第二个pod亲和第一个pod, 从而跟第一个pod运行在了一个节点。 而后第一个pod删除重建了之后一般情况下还会回到那个节点。 以为有第二个pod的关系在,调度时候的分数也大。 除非是因为资源不够用了,或者是其它方面的影响。