pod调度:节点选择与亲和

0、简介
k8s对于pod的调度有如下几种:按node名称、按标签、节点亲和、pod亲和

1、使用nodeName指定节点
场景:
pod需要部署到指定节点。
方案:

[root@vmroot schedule-yamls]# cat schedule-deloyment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: scdl-d
spec:
selector:
matchLabels:
app: scdl-d
replicas: 3
template:
metadata:
labels:
app: scdl-d
spec:
nodeName: cloudk8sn1 #通过节点名称指定pod目标节点
containers:
- name: scdl-d
image: alpine:latest
command: ['sh', '-c', 'sleep 3600']
restartPolicy: Always
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
全部pod都已调度到指定节点


2、标签选择
与直接选择节点相比,标签名称更有意义,且标签选择类似群组的功能,可以对多个节点打相同标签,集群节点变更时方便修改,不需要修改pod的yaml。
场景:
节点cloudk8sn1是ssd硬盘,其它节点是机械硬盘
要求:应用调度到ssd节点上
方案:

[root@vmroot schedule-yamls]# kubectl label node cloudk8sn1 disktype=ssd #添加标签
[root@vmroot schedule-yamls]# kubectl label node cloudk8sn1 disktype- #移除标签
1
2


部署pod,选择含disktype=ssd标签的节点。

[root@vmroot schedule-yamls]# cat schedule-deloyment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: scdl-d
spec:
selector:
matchLabels:
app: scdl-d
replicas: 3
template:
metadata:
labels:
app: scdl-d
spec:
nodeSelector:
disktype: ssd #这里指定标签名称
containers:
- name: scdl-d
image: alpine:v1
command: ['sh', '-c', 'sleep 3600']
restartPolicy: Always
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
全部pod部署到了含disktype=ssd的节点上,如果有新ssd节点加入集群,只需为新节点打上disktype=ssd标签,不需要改yaml文件


3、亲和与反亲和
相对于节点标签选择,有以下优点:
● 支持多种匹配表达式,不只是全名称精确匹配
● 支持required必须满足和preferred倾向满足,不只是必须满足
● 匹配对象除了node标签还支持pod标签
● 分为亲和与反亲和

1–node亲和
属于节点标签选择的升级版,功能依旧是pod对打了标签node的一种选择决策
亲和性限制方式有以下两种:
①requiredDuringSchedulingIgnoredDuringExecution:必须满足(也叫硬亲和),效果与节点标签选择一样,pod不会调度到不满足条件的节点。且必须与nodeSelector同时满足
②preferredDuringSchedulingIgnoredDuringExecution:更倾向满足(也叫软亲和),pod如果没得选也会被调度到不满足条件的节点上(IgnoredDuringException表示忽略pod运行期间node标签变化导致亲和性不满足)

场景:
节点cloudk8sn1和cloudk8sn2都是固态硬盘,vmroot是机械硬盘,cloudk8sn2是ddr4的内存
要求1:应用必须部署到ssd硬盘的节点上(必须满足requiredDuringSchedulingIgnoredDuringExecution)
要求2:应用尽量部署到ddr4的节点上(倾向满足preferredDuringSchedulingIgnoredDuringExecution)
方案:

①为节点打标签
[root@vmroot schedule-yamls]# kubectl label nodes cloudk8sn1 disktype=ssd
[root@vmroot schedule-yamls]# kubectl label nodes cloudk8sn2 disktype=ssd
[root@vmroot schedule-yamls]# kubectl label nodes cloudk8sn2 memtype=ddr4
1
2
3
查看标签


②配置亲和性
[root@vmroot schedule-yamls]# cat schedule-deloyment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: scdl-d
spec:
selector:
matchLabels:
app: scdl-d
replicas: 10
template:
metadata:
labels:
app: scdl-d
spec:
affinity: #从里开始写亲和
nodeAffinity: #节点亲和(根据实际情况也可以配置反亲和)
requiredDuringSchedulingIgnoredDuringExecution: #必须满足的亲和
nodeSelectorTerms: #可以写多个nodeSelectorTerms,其中一个满足即可
- matchExpressions: #可以写多个matchExpressions,但必须全满足才行
- key: disktype #标签的key
operator: In #匹配方式,还有NotIn、Exists、DoesNotExist、Gt 和 Lt 可选
values:
- ssd #标签的value,可以匹配多个
preferredDuringSchedulingIgnoredDuringExecution: #倾向的亲和
- weight: 1 #取值范围1-100,当有多个倾向条件时按优先级匹配
preference:
matchExpressions:
- key: memtype
operator: In
values:
- ddr4
containers:
- name: scdl-d
image: alpine:v1
command: ['sh', '-c', 'sleep 3600']
restartPolicy: Always
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
36
37
如果你同时指定了 nodeSelector 和 nodeAffinity,两者 必须都要满足, 才能将 Pod 调度到候选节点上。
如果你指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms, 只要其中一个 nodeSelectorTerms 满足的话,Pod 就可以被调度到节点上。
如果你指定了多个与同一 nodeSelectorTerms 关联的 matchExpressions, 则只有当所有 matchExpressions 都满足时 Pod 才可以被调度到节点上。

