Pod自身的亲和性调度分为两种表示形式,第一种podinity(亲和性),第二张podAffinity(反亲和性)
pod亲和性
pod与pod更倾向运行在一起。一般出于高效通讯的需求把pod对象组织在相近的位置,同一个节点,同一个机架,同一个机房,甚至于同一个区域或者地区,便于pod通讯。但是有些时候在部署两套系统的时候,出于一些安全或者其他的考虑,不能够部署在一起的时候,就需要反亲和性。
pod的亲和性定义比较独特,一般而言,通过节点亲和性定义pod之间的亲和性。用户必须为pod指定可运行的节点标签,那此前的节点亲和性也可以定义pod亲和性。如:pod被定义在亲和性高的节点之上,随之pod之间的亲和性也就高了。
但是定义节点亲和性从而完成pod亲和性的调度并不是最优的方式。定义节点亲和性的条件是必须确保节点和pod双方需要完全匹配到,并且需要有针对性的,精心的布局节点,比如如何去打标签,打什么标签等。这种方式太过于复杂,而较理想的方式就可以直接把第一个pod随机选择一个位置或者现存的多个pod,而后第二个pod根据第一个pod所在的位置或者现存pod位置,作为评判后续pod能否到第一个pod或者现存很多pod上亲和度的调度,有可能是在同一个节点,也有可能是在邻近的节点,而不是根据节点布局进行调度。
但是,这样一来又怎么去判定那些位置是相同的,那些是不相同位置的?
假设有ABCD四个机柜上有4台节点。随后,但第一个Pod运行在第一个节点之后,如何确保第二个,第三个节点是否能运行与第一个pod亲和的POD。此刻运行NMT,如果Nginx运行在A节点上,M又应该如何运行?我们知道pod亲和性并不是一定要运行在一个节点之上,也可能是具有亲和性的节点,Tomcat运行在B,Mysql运行在C,只要满足这三个节点在同一个机柜内就认为这是满足亲和性条件的不就可以了?毕竟有着高效的通讯前提。如下:
所以,在定义pod亲和性时候,必须有一个判断前提:
- pod和pod在同一个位置,或者不在同一个位置衡量的标准是什么。
怎么是同一个位置,怎么又不在同一个位置?如果以节点名称来判断位置,相同的节点名称就作为一个位置,节点名称不相同的就不作为 一个位置。那么就有4个位置,每个节点做为一个独特的位置存在。如果以这种方式为标准,第一个pod运行在第一个A机柜上,那么第二个Pod就必须在节点1上了。只有在同一个位置才能满足亲和性。
那如果换种方式,在同一个位置的标准是:只要是在同一个标签下的节点来判断亲和性范围。
比如,ABC的标签上zone=linuxea.rackShangHai.com,以NMT为例,nginx调度到A节点上,在同一个标签内,Tomcat可以被调度在标签内的A,B,C任意一个节点。唯独不会调度到D节点
- 我们必要有一种方式去判定,那些机房内的机柜,机柜中的服务器节点,节点与节点之间,或者机柜与机柜之间,甚至机房与机房之间是在同一个位置。从而在调度时候才能够有根据的标准来度量是否满足亲和性。
Pod软硬亲和
pod亲和性也分硬亲和性,在pods.spec.affinity.podAffinity
下也也有preferredDuringSchedulingIgnoredDuringExecution
和requiredDuringSchedulingIgnoredDuringExecution
。这和nodeAffinity相似。
硬亲和表示必须要在同一个位置,软亲和表示尽量在同一个位置。
对podAffinity来讲:
required硬性亲和参数中:labelSelector,namespaces,topologyKey。
- topologyKey
指位置键(如上所述),必须是一个key,必须判定亲和或者不亲和。
- labelSelector
在判定pod亲和时,labelSelector用来选定一组资源,选择能够作为亲和对象的pod
- namespaces
当标签选择器选择一组资源,指明标签选择器匹配的到的pod所在名称空间。当前pod必然属于某个名称空间,当没有手动指定namespaces ,就指labelSelector所匹配的pod只能是当前正在创建pod所属同一个名称空间中的那些pod。一般不需要跨名称空间引用pod,创建pod时候所在的名称空间当中其他目标pod可作为自己目标亲和的pod。
但需要手动指定的时候
硬亲和测试
此刻,需要运行两个pod,分别是linuxea-pods-1和linuxea-pods-2,我们知道,在硬亲和中,第二个pod必须满足亲和性,如果第一个pod运行在某个节点,且第二个pod通常也会运行在某个节点,这取决于第一个pod运行在那个节点,也取决于位置标准的标签定义方式。
1,yaml定义
第一个pod标签为
labels:
app: linuxea.com
在第二个pod中,我们期望第一个pod在的位置就是第二个pod在的位置,由此,我们需要一个特定的标签来进行区分pod运行的范围,我们使用节点名称来作为位置判定的同一标准,节点名称是唯一的
[root@linuxea networkpolicy]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
linuxea.master-1.com Ready master 42d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=linuxea.master-1.com,node-role.kubernetes.io/master=
linuxea.node-1.com Ready <none> 42d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=linuxea.node-1.com,zone=linuxea.zone.cn
linuxea.node-2.com Ready <none> 42d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=linuxea.node-2.com
linuxea.node-3.com Ready <none> 42d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=linuxea.node-3.com,zone=linuxea.zone
那么这样一来,因为硬限制,假如第一个pod调度到节点1,第二个pod就必须会运行在节点2,如果第一个在节点2,第二个pod就必须会运行在节点2
- affinity如下:
标签选择器中,选择的是pod的标签而不是node节点的标签。在这里意思是:当前的这个pod要和下面的这个标签所属的pod在一起
labels:
app: linuxea.com
如果要检查其他的标签,可以继续写
topologyKey
指的是kubernetes.io/hostname
.也就是说只要hostname是一样的,就认为是同一个位置,如果不一样就不是同一个位置。
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["linuxea.com"]}
topologyKey: kubernetes.io/hostname
如果不出意外,这两个pod都会运行在同一个位置上,也就是同一个hostname相同的节点之上。
2,yaml文件
[root@linuxea schedule]# cat pods-required-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: linuxea-pods-1
namespace: default
labels:
app: linuxea.com
spec:
containers:
- name: pods-1026
image: marksugar/nginx:1.14.a
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: linuxea-pods-2
namespace: default
labels:
app: linuxea.net
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sh","-c","sleep 3600"]
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["linuxea.com"]}
topologyKey: kubernetes.io/hostname
apply
[root@linuxea schedule]# kubectl apply -f pods-required-affinity.yaml
pod/linuxea-pods-1 created
pod/linuxea-pods-2 createdku
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
linuxea-pods-1 1/1 Running 0 27s 172.16.4.11 linuxea.node-2.com <none>
linuxea-pods-2 1/1 Running 0 27s 172.16.4.10 linuxea.node-2.com <none>
此刻使用硬亲和,linuxea-pods-2
和linuxea-pods-1
运行在linuxea.node-2.com上
- 那么我们应该知道,pod调度时候,如果有两个pod,默认是用了均衡法则,在优选策略中会尽可能那的进行均衡,cpu均衡,以及最少资源占用利用率节点会,在优选中,最少资源占用的节点一定会被调度到两个不同的节点之上去。但是现在使用podAffinity硬性亲和(required),就必然会组在一个节点之上。如果使用preferred就当另说。
podAntiAffinity
反亲和和亲和的唯一区别在于使用了topologyKey后,topologyKey的值一定不能是相同的。
仍然使用上面的yaml文件,将podAffinity改成podAntiAffinity。topologyKey此前我们知道,使用的是hostname标签名称作为区分位置标准,这样一来,两个pod必然会运行在不同的hostname节点上
测试1
[root@linuxea schedule]# cat pods-required-anti-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: linuxea-pods-1
namespace: default
labels:
app: linuxea.com
spec:
containers:
- name: pods-1026
image: marksugar/nginx:1.14.a
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: linuxea-pods-2
namespace: default
labels:
app: linuxea.net
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sh","-c","sleep 3600"]
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["linuxea.com"]}
topologyKey: kubernetes.io/hostname
[root@linuxea schedule]# kubectl apply -f pods-required-anti-affinity.yaml
pod/linuxea-pods-1 created
pod/linuxea-pods-2 created
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
linuxea-pods-1 1/1 Running 0 3s 172.16.4.12 linuxea.node-2.com <none>
linuxea-pods-2 1/1 Running 0 3s 172.16.5.13 linuxea.node-3.com <none
测试2
测试1中,topologyKey
是kubernetes.io/hostname
,而kubernetes.io/hostname
在每个节点之上都是唯一的,在反亲和中,不能运行在两个节点之上。
但是,我们知道,反亲和中,如果节点上的标签一样,而topologyKey
正好也使用这个标签,也就意味着在同一个位置拓扑中,那么linuxea-pods-2
反亲和条件不满足,linuxea-pods-2
必然会本pending
将linuxea.node-1.com
和linuxea.node-2.com
,linuxea.node-3.com
打上标签www=linuxea.com
。值得注意的是,如果有一台节点没有打标签就会在标签范围外运行第二个pod。反亲和条件仍然满足,就不会pending.
- 我们使用
kubectl label nodes linuxea.node-1.com LABLE_NAME-
删除不用的lables
[root@linuxea schedule]# kubectl label nodes linuxea.node-1.com wwwlabel=linuxealabel
node/linuxea.node-1.com labeled
[root@linuxea schedule]# kubectl label nodes linuxea.node-2.com wwwlabel=linuxealabel
node/linuxea.node-2.com labeled
[root@linuxea schedule]# kubectl label nodes linuxea.node-3.com wwwlabel=linuxealabel
node/linuxea.node-2.com labeled
修改topologyKey
等于wwwlabel
apiVersion: v1
kind: Pod
metadata:
name: linuxea-pods-1
namespace: default
labels:
app: linuxea.com
spec:
containers:
- name: pods-1026
image: marksugar/nginx:1.14.a
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: linuxea-pods-2
namespace: default
labels:
app: linuxea.net
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sh","-c","sleep 3600"]
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["linuxea.com"]}
topologyKey: wwwlabel
[root@linuxea schedule]# kubectl apply -f pods-required-anti-affinity.yaml
pod/linuxea-pods-1 created
pod/linuxea-pods-2 created
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
linuxea-pods-1 1/1 Running 0 7s 172.16.4.25 linuxea.node-2.com <none>
linuxea-pods-2 0/1 Pending 0 7s <none> <none> <none>