在k8s的调度中,有强制性的nodeSelector,节点亲和性nodeAffinity、Pod亲和性podAffinity、pod反亲和性podAntiAffinity。本篇先对nodeSelector和nodeAffinity做个初探。
进入主题之前,先看看创建pod的大概过程
k8s的各个组件是基于list-watch机制进行交互的,了解了list-watch机制,以及结合上述pod的创建流程,就可以很好的理解各个组件之间的交互。
关于list-watch机制概念(参考):
list-watch机制是一种比较常用的分布式协调机制,它使得系统中的多个节点能够相互通信并且同步更新状态。list-watch机制的基本原理是:一个节点A将发布一个列表存储到共享内存,然后另一个节点B可以访问该存储列表,当A对该存储列表进行任何变更时,系统会自动通知B节点同步数据。list-watch是一种轻量级的架构,用于在分布式环境中支持和管理系统name-value对模型。首先,它构建一个包含所有name-value对的结构,当name-value发生变化时更新这个结构,然后将其提供给特定的节点。对于每个节点,可以创建一条监视链条,以便检测名称-值的变化,以便节点能够保持最新的数据。如果name-value发生变化,list-watch机制将通知特定节点同步新的name-value。list-watch机制的工作方式非常简单,它不需要复杂的分布式框架。list-watch机制非常适合用于高可用系统,因为它可以自动地进行数据共享和同步,使各个节点能够及时获取最新的信息,从而提升系统的可用性和可靠性。此外,list-watch还可以帮助系统在各个节点上实现一致,这有助于提高系统的可扩展性,改进其可靠性和稳定性。
说白了就是将Pod指派到合适的节点上,以便对应节点上的Kubelet能够运行这些Pod。在k8s中,承担调度工作的组件是kube-scheduler,它也是k8s集群的默认调度器,它在设计上就允许编写一个自定义的调度组件并替换原有的kube-scheduler。所以,如果你足够牛逼,就可以自己开发一个调度器来替换默认的了。调度器通过K8S的监测(Watch)机制来发现集群中新创建且尚未被调度到节点上的Pod,调度器会将所发现的每一个未调度的Pod调度到一个合适的节点上来运行。
kube-scheduler给一个Pod做调度选择时包含了两个步骤:过滤、打分。
实际工作中,可能会有这样的情况,需要进一步控制Pod被部署到哪个节点。例如,确保某些Pod最终落在具有SSD硬盘的主机上,又需要确保某些pod落在具体部门的主机上运行,这时就可以使用标签选择器来进行选择。
进一步对nodeAffinity的理解:我对亲和性和反亲和性的理解是这样的,亲和性就是希望某些pod在同一个node上,反亲和性是希望某些pod不要在同一个node上。nodeAffinity是亲和性的,它的NotIn和DoesNotExist可用来实现节点反亲和性行为(当然也可以使用节点污点将Pod从特定节点上驱逐,后面专门分享),通过逻辑组合可以控制pod要部署在哪些节点上,以及不能部署在哪些节点上。
注意:
pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: goweb-demo
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 调度器只有在规则被满足的时候才执行调度
nodeSelectorTerms:
- matchExpressions:
- key: team
operator: In
values:
- team-a
- team-b
preferredDuringSchedulingIgnoredDuringExecution: # 调度器会尝试寻找满足对应规则的节点(如果找不到匹配的节点,调度器仍然会调度该Pod)
- weight: 1
preference:
matchExpressions:
- key: hostbrand
operator: In
values:
- ibm
containers:
- name: container-goweb-demo
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
配置node的标签
# 设置标签
kubectl label node test-b-k8s-node01 team=team-a
kubectl label node test-b-k8s-node02 team=team-b
kubectl label node test-b-k8s-node01 hostbrand=ibm
# 查看
kubectl get node --show-labels
# 创建
kubectl create -f pod.yaml
# 查看Pod
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
goweb-demo 1/1 Running 0 17s 10.244.240.58 test-b-k8s-node01 <none> <none>
tantianran@test-b-k8s-master:~/goweb-demo$
在上面的案例中,所应用的规则如下:
关于节点亲和性权重的weight字段:
pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: goweb-demo
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: team
operator: In
values:
- team-a
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
- weight: 50
preference:
matchExpressions:
- key: disktype
operator: In
values:
- sas
containers:
- name: container-goweb-demo
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
# 创建
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl create -f pod.yaml
pod/goweb-demo created
# 查看
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
goweb-demo 1/1 Running 0 35s 10.244.240.18 test-b-k8s-node01 <none> <none>
tantianran@test-b-k8s-master:~/goweb-demo$
上面的例子,存在两个候选节点,都满足 preferredDuringSchedulingIgnoredDuringExecution 规则, 其中一个节点具有标签 disktype:ssd,另一个节点具有标签 disktype:sas,调度器会考察各个节点的weight取值,并将该权重值添加到节点的其他得分值之上。
设置节点的标签
# 给节点打标签,key和value:gpu=true
kubectl label node test-b-k8s-node02 gpu=true
node/test-b-k8s-node02 labeled
# 查看指定节点标签
kubectl get node test-b-k8s-node02 --show-labels
# 不指定节点时,查看所有节点标签
kubectl get node --show-labels
添加nodeSelector字段到pod配置
apiVersion: v1
kind: Namespace
metadata:
name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: goweb-demo
namespace: test-a
spec:
replicas: 10
selector:
matchLabels:
app: goweb-demo
template:
metadata:
labels:
app: goweb-demo
spec:
nodeSelector:
gpu: true
containers:
- name: goweb-demo
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
---
apiVersion: v1
kind: Service
metadata:
name: goweb-demo
namespace: test-a
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8090
selector:
app: goweb-demo
type: NodePort
提示:刚测了一下,非要取这种标签的话gpu=true,在yaml定义时gpu: true ,true就要加双引号,它是字符串,不加的话,他认为是bool。所以,设置node的标签,value以后尽量不要是true/false,非要的话,指定时加上双引号即可。
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
goweb-demo-69d79997f7-24862 1/1 Running 0 16m 10.244.222.7 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-48c62 1/1 Running 0 16m 10.244.222.32 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-76jd9 1/1 Running 0 16m 10.244.222.51 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-dt7sf 1/1 Running 0 16m 10.244.222.21 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-fddpd 1/1 Running 0 16m 10.244.222.60 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-lw2t8 1/1 Running 0 16m 10.244.222.47 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-nwwkg 1/1 Running 0 16m 10.244.222.10 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-v768k 1/1 Running 0 16m 10.244.222.38 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-vgt5w 1/1 Running 0 16m 10.244.222.56 test-b-k8s-node02 <none> <none>
goweb-demo-69d79997f7-xqhxp 1/1 Running 0 16m 10.244.222.41 test-b-k8s-node02 <none> <none>
如果创建pod,指派的标签是不存在任何1台节点时,pod会一直处于pending状态,直至进入Terminating状态,pod的重启策略是always(默认策略:当容器退出时,总是重启容器),则一直在pending和Terminating中徘徊,直到有符合条件的标签,就会立马分配节点,从而创建pod。
删除标签
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl label node test-b-k8s-node02 gpu-
node/test-b-k8s-node02 unlabeled
tantianran@test-b-k8s-master:~/goweb-demo$
提示:key和小横杠之间不能有空格,否则删除失败。
本篇先对节点选择器和节点亲和性暂时做个初探性的分享,后续还会持续分享多几个贴近实际环境的各种场景调度的逻辑组合案例。
本文转载于(喜欢的盆友关注我们):https://mp.weixin.qq.com/s/QffBfGLpguAxSzucnkX-rQ
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。