可以看到,由于节点软亲和的存在,更多的pod调度到了cloudk8sn2节点

 

2–pod亲和
属于node亲和的升级版,不再是pod选择含标签的node,而是选择含标签pod所在的node,比较损耗性能,用于pod对pod的约束
名称分别是podAffinity 和 podAntiAffinity,其它和node亲和一样

①场景1:
有个项目名为zyz,由前端web和后端java两个服务组成,客户位于香港。当前集群节点vmroot 和cloudk8sn1 在香港,cloudk8sn2在哈尔滨
要求1:项目必须部署到位于香港的节点vmroot或cloudk8sn1(node硬亲和或节点标签选择)
要求2:后端必须调度到有前端的节点,减少通讯损耗(pod硬亲和)
要求3:后端尽量不要调度到cloudk8sn1,因为该节点运行着一个大型的应用(pod软反亲和)
场景模拟:
为节点打标签

[root@vmroot schedule-yamls]# kubectl label nodes vmroot zone=hongkong
[root@vmroot schedule-yamls]# kubectl label nodes cloudk8sn1 zone=hongkong
[root@vmroot schedule-yamls]# kubectl taint node vmroot node-role.kubernetes.io/master- #去除master污点
1
2
3
在cloudk8sn1节点部署一个含property=large标签的pod

方案:
1)写前端yaml,没用到亲和

[root@vmroot schedule-yamls]# cat zyz-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: zyz-web
spec:
selector:
matchLabels:
appname: zyz-web
replicas: 2
template:
metadata:
labels:
appname: zyz-web #定义标签
spec:
nodeSelector:
zone: hongkong #节点标签选择
containers:
- name: zyz-web
image: alpine:v1
command: ['sh', '-c', 'sleep 3600']
restartPolicy: Always
[root@vmroot schedule-yamls]# kubectl apply -f zyz-web.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2)写后端yaml

[root@vmroot schedule-yamls]# cat zyz-java.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: zyz-java
spec:
selector:
matchLabels:
appname: zyz-java
replicas: 3
template:
metadata:
labels:
appname: zyz-java
spec:
affinity: #从里开始写亲和
podAffinity: #pod亲和
requiredDuringSchedulingIgnoredDuringExecution: #必须调度到含appname=zyz-web标签的pod的节点上(pod的标签)
- labelSelector:
matchExpressions:
- key: appname
operator: In
values:
- zyz-web
topologyKey: zone #topologyKey字段表示:被调度的节点必须含有key为zone的标签(node的标签)
podAntiAffinity: #pod反亲和
preferredDuringSchedulingIgnoredDuringExecution: #尽量不要调度到含有property=large标签的pod的节点上(pod标签)
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: property
operator: In
values:
- large
topologyKey: kubernetes.io/hostname #这个字段必须写,没什么写的就写hostname,因为每个节点都有hostname这个标签
containers:
- name: zyz-java
image: alpine:v1
command: ['sh', '-c', 'sleep 3600']
restartPolicy: Always
[root@vmroot schedule-yamls]# kubectl apply -f zyz-java.yaml
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
36
37
38
39
40
41
42
效果为:尽量调度到vmroot节点;绝不调度到couldk8sn2节点
注意:不能两个pod写相互硬亲和,这样pod都是pending状态

*对于topologyKey字段,经测试只要求节点含有指定的key,value可以为任意。官网示例的解释为“调度器必须将 Pod 调度到具有 topology.kubernetes.io/zone=V 标签的节点上”

②场景2:
对于场景①,可以把property=large这个标签打给cloudk8sn1然后用节点亲和,就不需要使用pod反亲和。接下来这个场景很好的体现了pod反亲和的用途
要求:
多个nginx部署到固态硬盘的节点上且尽量分散,达到高可用的效果
准备:
清除之前的环境(略),现在vmroot和cloudk8sn2有disk=ssd的标签
方案:

[root@vmroot schedule-yamls]# cat nginxha.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginxha
spec:
selector:
matchLabels:
appname: nginxha
replicas: 3
template:
metadata:
labels:
appname: nginxha
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk #必须部署到ssd的node
operator: In
values:
- ssd
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: appname
operator: In
values:
- nginxha #用自己的label做pod反亲和,互相排斥,达到分散目的
topologyKey: kubernetes.io/hostname
containers:
- name: nginxha
image: alpine:v1
command: ['sh', '-c', 'sleep 3600']
restartPolicy: Always
[root@vmroot schedule-yamls]# kubectl apply -f nginxha.yaml
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
36
37
38
39
40
41


pod尽量在分散部署,且不会部署到cloudk8sn1,如果节点多效果更清晰

4、参考:
https://www.jianshu.com/p/61725f179223
https://zhuanlan.zhihu.com/p/405150555
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/
————————————————
版权声明:本文为CSDN博主「雪碧能喝多」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/seven_xu_/article/details/125268566

posted @ 2023-05-22 19:23  GaoYanbing  阅读(91)  评论(0编辑  收藏  举报