目录
一、什么是污点和容忍度
1、官方解释:
2、自我理解:
3、污点
1、污点的组成:
2、污点的三种策略:
1、PreferNoSchedule
2、NoExecute
3、NoSchedule
4、容忍
1、Toleration基本用法
2、用法:
3、注意:
二、使用演示
三、Pod优先级调度
1、调度策略:
1、驱逐(Eviction)
2、抢占(Preemtion)
2、创建权重
3、yaml文件定义
4、使用优先级
如果一个节点被标记为有污点,那么意味着不允许pod调度到该节点,除非pod也被标记为可以容忍污点的节点。
effect:用来定义节点污点对pod对象的排斥效果
表示尽量不调度到污点节点上去。
当pod能够容忍这个节点污点,会被调度到节点;当pod不能容忍节点污点,将会被驱逐。
NoExecute对正在运行的pod的影响:
1、没有设置 Toleration 的 Pod 会被立刻驱逐
2、配置了对应 Toleration 的 pod,如果没有为 tolerationSeconds 赋值,则会一直留在这一节点中
3、配置了对应 Toleration 的 pod 且指定了 tolerationSeconds 值,则会在指定时间后驱逐
不允许调度,已经调度的不受影响
给node1添加污点
[root@k8s-master-1 Taint]# kubectl taint node k8s-node-1 key1=value1:NoSchedule
node/k8s-node-1 tainted
查看是否添加成功
[root@k8s-master-1 Taint]# kubectl describe nodes k8s-node-1 | grep Taints
Taints: key1=value1:NoSchedule
删除污点(和标签相同)
kubectl taint nodes node1 key1=value1:NoSchedule-
设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,Pod将在一定程度上不会被调度到Node上。 但我们可以在Pod上设置容忍(Toleration),意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上。
一个toleration和一个taint相"匹配"是指它们有一样的key和effect
另外还有如下两个特例:
tolerations:
- key: key1
value: value1
operator: "Equal"
effect: "NoSchedule"
- - 或者 - -
tolerations:
- key: key1
operator: "Exists"
effect: "NoSchedule"
以上两个容忍,使用任意一个容忍的pod都能调度到node1上。
- - 或者- - 表示:如果一个toleration的effect为空,则key值与之相同的相匹配taint的effect可以是任意值
tolerations:
- key: key1
operator: "Exists"
yaml文件如下:在此基础上修改
apiVersion: apps/v1
kind: Deployment
metadata:
name: taint-test
spec:
selector:
matchLabels:
app: nginx
env: prod
replicas: 2
template:
metadata:
labels:
app: nginx
env: prod
spec:
containers:
- image: nginx:1.17.1
name: nginx
1、node节点没有任何的污点,创建有两个副本的deploy,会指定到两个节点上
[root@k8s-master-1 Taint]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
taint-test-5579c4b477-2c2r6 1/1 Running 0 7s 10.244.0.13 k8s-node-1
taint-test-5579c4b477-v6rgx 1/1 Running 0 7s 10.244.1.242 k8s-node-2
删除deploy,然后给node1添加污点,在创建有容忍的deploy
tolerations:
- key: key1
value: value1
operator: "Equal"
effect: "NoSchedule"
2、node1添加污点
[root@k8s-master-1 Taint]# kubectl taint nodes k8s-node-1 key1=value1:NoSchedule
node/k8s-node-1 tainted
[root@k8s-master-1 Taint]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
taint-test-5579c4b477-hklqg 1/1 Running 0 5s 10.244.1.243 k8s-node-2
taint-test-5579c4b477-xsdfd 1/1 Running 0 5s 10.244.0.14 k8s-node-1
可以看到也被调度到了两个节点上,因为node1上添加了污点,这个pod能容忍他的污点,node2上没有添加污点,所以也可以调度过去。
3、给node2 添加NoExecute 污点,此时node2上的pod就会被驱逐,因为创建了2个副本的deploy,为了保证副本数,会在node1 上新创建一个pod
[root@k8s-master-1 Taint]# kubectl taint nodes k8s-node-2 key1=value1:NoExecute
node/k8s-node-2 tainted
[root@k8s-master-1 Taint]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
taint-test-5579c4b477-2kqq8 1/1 Running 0 20s 10.244.0.15 k8s-node-1
taint-test-5579c4b477-xsdfd 1/1 Running 0 14m 10.244.0.14 k8s-node-1
4、给node1 添加NoExecute 污点和NoSchedule污点,并且设置tolerationSeconds值为30,让其在30秒之后被驱逐,,此时pod在30秒之后会被驱逐,被调度到node2上。
tolerations:
- key: key1
value: value1
operator: "Equal"
effect: "NoExecute"
tolerationSeconds: 30
[root@k8s-master-1 Taint]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
taint-test-58b64c6989-2qxpq 1/1 Running 0 5s 10.244.1.43 k8s-node-2
taint-test-58b64c6989-5hts2 1/1 Running 0 47s 10.244.1.42 k8s-node-2
当集群资源不足时又有新的Pod创建请求,那么这个Pod会一直处于Pending状态,就算是这个Pod非常的重要,非部署不可,那也没办法,你只能删除一些Pod释放一些资源才能被调度成功。
Eviction 是kubelet进程的行为,当该Node上的资源不足时,kubelet就会执行驱逐动作,配合优先级,将优先级低的Pod驱逐,如果优先级都一样,那么实际使用的资源量超过申请量最大倍数的高耗能 Pod 会被首先驱逐。
Preemption 是 Scheduler 执行调度的行为,当有新的Pod创建,但是因为资源不够无法正常调度,调度器便会驱逐部分优先级较低的Pod来满足新Pod的需求。
权重是区分优先级的关键因素。
1、查看优先级 kubectl get PriorityClass
[root@k8s-master-1 diaodu]# kubectl get pc
NAME VALUE GLOBAL-DEFAULT AGE
system-cluster-critical 2000000000 false 60d
system-node-critical 2000001000 false 60d
2、通过yaml方式定义一个PriorityClass
[root@k8s-master-1 diaodu]# vim PriorityClass.yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass # PriorityClass不受命名空间约束
metadata:
name: app-priority
value: 100 # 优先级为100,数字越大,优先级越高,没有设置优先级的Pod默认优先级为0
globalDefault: false #globalDefault 给没有设置优先级的Pod使用,整个系统只能设置一个globalDefault=true的PriorityClass
description: " app test priority." #description 描述什么时候应该使用该优先级
3、创建优先级
[root@k8s-master-1 diaodu]# kubectl apply -f PriorityClass.yaml
priorityclass.scheduling.k8s.io/app-priority created
4、查看优先级
[root@k8s-master-1 diaodu]# kubectl get pc
NAME VALUE GLOBAL-DEFAULT AGE
app-priority 100 false 10s
system-cluster-critical 2000000000 false 60d
system-node-critical 2000001000 false 60d
结合前面讲到的亲和性调度与污点来模拟效果。给node02设置上一个污点,使得Pod不能调度进来,给node01运行一个带有标签env=pro的Pod,再创建一个新的Pod使用了优先级app-priority,并且通过反亲和性设置不能调度到带有标签env=pro的Pod所在Node,那么新Pod将没有节点可调度,但是由于它的优先级高,那么会不会丢车保帅,将node01上的Pod驱逐呢?下面来验证一下。
1、创建一个标签是ds=true的Pod,指定调度到node1上
[root@k8s-master-1 diaodu]# vim pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-test
labels:
ds: "true"
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent
nodeName: k8s-node-1
[root@k8s-master-1 diaodu]# kubectl apply -f pod-test.yaml
pod/pod-test created
[root@k8s-master-1 diaodu]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-test 1/1 Running 0 4s 10.244.0.85 k8s-node-1
2、给node02创建污点,模拟不可用
[root@k8s-master-1 diaodu]# kubectl taint node k8s-node-2 app=true:NoExecute
node/k8s-node-2 tainted
[root@k8s-master-1 diaodu]# kubectl describe node k8s-node-2 | grep Taints
Taints: app=true:NoExecute
3、创建带有优先级的Pod
[root@k8s-master-1 diaodu]# vim priority-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: priority-pod
labels:
env: pro
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: IfNotPresent # 本地有不拉取镜像
affinity:
podAntiAffinity: # 使用Pod反亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
- labelSelector:
matchExpressions:
- key: ds
operator: In
values:
- "true"
topologyKey: kubernetes.io/hostname
priorityClassName: app-priority
# 启动priority-pod并且立刻查看Pod详情,pod-test正在被驱逐
[root@k8s-master-1 diaodu]# kubectl apply -f priority-pod.yaml && kubectl get pod -owide
pod/priority-pod created
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-test 1/1 Terminating 0 18s 10.244.0.89 k8s-node-1
priority-pod 0/1 Pending 0 0s k8s-node-1
# 再次查看Pod详情,priority-pod运行成功,target-pod被驱逐
[root@k8s-master-1 diaodu]#kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
priority-pod 1/1 Running 0 4s 10.244.0.90 k8s-node-1
解释:第一步创建了一个app-priority的优先级策略,然后,创建了一个设置有ds=true标签的Pod,并将其调度到node1上,在给node2打了一个NoExecute
模拟不可用,然后在创建一个反亲和性的Pod,指定不让他调度到和带有ds=true标签的Pod所在的节点上,此时,kube-scheduler,就会把它调度到node2上,
但是node2上添加了NoExecute污点,此Pod又不容忍,所以就调度失败,但是此pod优先级较高,故而就会把node1上优先级底的删除,用来创建优先级较高的Pod.
注意事项:
优先级抢占的调度方式可能会导致调度陷入“死循环”状态。当Kubernetes集群配置了多个调度器(Scheduler)时,这一行为可能就会发生。
高优先级Pod抢占节点并驱逐低优先级的Pod,这个问题对于普通的服务型的Pod来说问题不大,但对于执行批处理任务的Pod来说就可能是个灾难,当一个高 优先级的批处理任务的Pod创建后,正在执行批处理任务的某个低优先级的Pod可 能因为资源不足而被驱逐,从而导致对应的批处理任务被搁置。
为了避免这个问题发生,PriorityClass增加了一个新的属性一preemptionPolicy,当它的值为 preemptionLowerPriorty(默认)时,就执行抢占功能,当它的值被设置为Never 时,就默认不抢占资源,而是静静地排队,等待自己的调度机会。
[root@k8s-master-1 diaodu]# kubectl get pc app-priority -oyaml
apiVersion: scheduling.k8s.io/v1
description: ' app test priority.'
kind: PriorityClass
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"scheduling.k8s.io/v1","description":" app test priority.","globalDefault":false,"kind":"PriorityClass","metadata":{"annotations":{},"name":"app-priority"},"value":100}
creationTimestamp: "2023-06-19T03:02:55Z"
generation: 1
managedFields:
- apiVersion: scheduling.k8s.io/v1
fieldsType: FieldsV1
fieldsV1:
f:description: {}
f:metadata:
f:annotations:
.: {}
f:kubectl.kubernetes.io/last-applied-configuration: {}
f:preemptionPolicy: {}
f:value: {}
manager: kubectl-client-side-apply
operation: Update
time: "2023-06-19T03:02:55Z"
name: app-priority
resourceVersion: "1938189"
selfLink: /apis/scheduling.k8s.io/v1/priorityclasses/app-priority
uid: 2f925930-40c4-4bc1-a497-0d1748d14751
preemptionPolicy: PreemptLowerPriority
value: 100