Pod调度
在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相关的算法计算得到的,这个过程不受人工控制的。但是在实际的使用过程中,这并不满足相关的需求,因为在很多的情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这个就需要了解kubernetes对Pod的调度规则,kubernetes提供了四大类的调度方式:
- 自动调度: 运行在哪个节点上完全由Secheduler经过一系列的算法计算得到的
- 定向调度: NodeName、NodeSelector
- 亲和性调度: NodeAffinity、PodAffinity、PodAntiAffinity
- 污点(容忍)调度: Taints、Toleration
定向调度
定向调度,指的是利用在Pod上声明nodeName或者nodeSelector,以此将Pod调度到期望的node节点上。注意,这里的调度是强制的,这就意味着即使要调度的目标Node节点不存在,也会向上面进行调度,只不过pod运行失败而已。
NodeName
NodeName用于强制约束将Pod调度到指定的Name的Node节点上。这种方式,其实是直接跳过Scheduler的调度逻辑的,直接将Pod调度到指定名称的节点。
获取节点信息

创建一个pod-nodename.yaml文件
yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodename
namespace: dev
spec:
containers:
- name: nginx
image: docker.1ms.run/library/nginx:latest
nodeName: k8s-cluster-worker # 指定调度到 k8s-cluster-worker节点上
创建pod资源

查看pod的资源挂载情况
bash
sudo kubectl get pod pod-nodename -n dev -o wide

改成不存在的节点上

重新创建pod资源

pod资源的状态 pod创建失败

bash
sudo kubectl describe pod pod-nodename -n dev -o wide

NodeSelector
NodeSelector用于将pod调度到添加了指定标签的node节点上,他是通过kubernetes的label-selector机制 来实现的。也就是说,在pod创建之前,会由scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标Node,然后将pod调度到目标节点,该匹配规则是强制约束。
演示一下,需要先给node节点打标签
bash
sudo kubectl label node k8s-cluster-worker nodeenv=pro

pod-nodeselector.yaml文件,并使用它创建Pod
yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeselector
namespace: dev
spec:
containers:
- name: nginx
image: docker.1ms.run/library/nginx:latest
nodeSelector:
nodeenv: pro # 指定调度到具有nodeenv=pro标签的节点上

查看创建的pod资源挂载的节点

通过标签选择node节点成功
亲和性调度
上面的两种定向调度的方式,使用起来非常方便,但是也有一定的问题,那就是如果没有满足条件的Node,那么Pod将不会被运行,即使在集群中还有可用Node列表也不行,这就限制了它的使用场景。
基于上面的问题,kubernetes还提供了一种亲和性调度(Affinity) 。它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。
Affinity主要分为三类:
- nodeAffinity(node亲和性): 以node为目标,解决pod可以调度到哪些node的问题
- podAffinity(pod亲和性) : 以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题
- podAntiAffinity(pod反亲和性) : 以pod为目标,解决pod不能和哪些已存在pod部署在同一个拓扑域中的问题
关于亲和性(反亲和性)使用场景的说明:
亲和性:如果两个应用频繁交互,那就有必要利用亲和性让两个应用的尽可能的靠近,这样可以减少因网络通信而带来的性能损耗。
反亲和性:当应用的采用多副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性。
NodeAffinity
NodeAffinity的可配置项:
bash
pod.spec.affinity.nodeAffinity
requiredDuringSchedulingIgnoredDuringExecution Node节点必须满足指定的所有规则才可以,相当于硬限制
nodeSelectorTerms 节点选择列表
matchFields 按节点字段列出的节点选择器要求列表
matchExpressions 按节点标签列出的节点选择器要求列表(推荐)
key 键
values 值
operat or 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
preferredDuringSchedulingIgnoredDuringExecution 优先调度到满足指定的规则的Node,相当于软限制 (倾向)
preference 一个节点选择器项,与相应的权重相关联
matchFields 按节点字段列出的节点选择器要求列表
matchExpressions 按节点标签列出的节点选择器要求列表(推荐)
key 键
values 值
operator 关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
weight 倾向权重,在范围1-100。
bash
关系符的使用说明:
- matchExpressions:
- key: nodeenv # 匹配存在标签的key为nodeenv的节点
operator: Exists
- key: nodeenv # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
operator: In
values: ["xxx","yyy"]
- key: nodeenv # 匹配标签的key为nodeenv,且value大于"xxx"的节点
operator: Gt
values: "xxx"
演示一下requiredDuringSchedulingIgnoredDuringExecution
创建pod-nodeaffinity-required.yaml
yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity-required
namespace: dev
spec:
containers:
- name: nginx
image: docker.1ms.run/library/nginx:latest
affinity: #亲和性设置
nodeAffinity: #设置node亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
nodeSelectorTerms:
- matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签
- key: nodeenv
operator: In
values: ["xxx","yyy"]
创建相关的pod资源

查看pod的资源信息
bash
kubectl get pods pod-nodeaffinity-required -n dev -o wide

bash
kubectl describe pod pod-nodeaffinity-required -n dev
Warning FailedScheduling 2m default-scheduler 0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling...
