理论:POD从创建开始,到完成调度的详细过程。
实践:K8S都提供了哪些可选的调度策略。
POD调度流程
K8S调度的架构设计图:
中枢大脑:ApiServer。
ETCD和ApiServer是跟调度器紧密关联的。
K8S是如何完成POD调度呢?
(1)首先要知道调度哪个POD?要知道POD的信息,POD的信息从优先级队列(用于存储等待调度的POD列表)中拿。
(2)为啥使用优先级队列呢?考虑每个POD并不是对等的。有的服务重要,有的服务不那么重要,重要的服务要提前被调度而出队。
(3)队列有了,要有个人往里面放消息。Informer通知者,可通过ApiServer去监听ETCD的数据变化,比如监听了新增的POD。
=========================
新增的POD和普通的POD啥区别。新增的POD少一个配置,节点的名字。
#第一次创建没有nodeName。再次apply就会有。
#在经过调度器之后,才会知道运行在哪个节点上,才会把它加上去。
[root@node-1 4-health-check]# kubectl get pods -n dev web-demo-579d58cc8c-77kkp -o yaml
在
spec:
中少了
nodeName: node-2
=========================
(4)Informer发现有等待调度的POD,把POD的信息放到优先级队列中,它的工作就完成了,就会进入这个循环,把监听的信息放入队列。
那么scheduler就会从这个队列中拿到POD信息了。
(5)这样就该决定把POD调度在哪个节点上了。
要想调度到节点,首先得知道现在有哪些节点,这些信息可以从ApiServer中拿。
如果每调度一个POD,就去ApiServer请求许多信息,那么性能会差很多。
于是K8S设计了一个cache缓存,cache会从ApiServer拿到想要的数据缓存起来,节点列表、每个节点的详细信息(CPU、内存、每个磁盘的镜像、运行哪些POD、每个PDO的详细信息)都缓存在这。
(6)此时节点信息和POD信息都有了,那么就可以开始进行POD调度了。
调度过程分两步:
第一步:预选策略,初步过滤不符合需求的节点。Cache和优先级队列信息都拿过来,流程就可以开始了。
预选策略包括:剩余内存、CPU、对端口的检查,挂载的volume类型必须匹配、nodeSelector的规则必须匹配、节点状态必须正常、POD亲和性、POD污点等。
找到不满足要求的节点。通通排出,找到满足调度的节点。
第二步:优选策略。对上一步筛选出来的策略进行评分,评分比较复杂,比如评分有每个项,每个项还有各自的权重,整体的CPU、内存资源平衡性、NODE上是否存在运行的镜像、同一个deployment的POD是否已经调度了、POD的亲和性、POD的非亲和性、POD污点等,一项项统计,最终会对每一个POD进行一个评分,选择最高分的NODE作为最终调度POD的节点。
(7)POD和NODE做绑定关系。这也是K8S的一种资源,bangding。
会把这个绑定信息给ApiServer,ApiServer负责去更新上述spec.nodeName的值,指派给具体节点的kubelet,就会把这个服务调度起来了。
(8)这个定义流程已经定义好了,跟K8S的使用者有什么关系吗?
在讲label时,在deployment中配置了nodeSelector,选择了disktype: ssd的节点,这个定义就是这个流程中的预选策略中完成的,选择了特定标签的节点,除了nodeSelector还有很多跟调度相关的配置。
实践:
[root@node-1 5-scheduler]# kubectl get nodes node-2 -o yaml
方式1:node方式
[root@node-1 5-scheduler]# cat web-dev-node.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-demo-node
namespace: dev
spec:
selector:
matchLabels:
app: web-demo-node
replicas: 1
template:
metadata:
labels:
app: web-demo-node
spec:
containers:
- name: web-demo-node
image: hub.mooc.com/kubernetes/web:v1
ports:
- containerPort: 8080
#亲和性
affinity:
#POD跟节点的亲和性的关系
#节点的亲和性
nodeAffinity:
#必须满足下述的配置才能被调度
requiredDuringSchedulingIgnoredDuringExecution:
#节点的选择策略。数组形式。
#每个nodeSelectorTerms之间是或的关系。满足各种组合的需求。
nodeSelectorTerms:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
- matchExpressions:
#匹配节点的名字
- key: beta.kubernetes.io/arch
#操作:In
operator: In
values:
#架构是amd64的
#POD需要运行在CPU为amd64架构的机器上。这里的机器满足。
- amd64
#最好是怎么样,而不是必须怎么样,所以这里不存在上述的或和并且的关系逻辑。
#如果A节点资源满了,那么即使A满足此条件,可能会被调度到B节点。
preferredDuringSchedulingIgnoredDuringExecution:
#在多个之间的占比
#在这里需要的是一个权重,而不是一个强一致的逻辑关系。
- weight: 1
preference:
#匹配label的方式
matchExpressions:
- key: disktype
operator: NotIn
values:
- ssd
[root@node-1 5-scheduler]# kubectl apply -f web-dev-node.yaml
deployment.apps/web-demo-node created
#调度到非diskType:ssd的node-3节点。
#再次测试,修改requiredDuringSchedulingIgnoredDuringExecution,amd64为amd。测试完成,又改回来了。
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: beta.kubernetes.io/arch
operator: In
values:
- amd
[root@node-1 5-scheduler]# kubectl apply -f web-dev-node.yaml
deployment.apps/web-demo-node configured
[root@node-1 5-scheduler]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-demo-node-556cf67d5c-gs6gx 1/1 Running 0 4m3s 10.200.139.102 node-3 <none> <none>
web-demo-node-7dd965857f-nj6xn 0/1 Pending 0 6s <none> <none> <none> <none>
[root@node-1 ~]# kubectl describe pods web-demo-node-7dd965857f-nj6xn -n dev
0/2 nodes are available: 2 node(s) didn't match Pod's node affinity.
#再次测试,修改preferredDuringSchedulingIgnoredDuringExecution。测试完成,又改回来了。
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ss
[root@node-1 5-scheduler]# kubectl apply -f web-dev-node.yaml
deployment.apps/web-demo-node configured
[root@node-1 5-scheduler]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-demo-node-56f86cb496-rlwrn 1/1 Running 0 75s 10.200.247.46 node-2 <none> <none>
#可以发现preference是如果怎么样,没有也没啥关系,调度到了node-2节点,并没有匹配ssd。
[root@node-1 5-scheduler]# kubectl get nodes --show-labels
[root@node-1 5-scheduler]# kubectl delete -f web-dev-node.yaml
deployment.apps "web-demo-node" deleted
[root@node-1 5-scheduler]# kubectl get pods -n dev
No resources found in dev namespace.
方式2:pod方式
POD亲和性调度(不同服务相同节点)
[root@node-1 5-scheduler]# cat web-dev-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-demo-pod
namespace: dev
spec:
selector:
matchLabels:
app: web-demo-pod
replicas: 1
template:
metadata:
labels:
app: web-demo-pod
spec:
containers:
- name: web-demo-pod
image: hub.mooc.com/kubernetes/web:v1
ports:
- containerPort: 8080
#亲和性
affinity:
#POD的亲和性:一般用于在一定的区域内,一个POD跟其他POD的亲和关系,比如是否运行在一起。
#podAffinity亲和性调度可以和podAntiAffinity非亲和性调度一起配置,意思是相反的。
podAffinity:
#必须满足下述的配置才能被调度
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
matchExpressions:
- key: app
operator: In
values:
- web-demo-node
#要跟app=web-demo-node的POD运行在同一个节点上。
#范围:(topologyKey是关键字)对应词是对应节点上label的名字
#每个节点上都有一个label的名字:kubernetes.io/hostname,每个节点的主机名。
topologyKey: kubernetes.io/hostname
#最好是怎么样,而不是必须怎么样,所以这里不存在上述的或和并且的关系逻辑。
#如果A节点资源满了,那么即使A满足此条件,可能会被调度到B节点。
preferredDuringSchedulingIgnoredDuringExecution:
#在多个之间的占比
#在这里需要的是一个权重,而不是一个强一致的逻辑关系。
- weight: 100
podAffinityTerm:
labelSelector:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
matchExpressions:
- key: app
operator: In
values:
- web-demo-node2
topologyKey: kubernetes.io/hostname
[root@node-1 5-scheduler]# kubectl apply -f web-dev-pod.yaml
deployment.apps/web-demo-pod created
[root@node-1 5-scheduler]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-demo-node-556cf67d5c-fblc4 1/1 Running 0 6m20s 10.200.139.105 node-3 <none> <none>
web-demo-pod-65f54fd8d6-klzz2 1/1 Running 0 2s 10.200.139.109 node-3 <none> <none>
#核实其他node的label是否匹配
[root@node-1 ~]# kubectl get pods -n dev web-demo-node-556cf67d5c-fblc4 -o yaml
labels:
app: web-demo-node
[root@node-1 5-scheduler]# kubectl delete -f web-dev-pod.yaml
deployment.apps "web-demo-pod" deleted
POD非亲和性调度(不同服务不同节点)
#不要跟app=web-demo-node的POD运行在同一个节点上。
[root@node-1 5-scheduler]# cat web-dev-pod2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-demo-pod
namespace: dev
spec:
selector:
matchLabels:
app: web-demo-pod
replicas: 1
template:
metadata:
labels:
app: web-demo-pod
spec:
containers:
- name: web-demo-pod
image: hub.mooc.com/kubernetes/web:v1
ports:
- containerPort: 8080
#亲和性
affinity:
#POD的亲和性:一般用于在一定的区域内,一个POD跟其他POD的亲和关系,比如是否运行在一起。
#podAffinity亲和性调度可以和podAntiAffinity非亲和性调度一起配置,意思是相反的。
podAntiAffinity:
#必须满足下述的配置才能被调度
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
matchExpressions:
- key: app
operator: In
values:
- web-demo-node
#不要跟app=web-demo-node的POD运行在同一个节点上。
#范围:(topologyKey是关键字)对应词是对应节点上label的名字
#每个节点上都有一个label的名字:kubernetes.io/hostname,每个节点的主机名。
topologyKey: kubernetes.io/hostname
#最好是怎么样,而不是必须怎么样,所以这里不存在上述的或和并且的关系逻辑。
#如果A节点资源满了,那么即使A满足此条件,可能会被调度到B节点。
preferredDuringSchedulingIgnoredDuringExecution:
#在多个之间的占比
#在这里需要的是一个权重,而不是一个强一致的逻辑关系。
- weight: 100
podAffinityTerm:
labelSelector:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
matchExpressions:
- key: app
operator: In
values:
- web-demo-node2
topologyKey: kubernetes.io/hostname
[root@node-1 5-scheduler]# kubectl apply -f web-dev-pod2.yaml
deployment.apps/web-demo-pod created
[root@node-1 5-scheduler]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-demo-node-556cf67d5c-fblc4 1/1 Running 0 24m 10.200.139.105 node-3 <none> <none>
web-demo-pod-78864f5bb6-tqrvd 1/1 Running 0 9s 10.200.247.43 node-2 <none> <none>
#核实其他node的label是否匹配
[root@node-1 ~]# kubectl get pods -n dev web-demo-node-556cf67d5c-fblc4 -o yaml
labels:
app: web-demo-node
[root@node-1 5-scheduler]# kubectl delete -f web-dev-pod2.yaml
deployment.apps "web-demo-pod" deleted
POD非亲和性调度(相同服务不同节点)
#不想跟自己运行在同一台机器上,副本改成2,value为自己的名字:web-demo-pod。
#当同一个服务不想跑在同一台机器上的设置。
[root@node-1 5-scheduler]# cat web-dev-pod3.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-demo-pod
namespace: dev
spec:
selector:
matchLabels:
app: web-demo-pod
#不想跟自己运行在同一台机器上,副本改成2,value为自己的名字:web-demo-pod。
replicas: 2
template:
metadata:
labels:
app: web-demo-pod
spec:
containers:
- name: web-demo-pod
image: hub.mooc.com/kubernetes/web:v1
ports:
- containerPort: 8080
#亲和性
affinity:
#POD的亲和性:一般用于在一定的区域内,一个POD跟其他POD的亲和关系,比如是否运行在一起。
#podAffinity亲和性调度可以和podAntiAffinity非亲和性调度一起配置,意思是相反的。
podAntiAffinity:
#必须满足下述的配置才能被调度
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
matchExpressions:
- key: app
operator: In
values:
#不想跟自己运行在同一台机器上,副本改成2,value为自己的名字:web-demo-pod。
- web-demo-pod
#要跟app=web-demo-pod的POD运行在同一个节点上。
#范围:(topologyKey是关键字)对应词是对应节点上label的名字
#每个节点上都有一个label的名字:kubernetes.io/hostname,每个节点的主机名。
topologyKey: kubernetes.io/hostname
#最好是怎么样,而不是必须怎么样,所以这里不存在上述的或和并且的关系逻辑。
#如果A节点资源满了,那么即使A满足此条件,可能会被调度到B节点。
preferredDuringSchedulingIgnoredDuringExecution:
#在多个之间的占比
#在这里需要的是一个权重,而不是一个强一致的逻辑关系。
- weight: 100
podAffinityTerm:
labelSelector:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
matchExpressions:
- key: app
operator: In
values:
- web-demo-node2
topologyKey: kubernetes.io/hostname
[root@node-1 5-scheduler]# kubectl apply -f web-dev-pod3.yaml
deployment.apps/web-demo-pod created
[root@node-1 5-scheduler]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-demo-pod-6fffff7675-8rx8d 1/1 Running 0 14s 10.200.139.112 node-3 <none> <none>
web-demo-pod-6fffff7675-vnw6q 1/1 Running 0 14s 10.200.247.48 node-2 <none> <none>
#这里双节点,测试完最好删掉,如果和其他案例有双节点条件冲突,那么可能不能运行新的服务。
[root@node-1 5-scheduler]# kubectl delete -f web-dev-pod3.yaml
deployment.apps "web-demo-pod" deleted
POD亲和性调度(相同服务尽量相同节点)
#把同一个服务尽量跑在同一台机器上的设置。
[root@node-1 5-scheduler]# cat web-dev-pod4.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-demo-pod
namespace: dev
spec:
selector:
matchLabels:
app: web-demo-pod
#跟自己尽量运行在同一台机器上,副本改成2,value为自己的名字:web-demo-pod。
replicas: 2
template:
metadata:
labels:
app: web-demo-pod
spec:
containers:
- name: web-demo-pod
image: hub.mooc.com/kubernetes/web:v1
ports:
- containerPort: 8080
#亲和性
affinity:
#POD的亲和性:一般用于在一定的区域内,一个POD跟其他POD的亲和关系,比如是否运行在一起。
#podAffinity亲和性调度可以和podAntiAffinity非亲和性调度一起配置,意思是相反的。
podAffinity:
#必须满足下述的配置才能被调度
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
matchExpressions:
- key: app
operator: In
values:
#跟自己尽量运行在同一台机器上,副本改成2,value为自己的名字:web-demo-pod。
- web-demo-pod
#要跟app=web-demo-pod的POD运行在同一个节点上。
#范围:(topologyKey是关键字)对应词是对应节点上label的名字
#每个节点上都有一个label的名字:kubernetes.io/hostname,每个节点的主机名。
topologyKey: kubernetes.io/hostname
#最好是怎么样,而不是必须怎么样,所以这里不存在上述的或和并且的关系逻辑。
#如果A节点资源满了,那么即使A满足此条件,可能会被调度到B节点。
preferredDuringSchedulingIgnoredDuringExecution:
#在多个之间的占比
#在这里需要的是一个权重,而不是一个强一致的逻辑关系。
- weight: 100
podAffinityTerm:
labelSelector:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
matchExpressions:
- key: app
operator: In
values:
- web-demo-node2
topologyKey: kubernetes.io/hostname
[root@node-1 5-scheduler]# kubectl apply -f web-dev-pod4.yaml
deployment.apps/web-demo-pod created
[root@node-1 5-scheduler]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-demo-pod-68b784c84c-nczq8 1/1 Running 0 5s 10.200.247.47 node-2 <none> <none>
web-demo-pod-68b784c84c-tqdkf 1/1 Running 0 5s 10.200.247.49 node-2 <none> <none>
#这里双节点,测试完最好删掉,如果和其他案例有双节点条件冲突,那么可能不能运行新的服务。
[root@node-1 5-scheduler]# kubectl delete -f web-dev-pod4.yaml
deployment.apps "web-demo-pod" deleted
污点
和nodeAffinity相反,让node去拒绝POD的运行。可以在node上设置一个或多个污点,来拒绝运行在此node上,除非某些POD明确声明了能够容忍这些污点,否则不可能运行在此node上的。
场景1:单独节点给某个类型和某几个应用专门使用的,其他POD在调度时是不可能调度上来的,只有特殊的POD会调度上去。
场景2:机器有某些特殊的硬件设备,比如GPU、SSD,具有这些特殊设备的机器特别少,不想给一般的POD去使用,就可以给此node打上污点,给需要的POD配置污点容忍,就可以实现这个需求。
污点要达到的效果,效果有几种:
(1)NoSchedule(调度器不会把POD调度到这个节点上)。
(2)PreferNoSchedule(最好不要把POD调度到这个节点上)
(3)NoExecute(最严格的,除了不调度之外,如果这个POD已经运行在这个节点上了,没有设置容忍时间的话,那么立刻就会被驱逐掉。)
#案例:NoSchedule
#设置preference中的disktype:In:ssd。
[root@node-1 5-scheduler]# cat web-dev-node2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-demo-node
namespace: dev
spec:
selector:
matchLabels:
app: web-demo-node
replicas: 1
template:
metadata:
labels:
app: web-demo-node
spec:
containers:
- name: web-demo-node
image: hub.mooc.com/kubernetes/web:v1
ports:
- containerPort: 8080
#亲和性
affinity:
#POD跟节点的亲和性的关系
#节点的亲和性
nodeAffinity:
#必须满足下述的配置才能被调度
requiredDuringSchedulingIgnoredDuringExecution:
#节点的选择策略。数组形式。
#每个nodeSelectorTerms之间是或的关系。满足各种组合的需求。
nodeSelectorTerms:
#每个元素可以匹配一个matchExpressions表达式
#每个matchExpressions之间是并且的关系
#匹配label的方式
- matchExpressions:
#匹配节点的名字
- key: beta.kubernetes.io/arch
#操作:In
operator: In
values:
#架构是amd64的
#POD需要运行在CPU为amd64架构的机器上。这里的机器满足。
- amd64
#最好是怎么样,而不是必须怎么样,所以这里不存在上述的或和并且的关系逻辑。
#如果A节点资源满了,那么即使A满足此条件,可能会被调度到B节点。
preferredDuringSchedulingIgnoredDuringExecution:
#在多个之间的占比
#在这里需要的是一个权重,而不是一个强一致的逻辑关系。
- weight: 1
preference:
#匹配label的方式
matchExpressions:
- key: disktype
operator: In
values:
- ssd
[root@node-1 5-scheduler]# kubectl get nodes --show-labels
#设置node-2节点污点NoSchedule
[root@node-1 5-scheduler]# kubectl taint nodes node-2 gpu=true:NoSchedule
node/node-2 tainted
[root@node-1 5-scheduler]# kubectl apply -f web-dev-node2.yaml
deployment.apps/web-demo-node created
#这运行到了node-3上
[root@node-1 5-scheduler]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-demo-node-787d5d6b4-68fpr 1/1 Running 0 4m31s 10.200.139.110 node-3 <none> <none>
[root@node-1 5-scheduler]# kubectl delete -f web-dev-node2.yaml
deployment.apps "web-demo-node" deleted
污点容忍
#在上一节”污点”中node-2节点设置了污点
#设置node-2节点污点NoSchedule
[root@node-1 5-scheduler]# kubectl taint nodes node-2 gpu=true:NoSchedule
node/node-2 tainted
#单/多节点测试
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-demo-taint
namespace: dev
spec:
selector:
matchLabels:
app: web-demo-taint
#配置1或N
replicas: 1
template:
metadata:
labels:
app: web-demo-taint
spec:
containers:
- name: web-demo-taint
image: hub.mooc.com/kubernetes/web:v1
ports:
- containerPort: 8080
#tolerations污点容忍
#运行在设置污点的机器。但是容忍并不一定是不能运行在设置污点的机器或其他未设置污点的机器上。
tolerations:
#打污点的key
- key: "gpu"
#operator有几种值。Exists:如果KEY存在就生效,跟值无关系。Equal:相等的情况。
operator: "Equal"
value: "true"
#一定要配置,要跟打污点的值对应上。
effect: "NoSchedule"
[root@node-1 5-scheduler]# kubectl apply -f web-dev-taint.yaml
deployment.apps/web-demo-taint created
[root@node-1 5-scheduler]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-demo-taint-548b448ccf-cs5n7 1/1 Running 0 2s 10.200.139.117 node-3 <none> <none>
web-demo-taint-548b448ccf-zd48n 1/1 Running 0 2s 10.200.139.118 node-3 <none> <none>
[root@node-1 5-scheduler]# kubectl delete -f web-dev-taint.yaml
deployment.apps "web-demo-taint" deleted
标题:Kubernetes(十)服务调度与编排(10.2/3)Scheduler--玩转pod调度(上/下)
作者:yazong
地址:https://blog.llyweb.com/articles/2022/11/22/1669064083169.html