在实际应用中,我们往往需要提高Kubernetes集群的资源利用率,即允许集群中所有负载所需的资源总量超过集群所提供的资源量,这个时候,当资源不足时,系统可以选择释放一些不重要的负载,保障最重要的负载能够运行,这就是我们今天要学习的优先级抢占调度策略。
要使用优先级抢占,需要做以下两件事:
-
定义PriorityClass;
-
在Pod配置中声明PriorityClassName并设置为上面所定义的PriorityClass。
1、定义PriorityClass
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: priority-class-demo value: 100000 globalDefault: false description: "This is a demo priority class."
这里我们需要注意,PriorityClass不属于任何命名空间,在上面这个例子中,我们定义了一个叫做priority-cass-demo的PrioriryClass,其优先级为100000,这个值越大,优先级越高,而超出10亿的值,其实是被Kubernetes保留下来分配给系统 Pod使用的。显然,这样做就是为了保证系统 Pod 不会被业务Pod抢占掉。我们设置globalDefault为false意味着,创建这个PriorityClass之后,所创建的Pod的默认优先级都是100000。我们创建此PriorityClass:
[root@kubevm1 workspace]# kubectl apply -f priority_class.yml
priorityclass.scheduling.k8s.io/priority-class-demo created
2、为Pod指定PriorityClass
我们修改nginx的deployment,在其中pod配置中增加PriorityClassName的设置:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 3 template: metadata: labels: app: nginx spec: priorityClassName: priority-class-demo containers: - name: nginx image: nginx:latest ports: - containerPort: 80
当 Pod 拥有了优先级之后,高优先级的 Pod 就可能会比低优先级的 Pod 提前出队,从而尽早完成调度过程。但如果由于集群负载较大,一个高优先级Pod调度失败时,调度器的抢占能力就会被触发。此时调度器就会试图从当前集群里寻找一个Node,使得当这个Node上的一个或者多个低优先级 Pod 被删除后,待调度的高优先级 Pod 就可以被调度到这个节点上。当然在实际操作过程中,如果恰好此时又出现了一个优先级更高的Pod,调度器就会优先调度这个更高优先级的Pod,然后在重新调度之前等待的次高优先级Pod。
大家可以看出来,这个抢占能力其实对于服务性Pod影响不大,但对于执行批处理任务的Pod来说是一个灾难,这有可能导致Job没有执行完任务就被驱逐,从而导致部分任务没有被执行完成。为了避免这个问题,PriorityClass增加了一个属性preemptionPolicy,这个属性默认值为PreemptLowerPriority,即抢占资源,当我们设置为Never时,则不会抢占资源,而是默默排队,等待被调度。
以上就是优先级抢占调度的执行过程,其实我们不难看出,这个调度策略有可能会增加系统复杂性,以及部署在集群上的业务系统的稳定性,所以如果出现资源不足的情况,最好优先考虑扩容方案,实在不行在考虑优先级抢占调度。