podAffinity介绍
出于高效通信的需求,我们要把几个Pod对象运行在比较近的位置,例如APP Pod
与DB Pod
,我们的APP Pod
需要连接DB Pod
,这个时候就需要把这两个Pod运行在较近的位置以便于网络通信,一般可以按照区域、机房、地区等来划分。像这种类型就属于Pod的亲和性调度。但是有时候出于安全或者分布式考虑,也有可能将Pod运行在不同区域、不同机房,这个时候Pod的关系就是为反亲和性。
podAffinity也被分为硬亲和性和软亲和性,其原理与Node中的硬亲和性及软亲和性一致。
硬亲和性(required)
:硬亲和性实现的是强制性规则,它是Pod调度时必须要满足的规则,而在不存在满足规则的Node时,Pod对象会被置为Pending状态。
软亲和性(preferred)
:软亲和性规则实现的是一种柔性调度限制,它倾向于将Pod对象运行于某类特定节点之上,而调度器也将尽量满足此需求,但在无法满足需求时它将退而求其次地选择一个不匹配规则的节点之上。
定义Pod亲和性规则的关键点有两个:
- 1.为节点配置合乎需求的标签。
- 2.为Pod对象定义合理的标签选择器labelSelector,从而能够基于标签选择器选择出符合需求的标签。
帮助文档:kubectl explain pods.spec.affinity.podAffinity
Pod反亲和硬亲和性
Pod硬亲和性调度使用requiredDuringSchedulingIgnoredDuringExecution
属性进行定义,Pod硬亲和性使用topologyKey
参数来指定要运行在具备什么样标签key的Node上,然后再通过labelSelector
选择你想关联Pod的标签,可能有点绕,下面看示例应该就明白了。
帮助文档:kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution
Pod硬亲和性参数解析:
labelSelector:标签选择器🏷️。
topologyKey:指定要将当前创建Pod运行在具备什么样的Node标签上,通常指定Node标签的Key。
namespaces:指定labelSelector应用于哪个名称空间,null或空列表表示“此pod的名称空间”。
matchExpressions:按照Pod label列出节点选择器列表。(与matchLabels是两种方式,不过结果是一至)。
matchLabels:按照节点字段列出节点选择器列表。(与matchExpressions是两种方式,不过结果是一至)。
key:指定要选择节点label的key。
values:指定要选择节点label的value,值必须为数组 ["value"]
,如果操作符为In
或者 Notin
,value则不能为空,如果操作符为Exists
或者DoesNotExist
,value则必须为空[]
,如果操作符为Gt
或Lt
,则value必须有单个元素,该元素将被解释为整数。
operator:操作符,指定key与value的关系。
In:key与value同时存在,一个key多个value的情况下,value之间就成了逻辑或
效果。
NotIn:label 的值不在某个列表中。
Exists:只判断是否存在key,不用关心value值是什么。
DoesNotExist:某个 label 不存在。
Gt:label 的值大于某个值。
Lt:label 的值小于某个值
1.为Node打上不同地区的标签
node01标签为beijing
node02标签为shanghai
node03标签为shenzhen
1 2 3 |
kubectl label node k8s-node01 zone=beijing kubectl label node k8s-node02 zone=shanghai kubectl label node k8s-node03 zone=shenzhen |
2.创建资源配置清单
下面清单中,Pod首先会选择标签key为zone的Node,我们上面做了三个Node标签key都为zone,匹配之后,开始在标签key为zone的Node上寻找标签key为app,values为proxy或者web的Pod,然后与其运行在那台Node之上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
cat podaffinity-pod.yaml apiVersion: v1 kind: Pod metadata: name: podaffinity-required-pod spec: containers: - name: nginx-containers image: nginx:latest affinity: podAffinity: #硬亲和性 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: #选择标签key为app,values为proxy或者web的Pod,然后与其运行在同一个Node上 - { key: app, operator: In, values: ["proxy","web"] } #选择key为zone的Node topologyKey: zone |
3.查看调度结果
如下可以看到,三台Node上没有标签key为app,values为proxy或者web的Pod,我们采用的是硬亲和性,所以该Pod一直为Pending状态。
1 2 3 |
kubectl apply -f podaffinity-pod.yaml kubectl get pods -o wide | grep podaffinity podaffinity-required-pod 0/1 Pending 0 3m43s <none> <none> <none> <none> |
4.创建标签key为app,值为proxy或者web的Pod
1 2 3 4 5 6 7 8 9 10 11 12 |
cat app_proxy.yaml apiVersion: v1 kind: Pod metadata: name: app-proxy-pod labels: app: proxy spec: containers: - name: app-proxy image: busybox:latest command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ] |
5.查看调度结果
1 2 3 4 5 6 7 |
kubectl apply -f app_proxy.yaml #具备标签key为app,values的Pod被调度到了node03上 kubectl get pods -owide | grep app-proxy app-proxy-pod 1/1 Running 0 42s 10.244.5.102 k8s-node03 <none> <none> #如下podAffinity硬亲和性调度也被调度到此Node kubectl get pods -owide | grep podaff podaffinity-required-pod 1/1 Running 0 2m30s 10.244.5.103 k8s-node03 <none> <none> |
Pod软亲和性
Pod软亲和性使用preferredDuringSchedulingIgnoredDuringExecution
属性进行定义,Pod软亲和性使用podAffinityTerm
属性来挑选Pod标签,当调度的Pod对象不再是”必须”,而是“应该”放置于某些特性节点之上,当条件不满足时,它也能够接受编排于其它不符合条件的节点之上,另外,它还为每种倾向性提供了weight属性以便用户定义其优先级,取值范围是1-100,数字越大优先级越高。
帮助文档:kubectl explain pods.spec.affinity.podAffinity.preferredDuringSchedulingIgnoredDuringExecution
Pod软亲和性参数解析:
podAffinityTerm:Pod亲和性选择器。
weight:在1-100范围内,与匹配相应的节点选项相关联的权重。
labelSelector:标签选择器。
matchExpressions:按照Pod label列出节点选择器列表。(与matchLabels是两种方式,不过结果是一至)。
matchLabels:按照节点字段列出节点选择器列表。(与matchExpressions是两种方式,不过结果是一至)。
key:指定要选择节点label的key。
values:指定要选择节点label的value,值必须为数组 ["value"]
,如果操作符为In
或者 Notin
,value则不能为空,如果操作符为Exists
或者DoesNotExist
,value则必须为空[]
,如果操作符为Gt
或Lt
,则value必须有单个元素,该元素将被解释为整数。
operator:操作符,指定key与value的关系。
In:key与value同时存在,一个key多个value的情况下,value之间就成了逻辑或效果。
NotIn:label 的值不在某个列表中。
Exists:只判断是否存在key,不用关心value值是什么。
DoesNotExist:某个 label 不存在。
Gt:label 的值大于某个值。
Lt:label 的值小于某个值
1.创建资源配置清单
下面创建一个Pod软亲和性资源配置清单,定义了两组亲和性判断机制,一个是选择cache Pod所在节点的zone标签,并赋予权重为80,另一个是选择db Pod所在的zone标签,权重为20,调度器首先会将Pod调度到具有zone标签key的Node上,然后将多数Pod调度到具备标签为app=cache的Pod同节点,其次调度到具备标签app=db的Pod同节点。如果Node上的Pod都具备app=cache和app=db,那么根据Pod软亲和性策略,调度器将退而求其次的将Pod调度到其它Node,如果甚至连Node都具备标签zone键,那么根据软亲和策略,调度器还是会退而求其次的将Pod调度到不存在zone键的Node上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
cat podaffinity-deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: podaffinity-perferred-pod spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: name: myapp labels: app: myapp spec: affinity: podAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 80 podAffinityTerm: labelSelector: matchExpressions: - { key: app, operator: In, values: ["cache"] } topologyKey: zone - weight: 20 podAffinityTerm: labelSelector: matchExpressions: - { key: app, operator: In, values: ["db"] } topologyKey: zone containers: - name: myapp image: busybox:latest command: ["/bin/sh", "-c", "tail -f /etc/passwd" ] |
2.查看调度结果
1 2 3 4 5 6 7 8 9 10 11 |
#Pod调度结果为node01两个,node03一个 kubectl get pods -o wide | grep podaffinity-perferred-pod podaffinity-perferred-pod-7cddc8c964-5tfr2 1/1 Running 0 12m 10.244.5.106 k8s-node03 <none> <none> podaffinity-perferred-pod-7cddc8c964-kqsmk 1/1 Running 0 12m 10.244.3.109 k8s-node01 <none> <none> podaffinity-perferred-pod-7cddc8c964-wpqqw 1/1 Running 0 12m 10.244.3.110 k8s-node01 <none> <none> #以下三个Node都具备标签键为zone,但是这三个Node上没有Pod标签为app=cache及app=db,所以上面的调度策略在选择Pod标签的时候进行退步才得以将Pod调度到Node01和Node03 k8sops@k8s-master01:~/manifests/pod$ kubectl get nodes -l zone -L zone NAME STATUS ROLES AGE VERSION ZONE k8s-node01 Ready <none> 28d v1.18.2 beijing k8s-node02 Ready <none> 28d v1.18.2 shanghai k8s-node03 Ready <none> 29d v1.18.2 shenzhen |