背景

K8S 默认的 POD 的创建是随机的,即假如当前只有 8C16G 的资源,而当前有两个需要 6C8G 的 POD 需要创建,那么到底是哪个 POD 抢到了资源完全随机。因此,在比赛平台使用过程中,时不时有打榜人员反映提交了两个策略,后提交的策略已经结束了测试,但先提交的策略还没开始测试。后来,老板就让运维同学去解决这个问题,解决问题的方案是采用 K8S 的 POD 优先级机制,参考 Pod 优先级和抢占 | Kubernetes 文档。

配置 Pod 优先级

Pod 可以配置优先级,优先级高的 Pod 享有优先使用资源的权限。

在 v1.8 版本中,K8S 首次引入 Pod 优先级和抢占功能,并在 v1.14 达到稳定版本。为了使用优先级和抢占,需要两步,创建 PriorityClass 对象和为 Pod 配置 priorityClassName。

首先是创建 PriorityClass 对象。

PriorityClass 是一个无命名空间对象,它定义了从优先级类名称到优先级整数值的映射。名称在 PriorityClass 对象元数据的  name  字段中指定。值在必填的  value  字段中指定。值越大,优先级越高。 PriorityClass 对象的名称必须是有效的 DNS 子域名,并且它不能以  system-  为前缀。

PriorityClass 对象可以设置任何小于或等于 10 亿的 32 位整数值。 这意味着 PriorityClass 对象的值范围是从 -2,147,483,648 到 1,000,000,000(含)。 保留更大的数字,用于表示关键系统 Pod 的内置 PriorityClass。 集群管理员应该为这类映射分别创建独立的 PriorityClass 对象。

PriorityClass 还有两个可选字段:globalDefault  和  description。 globalDefault  字段表示这个 PriorityClass 的值应该用于没有  priorityClassName  的 Pod。系统中只能存在一个  globalDefault  设置为 true 的 PriorityClass。如果不存在设置了  globalDefault  的 PriorityClass,则没有  priorityClassName  的 Pod 的优先级为零。

description  字段是一个任意字符串。它用来告诉集群用户何时应该使用此 PriorityClass。

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "此优先级类应仅用于 XYZ 服务 Pod。"

使用 PriorityClass 还有一些注意事项:

  • 在 K8S 中引入 PriorityClass 后,之前已经存在的 Pod 的优先级等效于零.
  • 添加一个将  globalDefault  设置为  true  的 PriorityClass 不会改变现有 Pod 的优先级,仅仅适用于之后创建的 Pod。
  • 删除了某个 PriorityClass 对象后,则使用被删除的 PriorityClass 名称的现有 Pod 保持不变,但是不能再创建使用已删除的 PriorityClass 名称的 Pod。

其次,为 Pod 配置 priorityClassName。

具体来说,在 spec 下添加 priorityClassName,并配置对应的 PriorityClass 对象中 metadata 中的 name。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
    - name: nginx
      image: nginx
      imagePullPolicy: IfNotPresent
  priorityClassName: high-priority

比赛平台的修改

首先,对 helm chart 模板进行修改。

添加 priorityclass.yaml 文件:

{{- if .Values.priorityclassname }}
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: "{{ .Values.priorityclassname }}"
value: {{ .Values.priorityclassvalue }}
globalDefault: false
preemptionPolicy: "Never"
description: "This is a priority class."
{{- end }}

修改 job.yaml 文件,添加 priorityclass 相关配置:

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "xxx.fullname" . }}
  labels:
    {{- include "xxx.labels" . | nindent 4 }}
    {{- with .Values.podLabels }}
    {{- toYaml . | nindent 4 }}
    {{- end }}
spec:
  template:
    metadata:
      labels:
        {{- include "xxx.labels" . | nindent 8 }}
        {{- with .Values.podLabels }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
    spec:
      {{- with .Values.priorityclassname }}
      priorityClassName: "{{ . }}"
      {{- end }}
      containers:
        ...

修改 values.yaml 文件,添加相关属性:

priorityclassname: ""
priorityclassvalue: "0"

其次,比赛平台方面,会对 values.yaml 中的 priorityclassnamepriorityclassvalue 进行赋值。

其中,priorityclassvalue10**9 - submit-idpriorityclassname 为基于优先级数值改造的字符串。

其他

Pod 优先级和抢占 | Kubernetes 文档中的一些知识:

  • 如果一个 Pod 无法被调度,调度程序会尝试抢占(驱逐)较低优先级的 Pod,以使悬决 Pod 可以被调度。

Backlinks:

LIST FROM [[]]