ibcadmin 发表于 2019-10-22 09:05:00

生产环境中的kubernetes 优先级与抢占

<p>kubernetes 中的抢占功能是调理器比较紧张的feature,但是真正使用起来还是比较伤害,否则很轻易把低优先级的pod给无辜kill。为了进步GPU集群的资源使用率,决定勇于实行一番该featrue。固然使用之前还是得阅读一下相关的代码做到心里有数,出了问题也方便定位修复。</p>
<h2 id="根本原理">根本原理</h2>
<p>优先级与抢占是为了确保一个高优先级的pod在调理失败后,可以通过"挤走" 低优先级的pod,腾出空间后包管它可以调理成功。 我们起首必要在集群中声明<code>PriorityClass</code>来界说优先品级数值和抢占计谋,</p>
<code>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."</code>
<p>如上所示界说了两个PriorityClass对象。然后就可以在pod中声明使用它了:</p>
<code>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</code>
<p>这个 Pod 通过 priorityClassName 字段。声明了要使用名叫 high-priority 的 PriorityClass。当这个 Pod 被提交给 Kubernetes 之后,Kubernetes 的 Priority AdmissionController 就会自动将这个 Pod 的spec.priority 字段设置为10000。<br />
如下:</p>
<code>preemptionPolicy: Never
priority: 10000
priorityClassName: high</code>
<p>Pod创建好之后,调理器就会根据创建的priority进行调理的决议,起首会在等待队列中优先调理,如果调理失败就会进行抢占: 依次遍历全部的node找出最得当的node,将该nodename添补在spec.nominatedNodeName字段上,然后等待被抢占的pod全都退出后再次实行调理到该node之上。详细的逻辑请自行阅读相关代码,此处不在赘述。</p>
<h2 id="生产情况使用方式">生产情况使用方式</h2>
<ul>
<li>v1.14版本的kubernetes该feature已经GA,默认开启,但此时我们往往没有做好准备,如果直接给pod设置优先级会导致很多意料之外的抢占,造成故障。 (拜见How a Production Outage Was Caused Using Kubernetes Pod Priorities)。所以建议在初次使用的时间还是先显式关闭抢占,只设置优先级,等集群中全部的pod都有了各自的优先级之后再开启,此时全部的抢占都是可预期的。可以通过kube-scheduler 设置文件中的<code>disablePreemption: true</code>进行关闭</li>
<li>调理器是根据优先级pod.spec.priority数值来决定优先级的,而用户是通过指定pod.sepc.priorityclass的名字来为pod选择优先级的,此时就必要Priority AdmissionController根据priorityclass name为pod自动转换并设置对应的priority数值。我们必要确保该admissionController开启,如果你的kube-apiserver中还是通过<code>--admission-control</code> flag来指定admissionoController的话必要手动添加<code>Priority</code> admissonController,如果是通过<code>--enable-admission-plugins</code>来指定的话,无需操纵,该admissionController默认开启。</li>
<li>按照集群规划创建对应的<code>PriorityClass</code>及其对应的抢占计谋,现在支持两种计谋: Never, PreemptLowerPriority。 Never可以指定不抢占其他pod, 纵然该pod优先级特别高,这对于一些离线任务较为友爱。 非抢占调理在v1.15中为alpha, 必要通过<code>--feature-gates=NonPreemptingPriority=true</code> 进行开启。</li>
<li>在创建好了PriorityClass之后,必要防止高优先级的pod过分占用太多资源,使用resourceQuota机制来限定其使用量,克制低优先级的pod总是被高优先级的pod压制,造成资源饥饿。resoueceQuote可以通过指定scope为<code>PriorityClass</code>来限定某个优先级能使用的资源量:</li>
</ul>
<code>apiVersion: v1
kind: ResourceQuota
metadata:
name: high-priority
spec:
hard:
    pods: "10"
scopeSelector:
    matchExpressions:
    - operator : In
      scopeName: PriorityClass
      values: ["high"]</code>
