生产环境中的kubernetes 优先级与抢占
kubernetes 中的抢占功能是调度器比较重要的feature,但是真正使用起来还是比较危险,否则很容易把低优先级的pod给无辜kill。为了提高GPU集群的资源利用率,决定勇于尝试一番该featrue。当然使用之前还是得阅读一下相关的代码做到心里有数,出了问题也方便定位修复。
基本原理
优先级与抢占是为了确保一个高优先级的pod在调度失败后,可以通过"挤走" 低优先级的pod,腾出空间后保证它可以调度成功。 我们首先需要在集群中声明PriorityClass
来定义优先等级数值和抢占策略,
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high value: 10000 preemptionPolicy: Never globalDefault: false description: "This priority class should be used for high priority service pods." --- apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low value: -999 globalDefault: false description: "This priority class should be used for log priority service pods."
如上所示定义了两个PriorityClass对象。然后就可以在pod中声明使用它了:
apiVersion: apps/v1 kind: Deployment metadata: labels: run: nginx name: high-nginx spec: replicas: 1 selector: matchLabels: run: nginx template: metadata: labels: run: nginx spec: containers: - image: nginx imagePullPolicy: Always name: nginx resources: limits: cpu: "500m" priorityClassName: high
这个 Pod 通过 priorityClassName 字段。声明了要使用名叫 high-priority 的 PriorityClass。当这个 Pod 被提交给 Kubernetes 之后,Kubernetes 的 Priority AdmissionController 就会自动将这个 Pod 的spec.priority 字段设置为10000。
如下:
preemptionPolicy: Never priority: 10000 priorityClassName: high
Pod创建好之后,调度器就会根据创建的priority进行调度的决策,首先会在等待队列中优先调度,如果调度失败就会进行抢占: 依次遍历所有的node找出最适合的node,将该nodename填充在spec.nominatedNodeName字段上,然后等待被抢占的pod全都退出后再次尝试调度到该node之上。具体的逻辑请自行阅读相关代码,此处不在赘述。
生产环境使用方式
- v1.14版本的kubernetes该feature已经GA,默认开启,但此时我们往往没有做好准备,如果直接给pod设置优先级会导致很多意料之外的抢占,造成故障。 (参见How a Production Outage Was Caused Using Kubernetes Pod Priorities)。所以建议在初次使用的时候还是先显式关闭抢占,只设置优先级,等集群中所有的pod都有了各自的优先级之后再开启,此时所有的抢占都是可预期的。可以通过kube-scheduler 配置文件中的
disablePreemption: true
进行关闭 - 调度器是根据优先级pod.spec.priority数值来决定优先级的,而用户是通过指定pod.sepc.priorityclass的名字来为pod选择优先级的,此时就需要Priority AdmissionController根据priorityclass name为pod自动转换并设置对应的priority数值。我们需要确保该admissionController开启,如果你的kube-apiserver中还是通过
--admission-control
flag来指定admissionoController的话需要手动添加Priority
admissonController,如果是通过--enable-admission-plugins
来指定的话,无需操作,该admissionController默认开启。 - 按照集群规划创建对应的