之前的scheduler,默认的default scheduler分三部实现调度过程,首先是预选,从所有节点当中选择基本符合选择条件的节点,而后在众多基本符合选择条件的节点中通过优选函数,对这些节点加以比较。并且从最高得分当中随机选择一个作为运行pod的节点。这就是scheduler负责的功用。
高级调度机制
节点调度
在某些调度参加中,可通过自己的预设来影响预选,优选的过程,从而使得调度的操作符合期望。如,一个pod应该固定的被运行在某个节点,就可以使用预设的方式来影响调度来达到预期的目的。
此类的影响方式有4种,这4种都可成为高级调度设置机制
1,节点选择器,如nodeSelector,nodename
2,节点亲和性调度,nodeAffinity
对于nodename来讲,我们期望将pod调度到某一个特定的节点之上,就可以在nodename属性当中直接给定node的名称,而后对应的这个pod,一定只能会调度到这个node节点之上。
如果有一类节点都符合调用的属性条件,并且我们期望调度到这类节点上,就可以使用nodeSelector
,可以给一部分节点打上特有的标签,在pod配置当中使用nodeSelector
匹配这些标签,节点能适配这些标签的就是pod可运行的节点之一。而这种方式也会非常大的缩小预选范围
1,nodeSelector
我们测试下nodeSelector的效果,如下图
在linuxea.node-3.com
节点之上,添加标签zone=linuxea.zone
[root@linuxea schedule]# kubectl label nodes linuxea.node-3.com zone=linuxea.zone
node/linuxea.node-3.com labeled
[root@linuxea schedule]# kubectl get nodes --show-labels|grep zone
linuxea.node-3.com Ready <none> 39d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=linuxea.node-3.com,zone=linuxea.zone
而后绑定到linuxea.zone标签的节点之上
[root@linuxea schedule]# cat pods.yaml
apiVersion: v1
kind: Pod
metadata:
name: linuxea-pods-1026
namespace: default
labels:
app: linuxea.com
spec:
containers:
- name: pods-1026
image: marksugar/nginx:1.14.a
ports:
- name: http
containerPort: 80
nodeSelector:
zone: linuxea.zone
[root@linuxea schedule]# kubectl apply -f pods.yaml
pod/linuxea-pods-1026 created
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
linuxea-pods-1026 1/1 Running 0 2h 172.16.5.12 linuxea.node-3.com
此时linuxea-pods-1026名称的pod就运行在node3之上。因为只有node3才有 zone: linuxea.zone
标签
- 如果nodeSelector定义的标签在节点内不存在就会挂起。nodeSelector是签约束,如果不满足条件,在预选时候就会停止。
此刻将nodeSelector的标签修改成 zone: linuxea.zone.cn
。 zone: linuxea.zone.cn
是不存在的。
nodeSelector:
zone: linuxea.zone.cn
那么标签 zone: linuxea.zone.cn
不存在在节点上,这个pod就会Pending。因为pod中nodeSelector的标签不存在。
[root@linuxea schedule]# kubectl apply -f pods.yaml
pod/linuxea-pods-1026 created
[root@linuxea schedule]# kubectl get pods
NAME READY STATUS RESTARTS AGE
linuxea-pods-1026 0/1 Pending 0 3s
将node1.linuxea.com打上zone: linuxea.zone.cn标签,就会将linuxea-pods-1026调度到node1上
[root@linuxea schedule]# kubectl label nodes linuxea.node-1.com zone=linuxea.zone.cn
node/linuxea.node-1.com labeled
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
linuxea-pods-1026 1/1 Running 0 46s 172.16.3.2 linuxea.node-1.com
2,nodeAffinity
在pod.spec.affinity
中就有affinity
,在affinity
中nodeAffinity
(节点亲和性),podAffinity
(pod亲和性),podAntiAffinity
(pod反亲和性)
在nodeAffinity
中有两项如下:
requiredDuringSchedulingIgnoredDuringExecution
requiredDuringSchedulingIgnoredDuringExecution
是硬亲和性,也就是说必须满足条件。与nodeSelector
相似,如果不满足亲和定义的条件,就一定不会运行,那么就会pending状态
preferredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution
倾向性。优先运行满足节点亲和性高的节点上。尽量满足条件,如果不能够尽量的满足条件,那也可以找其他节点运行。当然,能够运行在亲和性高,满足条件多的节点是最好不过了。
在preferredDuringSchedulingIgnoredDuringExecution
下嵌套:
preference
倾向节点weight
倾向权重
在requiredDuringSchedulingIgnoredDuringExecution
下的nodeSelectorTerms
定义对象列表,并且嵌套节点选择器Terms。在nodeSelectorTerms
之下嵌套
matchExpressions
:匹配表达式
matchFields
:匹配字段
- 在
matchFields
下需要定义key,检查label key,操作符operator(等值或者不等值选择,以及集合的标签,如果使用exists,或者doesnotexist
的时候values是不能有值的),values只需要给定值即可 matchExpressions
定义表达式基于标签选择。
开始测试requiredDuringSchedulingIgnoredDuringExecution
其中定义affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchExpressions
,定义key是zone,operator操作符是In,values是www.linuxea.com,而后在添加weight ,如上图yaml
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: In
values:
- www.linuxea.com
如下:
[root@linuxea schedule]# cat pods_nodeAffinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: linuxea-nodeaffinity
namespace: default
labels:
app: linuxea.com
spec:
containers:
- name: pods-1026
image: marksugar/nginx:1.14.a
ports:
- name: http
containerPort: 80
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: In
values:
- www.linuxea.com
apply
[root@linuxea schedule]# kubectl apply -f pods_nodeAffinity.yaml
pod/linuxea-nodeaffinity created
此刻状态是Pending,因为目前并没有zone标签,且值是等值的www.linuxea.com的node
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
linuxea-nodeaffinity 0/1 Pending 0 9s <none> <none> <none>
并且定义的是requiredDuringSchedulingIgnoredDuringExecution
硬亲和性,在上述中,我们知道硬亲和性的话,如果不存在,就不会选中。所以被Pending
preferredDuringSchedulingIgnoredDuringExecution
那么这样以来就无法绑定了,我们尝试使用倾向性绑定,这和硬绑定requiredDuringSchedulingIgnoredDuringExecution不同,配置preference和weight即可,如下:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: zone
operator: In
values:
- www.linuxea.com
weight: 60
如下:
[root@linuxea schedule]# cat pods_nodeAffinity-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: linuxea-nodeaffinity
namespace: default
labels:
app: linuxea.com
spec:
containers:
- name: pods-1026
image: marksugar/nginx:1.14.a
ports:
- name: http
containerPort: 80
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: zone
operator: In
values:
- www.linuxea.com
weight: 60
apply
[root@linuxea schedule]# kubectl apply -f pods_nodeAffinity-2.yaml
pod/linuxea-nodeaffinity created
而后调度到node2节点。
[root@linuxea schedule]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
linuxea-nodeaffinity 1/1 Running 0 6s 172.16.4.9 linuxea.node-2.com <none>
[root@linuxea schedule]# kubectl describe pods linuxea-nodeaffinity|tail -6
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m default-scheduler Successfully assigned default/linuxea-nodeaffinity to linuxea.node-2.com
Normal Pulled 6m kubelet, linuxea.node-2.com Container image "marksugar/nginx:1.14.a" already present on machine
Normal Created 6m kubelet, linuxea.node-2.com Created container
Normal Started 6m kubelet, linuxea.node-2.com Started container
但是我们知道,node2肯定是不符合硬性条件的。但是仅仅尽量满足而已。如果此时在其他节点打上一个符合的标签,如果使用preferred仍然会调度到符合条件的节点上。如果使用required则只会调度到符合的节点,而不会尽量满足调用,而是硬性满足,没有则pending。这就是两种节点亲和,前者硬性亲和,后者软亲和。