文章目录
一、pod调度概述
在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。但是在实际使用中,这并不满足的需求,因为很多情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这就要求了解kubernetes对Pod的调度规则。
kubernetes提供了四大类调度方式:
- 自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出
- 定向调度:NodeName、NodeSelector
- 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
- 污点(容忍)调度:Taints、Toleration
二、定向调度
定向调度,指的是利用在pod上声明 nodeName 或者 nodeSelector ,以此将Pod调度到期望的node节点上。
注意,这里的调度是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过pod运行失败而已。
(一)nodeName
NodeName用于强制约束将Pod调度到指定的Name的Node节点上。
这种方式,其实是直接跳过Scheduler的调度逻辑,直接将Pod调度到指定名称的节点。
[root@k8s-master ~]# vim pod-nodename.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodename
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 801
nodeName: k8s-node01 # 指定将该pod调度到k8s-node01节点上。nodeName键所指定的值必须是 kubectl get node 命令所查出来的,nodeName是固定写法
[root@k8s-master ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 5d20h v1.17.4
k8s-node01 Ready <none> 5d20h v1.17.4
k8s-node02 Ready <none> 5d20h v1.17.4
[root@k8s-master ~]# kubectl create -f pod-nodename.yaml
pod/pod-nodename created
[root@k8s-master ~]# kubectl get pod pod-nodename -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-nodename 1/1 Running 0 17s 10.244.1.36 k8s-node01 <none> <none>
[root@k8s-master ~]# kubectl delete -f pod-nodename.yaml
pod "pod-nodename" deleted
# 指定将pod运行在一个不属于集群中的某节点上
[root@k8s-master ~]# vim pod-nodename.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodename
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
nodeName: node100
[root@k8s-master ~]# kubectl create -f pod-nodename.yaml
pod/pod-nodename created
[root@k8s-master ~]# kubectl get pod pod-nodename -n test -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-nodename 0/1 Pending 0 29s <none> node100 <none> <none>
pod-nodename 0/1 Terminating 0 56s <none> node100 <none> <none>
pod-nodename 0/1 Terminating 0 56s <none> node100 <none> <none>
# 因为没有该节点,所以无法调度到,过一会就会自动删除该pod
(二)nodeSelector
NodeSelector用于将pod调度到添加了指定标签的node节点上。
它是通过kubernetes的label-selector机制实现的,也就是说,在pod创建之前,会由sceduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将pod调度到目标节点,该匹配规则是强制约束,没有则失败。
首先为node节点添加标签:
[root@k8s-master ~]# kubectl label node k8s-node01 nodeenv=pro
node/k8s-node01 labeled
[root@k8s-master ~]# kubectl label node k8s-node02 nodeenv=test
node/k8s-node02 labeled
# 查看
[root@k8s-master ~]# kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready master 5d20h v1.17.4 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/master=
k8s-node01 Ready <none> 5d20h v1.17.4 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux,nodeenv=pro
k8s-node02 Ready <none> 5d20h v1.17.4 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node02,kubernetes.io/os=linux,nodeenv=test
创建使用nodeSelector调度pod的配置文件:
[root@k8s-master ~]# vim pod-nodeselector.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeselector
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
nodeSelector:
nodeenv: pro # 指定调度到具有 nodeenv=pro 标签的节点上。键值对必须存在,不存在调度会失败
# 创建
[root@k8s-master ~]# kubectl create -f pod-nodeselector.yaml
pod/pod-nodeselector created
# 调度到指定节点上
[root@k8s-master ~]# kubectl get pod pod-nodeselector -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-nodeselector 1/1 Running 0 16s 10.244.1.37 k8s-node01 <none> <none>
# 删除
[root@k8s-master ~]# kubectl delete -f pod-nodeselector.yaml
pod "pod-nodeselector" deleted
# 指定pod调度带到在不存在的节点标签上
[root@k8s-master ~]# vim pod-nodeselector.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeselector
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
nodeSelector:
nodeenv: pro100 # 不存在的节点标签
[root@k8s-master ~]# kubectl create -f pod-nodeselector.yaml
pod/pod-nodeselector created
# 找不带此node节点,调度失败
[root@k8s-master ~]# kubectl get pod pod-nodeselector -n test -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-nodeselector 0/1 Pending 0 2m3s <none> <none> <none> <none>
[root@k8s-master ~]# kubectl describe pod pod-nodeselector -n test
……省略……
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector.
Warning FailedScheduling <unknown> default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector. # 在3个节点(1个master,2个node)上无法找到具有该标签的节点
# 虽然调度失败,但不会自动删除该pod,需手动删除
[root@k8s-master ~]# kubectl delete -f pod-nodeselector.yaml
pod "pod-nodeselector" deleted
# 删除主机标签
[root@k8s-master ~]# kubectl label node k8s-node01 nodeenv-
node/k8s-node01 labeled
[root@k8s-master ~]# kubectl label node k8s-node02 nodeenv-
node/k8s-node02 labeled
三、亲和性调度
上面基于 nodeName 和 nodeSelector 的两种定向调度的方式,使用比较方便,但是存在一定问题,那就是如果没有满足条件的node,那么pod将不会被调度和运行,即使在集群中还有可用node列表也不行,这就限制了它的使用场景。
基于此问题,kubernetes提供了一种亲和性调度(Affinity)。它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。
Affinity主要分为三类:
- nodeAffinity(node亲和性) ∶以node为目标,解决pod可以调度到哪些node的问题
- podAffinitypod亲和性):以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题
- podAntiAffinity(pod反亲和性):以pod为目标,解决pod不能和哪些已存在pod部署在同一个拓扑域中的问题
关于亲和性(反亲和性)使用场景的说明:
亲和性:如果两个应用频繁交互,那就有必要利用亲和性让两个应用的尽可能的靠近,这样可以减少因网络通信而带来的性能损耗。
反亲和性:当应用的采用多副本部署时,有必要采用反亲和性让各