本文参考摘抄于kubernetes官方文档,参考地址:https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity
nodeSelector 提供了一种最简单的方法来将 Pod 约束到具有特定标签的节点上。 亲和性和反亲和性扩展了你可以定义的约束类型。使用亲和性与反亲和性的一些好处有
1.亲和性、反亲和性语言的表达能力更强。nodeSelector 只能选择拥有所有指定标签的节点。 亲和性、反亲和性为你提供对选择逻辑的更强控制能力。
2.你可以标明某规则是“软需求”或者“偏好”,这样调度器在无法找到匹配节点时仍然调度该 Pod。
3.你可以使用节点上(或其他拓扑域中)运行的其他 Pod 的标签来实施调度约束, 而不是只能使用节点本身的标签。这个能力让你能够定义规则允许哪些 Pod 可以被放置在一起。
亲和性功能由两种类型的亲和性组成:
(1)节点亲和性功能类似于 nodeSelector 字段,但它的表达能力更强,并且允许你指定软规则。
(2)Pod 间亲和性/反亲和性允许你根据其他 Pod 的标签来约束 Pod
节点亲和性
节点亲和性概念上类似于 nodeSelector, 它使你可以根据节点上的标签来约束 Pod 可以调度到哪些节点上。 节点亲和性有两种:
requiredDuringSchedulingIgnoredDuringExecution: 调度器只有在规则被满足的时候才能执行调度。此功能类似于 nodeSelector, 但其语法表达能力更强。
preferredDuringSchedulingIgnoredDuringExecution: 调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点,调度器仍然会调度该 Pod。
可以使用 Pod 规约中的 .spec.affinity.nodeAffinity 字段来设置节点亲和性。 例如,考虑下面的 Pod 规约
#分别在k8s-master3,和k8s-node1 两个节点上分别加上app=host1标签
[root@k8s-master1 node]# kubectl label node k8s-node1 app=host1 --overwrite
node/k8s-node1 labeled
[root@k8s-master1 node]# kubectl label node k8s-master3 app=host1 --overwrite
node/k8s-master3 labeled
#单独在k8s-node上增加一个apps=host1的标签
[root@k8s-master1 node]# kubectl label node k8s-node1 apps=host1 --overwrite
node/k8s-node1 not labeled
创建node亲和性的pod的
[root@k8s-master1 node]# cat pod-with-node-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
namespace: app
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #必须条件:app=host1标签的节点
nodeSelectorTerms:
- matchExpressions:
- key: app
operator: In
values:
- host1
preferredDuringSchedulingIgnoredDuringExecution: #非必要条件存在的优先apps=host1
- weight: 50 #权重
preference:
matchExpressions:
- key: apps
operator: In
values:
- host1
containers:
- name: with-node-affinity
image: nginx
由于咱们在k8s-node1节点上配置了app=host1和apps=host1两个标签,所以容器优先分配到k8s-node1节点
[root@k8s-master1 node]# kubectl get pods -n app -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 64m 10.10.135.202 k8s-master3 <none> <none>
with-node-affinity 1/1 Running 0 49s 10.10.36.115 k8s-node1 <none> <none>
节点亲和性权重
你可以为 preferredDuringSchedulingIgnoredDuringExecution 亲和性类型的每个实例设置 weight 字段,其取值范围是 1 到 100。 当调度器找到能够满足 Pod 的其他调度请求的节点时,调度器会遍历节点满足的所有的偏好性规则, 并将对应表达式的 weight 值加和。
最终的加和值会添加到该节点的其他优先级函数的评分之上。 在调度器为 Pod 作出调度决定时,总分最高的节点的优先级也最高。
[root@k8s-master1 node]# kubectl get nodes --show-labels |grep -E 'app|apps'
k8s-master3 Ready <none> 35d v1.22.1 app=host1,apps=host2,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,ingress=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master3,kubernetes.io/os=linux,topology.kubernetes.io/zone=antarctica-east1
k8s-node1 Ready <none> 53d v1.22.1 another-node-label-key=another-node-label-value,app.kubernetes.io/instance=tomcat,app.kubernetes.io/managed-by=Helm,app.kubernetes.io/name=tomcat,app.kubernetes.io/version=10.1.15,app=host1,apps=host1,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,helm.sh/chart=tomcat-10.11.0,ingress=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux,pod-template-hash=7b7447795c,topology.kubernetes.io/zone=antarctica-east1
|节点| 标签 |
|--|--|
| k8s-node1| app=host1,apps=host1 |
| k8s-master3| app=host1,apps=host2 |
[root@k8s-master1 node]# cat pod-with-node-anti-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: with-affinity-anti-affinity
namespace: app
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: app
operator: In
values:
- host1
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: apps
operator: In
values:
- host1
- weight: 50
preference:
matchExpressions:
- key: apps
operator: In
values:
- host2
containers:
- name: with-node-affinity
image: nginx
因为apps=host2的权重比较高,所以容器落在了k8s-master3的宿主机上
[root@k8s-master1 node]# kubectl get pods -n app -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 88m 10.10.135.202 k8s-master3 <none> <none>
with-affinity-anti-affinity 1/1 Running 0 2m46s 10.10.135.205 k8s-master3 <none> <none>
如果存在两个候选节点,都满足 preferredDuringSchedulingIgnoredDuringExecution 规则, 其中一个节点具有标签 label-1:key-1,另一个节点具有标签 label-2:key-2, 调度器会考察各个节点的 weight 取值,并将该权重值添加到节点的其他得分值之上。
Pod 间亲和性与反亲和性
Pod 间亲和性与反亲和性的类型
与节点亲和性类似,Pod 的亲和性与反亲和性也有两种类型:
1.requiredDuringSchedulingIgnoredDuringExecution
2.preferredDuringSchedulingIgnoredDuringExecution
例如,你可以使用 requiredDuringSchedulingIgnoredDuringExecution 亲和性来告诉调度器, 将两个服务的 Pod 放到同一个云提供商可用区内,因为它们彼此之间通信非常频繁。 类似地,你可以使用 preferredDuringSchedulingIgnoredDuringExecution 反亲和性来将同一服务的多个 Pod 分布到多个云提供商可用区中。
要使用 Pod 间亲和性,可以使用 Pod 规约中的 .affinity.podAffinity 字段。 对于 Pod 间反亲和性,可以使用 Pod 规约中的.affinity.podAntiAffinity 字段。
Pod 亲和性示例
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: registry.k8s.io/pause:2.0
本示例定义了一条 Pod 亲和性规则和一条 Pod 反亲和性规则。Pod 亲和性规则配置为 requiredDuringSchedulingIgnoredDuringExecution,而 Pod 反亲和性配置为 preferredDuringSchedulingIgnoredDuringExecution。
亲和性规则规定,只有节点属于特定的 区域 且该区域中的其他 Pod 已打上 security=S1 标签时,调度器才可以将示例 Pod 调度到此节点上。 例如,如果我们有一个具有指定区域(称之为 “Zone V”)的集群,此区域由带有 topology.kubernetes.io/zone=V 标签的节点组成,那么只要 Zone V 内已经至少有一个 Pod 打了 security=S1 标签, 调度器就可以将此 Pod 调度到 Zone V 内的任何节点。相反,如果 Zone V 中没有带有 security=S1 标签的 Pod, 则调度器不会将示例 Pod 调度给该区域中的任何节点。
反亲和性规则规定,如果节点属于特定的 区域 且该区域中的其他 Pod 已打上 security=S2 标签,则调度器应尝试避免将 Pod 调度到此节点上。 例如,如果我们有一个具有指定区域(我们称之为 “Zone R”)的集群,此区域由带有 topology.kubernetes.io/zone=R 标签的节点组成,只要 Zone R 内已经至少有一个 Pod 打了 security=S2 标签, 调度器应避免将 Pod 分配给 Zone R 内的任何节点。相反,如果 Zone R 中没有带有 security=S2 标签的 Pod, 则反亲和性规则不会影响将 Pod 调度到 Zone R。