<p>如上即为限定高优先级的pod最多能创建10个。operator指定了作用的对象,<code>operator: In</code>可以显式指定作用于的哪些priorityClass,<code>operator: Exists</code>则指定作用于该namespace下的全部priorityClass。</p>
<ul>
<li>偶然候我们想要只有priorityClass对应的resourceQuota存在之后才气创建pod,确保全部的priorityClass的pod资源都是受控的。 如果谁人namespacew没有该resourceQuota则拒绝该pod的创建,该操纵可以通过指定<code>--admission-control-config-file</code>文件来设置,内容如下:</li>
</ul>
<code>apiVersion: apiserver.k8s.io/v1alpha1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
    apiVersion: resourcequota.admission.k8s.io/v1beta1
    kind: Configuration
    limitedResources:
    - resource: pods
      matchScopes:
      - scopeName: PriorityClass
      operator: In
      values: ["high"]</code>
<p>该设置界说了: "high"优先级的pod只能在指定的namespaces下创建,该namespaces有作用于"high"优先级的resouceQuota,上面第四步中的resouceQuota即可满足要求。<br />
scopeName界说了作用的对象为priorityClass, operator指定了作用的范围,可以是In操纵符,指定某几个value, 也可以是Exits操纵符,指定全部的PriorityClass必须有对应的quota存在, 否则该namespace就无法创建该优先级的pod,这些操纵符与上面resouceQuota中界说的一一对应。通过这样就限定了一些优先级只能在有资源束缚的namespace下创建。</p>
<ul>
<li>如果没有显式指定优先级,则默认的优先级值为0,必要联合业务规划决定是否有须要调解默认优先级。</li>
<li>对于一些daemonset必要显式设置较高的优先级来防止被抢占,在部署一个新的daemonset的时间必要思量是否会造成大规模pod的抢占。</li>
<li>等到全部的优先级设置完毕之后就可以开启抢占功能了,此时集群中全部pending 的高优先级pod就会瞬间抢占,还是必要额外警惕,确保集群中高优先级的pod不会导致低优先级的pod大规模被kill,如果我们提前设置了对应的resource quota值,则会有肯定的资源束缚。</li>
<li>优先级和抢占对于资源的精致化运营考验很大,对于resource quota的设置必要非常精致,必要思量两个维度来设置: namespace层面和priority层面,我们既渴望限定namespace使用的资源,有渴望某个priority使用的资源,防止低优先级的pod资源饥饿。 可以在初期只思量namespace层面的限定,priority层面通过上层业务来包管,比方创建任务的时间包管集群中高优先级的资源使用量不高出50%等。</li>
</ul>
<h2 id="其他思考">其他思考</h2>
<p>笔者的线上情况中, 有些再跑的模型练习任务业务对于自动failove实现不是很好,如果中途被抢占了只能重新开始盘算,必要占用额外的GPU资源,这种工作类型不允许被抢占,但是如果把他设置为高优先级又不太合适,由于它确实不是最高的优先级,优先级最高的还是在线业务,不能让它抢占在线业务。 它属于中心优先级,可以抢占低优先级的pod。 经过探索发现现在kubernetes并不支持该中类型,当前支持的抢占计谋为: Never, PreemptLowerPriority都无法满足需求。所以在此底子上开发了<code>NonPreemptible</code>类型的抢占计谋,该优先级的pod是不允许被其他人抢占的,调理还是按照优先级在队列里列队,但是一旦调理上去就无法被抢占。<br />
这种抢占计盘算显"霸道",所以必要审慎使用,设置resouceQuota,而且只能由特定的任务使用。 而且为了不影响deamonset等优先级最高的任务,允许被某个指定Priority数值之上的pod抢占。而且随着业务的发展,这部分逻辑必要渐渐去掉,之全部存在这部分逻辑是由于pod不能被中断,不能被抢占,所以还是必要使这些任务支持重启与挂起,详细来说就是: pod挂载长途磁盘并自动checkpoint,重启之后从以前的规复点继续实行。等这些业务改造完成之后,渐渐去掉这种工作抢占计谋</p>
<h2 id="reference">reference</h2>
<p>Pod Priority and Preemption<br />
Priority in ResourceQuota<br />
Allow PriorityClasses To Be Non-Preempting</p><br><br/><br/><br/><br/><br/>来源:<a href="https://www.cnblogs.com/gaorong/p/11318328.html" target="_blank">https://www.cnblogs.com/gaorong/p/11318328.html</a>
页: [1]
查看完整版本: 生产环境中的kubernetes 优先级与抢占