Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save gogeof/a24b6581c1c3c1f89f45a0f26d236e6b to your computer and use it in GitHub Desktop.

Select an option

Save gogeof/a24b6581c1c3c1f89f45a0f26d236e6b to your computer and use it in GitHub Desktop.

Revisions

  1. @ykfq ykfq created this gist Jan 29, 2019.
    327 changes: 327 additions & 0 deletions Kubernetes 调度优化--重平衡策略方案整理.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,327 @@
    <!DOCTYPE html>
    <html>

    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Kubernetes 调度优化--重平衡策略方案整理</title>
    <link rel="stylesheet" href="https://stackedit.io/style.css" />
    </head>

    <body class="stackedit">
    <div class="stackedit__left">
    <div class="stackedit__toc">
    <ul>
    <li>
    <ul>
    <li></li>
    <li><a href="#参考文档">参考文档</a></li>
    </ul>
    </li>
    </ul>

    </div>
    </div>
    <div class="stackedit__right">
    <div class="stackedit__html">
    <h3 id="背景简介">背景简介</h3>
    <p>什么是 Kubernetes 中的调度(Scheduling)?</p>
    <p>Kubernetes 中的调度,是将处于待定(Pending)的 pod 绑定到某个节点的过程,由 Kubernetes 中名为 kube-scheduler 的组件执行。</p>
    <p>调度器决定一个 pod 是否或在哪能否被调度,由调度器的可配置策略来指导,该策略包括一组规则,称为预判和优选。调度器的决定受到新 pod 第一次被调度时调度器在 Kubernetes 集群中所看到的资源情况的影响。</p>
    <p>k8s 自身提供了很多默认调度器和一些高级的调度策略(如 nodeAffinity 等),基本上可以满足大部分业务需求,对于特定业务,我们还可以自定义调度器(使用 python/shell/go 等实现)。</p>
    <p>由于 Kubernetes 集群是动态的且状态会发生变化,有时候我们希望将已经运行的 pod 调度到其他节点,原因如下:</p>
    <ul>
    <li>一些节点资源利用不足或使用过度;</li>
    <li>原始调度策略不再适用,比如节点添加或删除了污点或标签,不再满足 pod/node 亲和性要求;</li>
    <li>某些节点发生故障,其上 pod 被调度至其他节点;</li>
    <li>有新节点被添加到群集中;</li>
    <li>其它</li>
    </ul>
    <p>这些问题可能引起当前调度器分配 pod 不均衡,造成节点性能瓶颈掉线,最终引发集群雪崩。<br>
    我们大致从如下可能的点进行优化:</p>
    <ul>
    <li>limit:限制每个 pod 的资源分配,设置对 cpu/mem/disk 的 requests 和 limits;</li>
    <li>type:为每台节点指定类型或标签,可用于作为调度算法的参数。如 CPU/内存/IO 密集或高网络带宽使用等;</li>
    <li>重平衡:采取人为介入或定时任务的方式,根据多种维度去对当前的 pod 分布做重平衡;</li>
    <li>节点层面的优化,以及 pod 层面的优化;</li>
    </ul>
    <h3 id="调研文档">调研文档</h3>
    <ul>
    <li>
    <p>调度器性能调优<br>
    <a href="https://kubernetes.io/docs/concepts/configuration/scheduler-perf-tuning">https://kubernetes.io/docs/concepts/configuration/scheduler-perf-tuning</a></p>
    </li>
    <li>
    <p>优化预选阶段,丢弃不满足条件的 node<br>
    <a href="https://zhuanlan.zhihu.com/p/33470869">https://zhuanlan.zhihu.com/p/33470869</a><br>
    添加 alwaysCheckAllPredicates 开关,在预选阶段不符合条件的候选 Node,将不会参与后续条件的判断。</p>
    </li>
    <li>
    <p>k8s 调度详解(预选、优选过程)<br>
    <a href="http://dockone.io/article/2885">http://dockone.io/article/2885</a><br>
    nodeAffinity 具备 nodeSelector 的全部功能,所以未来 Kubernetes 会将 nodeSelector 废除</p>
    </li>
    <li>
    <p>活用 k8s 的默认调度器和一些高级调度策略,特殊业务可自定义调度器(python/shell/go)<br>
    <a href="http://www.rhca.me/?p=44">http://www.rhca.me/?p=44</a></p>
    </li>
    <li>
    <p>使用 Kubernetes 实现高级的调度技巧<br>
    <a href="https://thenewstack.io/implementing-advanced-scheduling-techniques-with-kubernetes">https://thenewstack.io/implementing-advanced-scheduling-techniques-with-kubernetes</a></p>
    </li>
    <li>
    <p>Kubernetes 是如何转变成一个通用调度器的<br>
    <a href="https://thenewstack.io/how-kubernetes-is-transforming-into-a-universal-scheduler">https://thenewstack.io/how-kubernetes-is-transforming-into-a-universal-scheduler</a></p>
    </li>
    <li>
    <p>根据 nodeSelector 或 Affinity 为 pod 指派 node<br>
    <a href="https://kubernetes.io/docs/concepts/configuration/assign-pod-node">https://kubernetes.io/docs/concepts/configuration/assign-pod-node</a></p>
    </li>
    <li>
    <p>Kubernetes最佳实践:资源需求和上限<br>
    <a href="https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-resource-requests-and-limits">https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-resource-requests-and-limits</a></p>
    </li>
    <li>
    <p>管理容器的计算资源<br>
    <a href="https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container">https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container</a></p>
    </li>
    <li>
    <p>为容器和容器组分配内存资源<br>
    <a href="https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource">https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource</a></p>
    </li>
    <li>
    <p>为 Namespace 配置默认的 CPU/内存 需求和上限<br>
    <a href="https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/cpu-default-namespace">https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/cpu-default-namespace</a><br>
    <a href="https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/memory-default-namespace">https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/memory-default-namespace</a></p>
    </li>
    <li>
    <p>为 Namespace 配置最小和最大 CPU/内存 限制<br>
    <a href="https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/cpu-constraint-namespace">https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/cpu-constraint-namespace</a><br>
    <a href="https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/memory-constraint-namespace">https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/memory-constraint-namespace</a></p>
    </li>
    <li>
    <p>为 Namespace 配置 内存和CPU 配额<br>
    <a href="https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace">https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace</a></p>
    </li>
    <li>
    <p>为 Namespace 配置 pod 限额(数量)<br>
    <a href="https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-pod-namespace">https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-pod-namespace</a></p>
    </li>
    </ul>
    <h3 id="应用实践">应用实践</h3>
    <p>调度器在调度过程中是如何计算哪些节点是满足<strong>可调度</strong>条件的呢?</p>
    <p>首先是判断节点是否有可分配的资源,如果有多台满足<strong>可调度</strong>条件,则调度至资源最优的节点上。</p>
    <p>Kubernetes 每个节点上的 kubelet 会监控该节点的 <strong>资源容量</strong> 和 <strong>可用资源</strong>,我们可以通过下面的命令查看:</p>
    <pre class=" language-bash"><code class="prism language-bash"><span class="token comment"># kubectl describe node "node01" | grep -A16 "Addresses:"</span>
    Addresses:
    InternalIP: 172.xx.xxx.xx
    Hostname: node01
    Capacity:
    cpu: 4
    ephemeral-storage: 41926416Ki
    hugepages-1Gi: 0
    hugepages-2Mi: 0
    memory: 8010544Ki
    pods: 110
    Allocatable:
    cpu: 3800m
    ephemeral-storage: 38639384922
    hugepages-1Gi: 0
    hugepages-2Mi: 0
    memory: 7408144Ki
    pods: 110
    </code></pre>
    <p>其中,<code>Capacity</code> 表示节点的资源容量,即机器的 CPU、内存、磁盘总量。本地磁盘被定义为 <strong>短暂存储</strong>,生命周期与 pod 一致。它与 <strong>持久存储</strong> 相对应。<br>
    <code>Allocatable</code> 则表示节点的可用资源,它是除开 <strong>系统预留</strong> 和 <strong>k8s 预留</strong> 以外的资源,是可以分配给集群创建 pod 使用的资源。</p>
    <p>每个 pod 或容器在创建时都应该声明自己所需资源的 <strong>请求值</strong>(requests) 和 <strong>上限值</strong>(limits),以便 kubelet 计算和统计整个节点资源的使用量和百分比。可以使用下面命令来查看当前节点的资源使用情况:</p>
    <pre class=" language-bash"><code class="prism language-bash"><span class="token comment"># kubectl describe node "node03" | sed '1,/Non-terminated Pods/d'</span>
    Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
    --------- ---- ------------ ---------- --------------- -------------
    default c3-registercenter-0 0 <span class="token punctuation">(</span>0%<span class="token punctuation">)</span> 0 <span class="token punctuation">(</span>0%<span class="token punctuation">)</span> 0 <span class="token punctuation">(</span>0%<span class="token punctuation">)</span> 0 <span class="token punctuation">(</span>0%<span class="token punctuation">)</span>
    kube-system calico-node-dvmgv 150m <span class="token punctuation">(</span>3%<span class="token punctuation">)</span> 300m <span class="token punctuation">(</span>7%<span class="token punctuation">)</span> 64M <span class="token punctuation">(</span>0%<span class="token punctuation">)</span> 500M <span class="token punctuation">(</span>6%<span class="token punctuation">)</span>
    kube-system kube-proxy-node03 150m <span class="token punctuation">(</span>3%<span class="token punctuation">)</span> 500m <span class="token punctuation">(</span>12%<span class="token punctuation">)</span> 64M <span class="token punctuation">(</span>0%<span class="token punctuation">)</span> 2G <span class="token punctuation">(</span>25%<span class="token punctuation">)</span>
    kube-system nginx-proxy-node03 25m <span class="token punctuation">(</span>0%<span class="token punctuation">)</span> 300m <span class="token punctuation">(</span>7%<span class="token punctuation">)</span> 32M <span class="token punctuation">(</span>0%<span class="token punctuation">)</span> 512M <span class="token punctuation">(</span>6%<span class="token punctuation">)</span>
    Allocated resources:
    <span class="token punctuation">(</span>Total limits may be over 100 percent, i.e., overcommitted.<span class="token punctuation">)</span>
    CPU Requests CPU Limits Memory Requests Memory Limits
    ------------ ---------- --------------- -------------
    325m <span class="token punctuation">(</span>8%<span class="token punctuation">)</span> 1100m <span class="token punctuation">(</span>28%<span class="token punctuation">)</span> 160M <span class="token punctuation">(</span>2%<span class="token punctuation">)</span> 3012M <span class="token punctuation">(</span>38%<span class="token punctuation">)</span>
    </code></pre>
    <p>这里可以看到每个 pod 有单独的资源使用统计,最后还有汇总。它是如何统计的呢?</p>
    <p>可以发现它只是简单的相加,这些统计是针对 <code>limits</code> 和 <code>requests</code> 的,并不是 pod 运行中实际使用的资源。也就是说如果一个 pod 没有设置 limits 和 requests(参考上面的 <code>0 (0%)</code> ),那么它就可以无限使用资源,还不会被纳入统计,这就使得统计结果不准确,可能节点已经超负荷运行了,但 Sheduler 还认为它有可用资源,直至节点被拖死,集群发生雪崩。<br>
    因此,我们应该采取一些合理的手段来避免这种情况:</p>
    <ul>
    <li>在创建 pod 时,主动为 pod 提交资源申请和限制;</li>
    <li>让 sheduler 以指标采集工具采集的指标为准来计算可用资源;</li>
    <li>为系统 和 k8s 预留适当的资源;</li>
    </ul>
    <p>下面介绍一下资源预留和应用场景。</p>
    <pre class=" language-bash"><code class="prism language-bash"> Node Capacity
    ---------------------------
    <span class="token operator">|</span> kube-reserved <span class="token operator">|</span>
    <span class="token operator">|</span>-------------------------<span class="token operator">|</span>
    <span class="token operator">|</span> system-reserved <span class="token operator">|</span>
    <span class="token operator">|</span>-------------------------<span class="token operator">|</span>
    <span class="token operator">|</span> eviction-threshold <span class="token operator">|</span>
    <span class="token operator">|</span>-------------------------<span class="token operator">|</span>
    <span class="token operator">|</span> <span class="token operator">|</span>
    <span class="token operator">|</span> allocatable <span class="token operator">|</span>
    <span class="token operator">|</span> <span class="token punctuation">(</span>available <span class="token keyword">for</span> pods<span class="token punctuation">)</span> <span class="token operator">|</span>
    <span class="token operator">|</span> <span class="token operator">|</span>
    ---------------------------
    </code></pre>
    <p>上图表示了一个节点上资源的分配关系。</p>
    <ul>
    <li>
    <p>Node Capacity<br>
    代表整个节点的资源容量,和 <code>kubectl describe node node01</code> 看到的 Capacity 一致。</p>
    </li>
    <li>
    <p>kube-reserved<br>
    a.) 为 k8s 后台服务预留资源,如 <code>kubelet</code>, <code>container runtime</code>, <code>node problem detector</code> 等,但并不包含那些运行在 pod 中的 k8s 服务,如 <code>calico-node</code>、<code>kube-apiserver</code>、<code>kube-controller-manager</code>、<code>kube-dns</code>、<code>kube-proxy</code>、<code>kube-scheduler</code>、<code>kube-scheduler</code>、<code>kubedns-autoscaler</code>、<code>kubernetes-dashboard</code> 等。<br>
    b.) 在 systemd 系统上建议将的 k8s 后台服务放置在顶级 cgroup 下(设置 runtime.slice);<br>
    c.) 在 kubelet 服务启动参数中添加标记来设置,示例:<br>
    <code>--kube-reserved=[cpu=100m][,][memory=100Mi][,][ephemeral-storage=1Gi]</code></p>
    </li>
    <li>
    <p>system-reserved<br>
    a.) 为系统后台服务预留资源,如 <code>sshd</code>、<code>udev</code> 等;<br>
    b.) 推荐为内核预留内存资源因为目前为止它还没有被计入 k8s 的 pod 资源;<br>
    c.) 推荐为 systemd 系统的<strong>用户登录会话</strong>预留资源(cgroup 设置 user.slice );<br>
    d.) 在 kubelet 服务启动参数中添加标记来设置,示例:<br>
    <code>--system-reserved=[cpu=100m][,][memory=100Mi][,][ephemeral-storage=1Gi]</code></p>
    </li>
    <li>
    <p>eviction-threshold<br>
    a.) 为 k8s 节点设置空余资源阈值,当节点可用资源低于该阈值时,pod 将被驱逐;<br>
    b.) 目前仅适用于 memory 和 ephemeral-storage;<br>
    c.) 在 kubelet 服务启动参数中添加标记来设置,示例:<br>
    <code>--eviction-hard=[memory.available&lt;500Mi]</code></p>
    </li>
    </ul>
    <p>关于资源预留,参考文档:<br>
    <a href="https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources">https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources</a></p>
    <h3 id="重平衡工具-descheduler">重平衡工具 Descheduler</h3>
    <p>本文着重介绍一下 Kubernetes 孵化器中的一个工具:<a href="https://github.com/kubernetes-incubator/descheduler">Descheduler</a></p>
    <h4 id="工具简介">工具简介</h4>
    <p>Descheduler 的出现就是为了解决 Kubernetes 自身调度(一次性调度)不足的问题。它以定时任务方式运行,根据已实现的策略,重新去平衡 pod 在集群中的分布。</p>
    <p>截止目前,Descheduler 已实现的策略和计划中的功能点如下:</p>
    <p><strong>已实现的调度策略</strong></p>
    <ul>
    <li>RemoveDuplicates<br>
    移除重复 pod</li>
    <li>LowNodeUtilization<br>
    节点低度使用</li>
    <li>RemovePodsViolatingInterPodAntiAffinity<br>
    移除违反pod反亲和性的 pod</li>
    <li>RemovePodsViolatingNodeAffinity</li>
    </ul>
    <p><strong>路线图中计划实现的功能点</strong></p>
    <ul>
    <li>Strategy to consider taints and tolerations<br>
    考虑污点和容忍</li>
    <li>Consideration of pod affinity<br>
    考虑 pod 亲和性</li>
    <li>Strategy to consider pod life time<br>
    考虑 pod 生命周期</li>
    <li>Strategy to consider number of pending pods<br>
    考虑待定中的 pod 数量</li>
    <li>Integration with cluster autoscaler<br>
    与集群自动伸缩集成</li>
    <li>Integration with metrics providers for obtaining real load metrics<br>
    与监控工具集成来获取真正的负载指标</li>
    <li>Consideration of Kubernetes’s scheduler’s predicates<br>
    考虑 k8s 调度器的预判机制</li>
    </ul>
    <h4 id="策略介绍">策略介绍</h4>
    <ul>
    <li>
    <p>RemoveDuplicates<br>
    此策略确保每个副本集(RS)、副本控制器(RC)、部署(Deployment)或任务(Job)只有一个 pod 被分配到同一台 node 节点上。如果有多个则会被驱逐到其它节点以便更好的在集群内分散 pod。</p>
    </li>
    <li>
    <p>LowNodeUtilization<br>
    a. 此策略会找到未充分使用的 node 节点并在可能的情况下将那些被驱逐后希望重建的 pod 调度到该节点上。<br>
    b. 节点是否<strong>利用不足</strong>由一组可配置的 <strong>阈值</strong>(<code>thresholds</code>) 决定。这组阈值是以百分比方式指定了 CPU、内存以及 pod数量 的。只有当所有被评估资源都低于它们的阈值时,该 node 节点才会被认为处于<strong>利用不足</strong>状态。<br>
    c. 同时还存在一个 <strong>目标阈值</strong>(<code>targetThresholds</code>),用于评估那些节点是否因为超出了阈值而应该从其上驱逐 pod。任何阈值介于 <code>thresholds</code> 和 <code>targetThresholds</code> 之间的节点都被认为资源被合理利用了,因此不会发生 pod 驱逐行为(无论是被驱逐走还是被驱逐来)。<br>
    d. 与之相关的还有另一个参数<code>numberOfNodes</code>,这个参数用来激活指定数量的节点是否处于资源<strong>利用不足</strong>状态而发生 pod 驱逐行为。</p>
    </li>
    <li>
    <p>RemovePodsViolatingInterPodAntiAffinity<br>
    此策略会确保 node 节点上违反 pod 间亲和性的 pod 被驱逐。比如节点上有 podA 并且 podB 和 podC(也在同一节点上运行)具有禁止和 podA 在同一节点上运行的反亲和性规则,则 podA 将被从节点上驱逐,以便让 podB 和 podC 可以运行。</p>
    </li>
    <li>
    <p>RemovePodsViolatingNodeAffinity<br>
    此策略会确保那些违反 node 亲和性的 pod 被驱逐。比如 podA 运行在 nodeA 上,后来该节点不再满足 podA 的 node 亲和性要求,如果此时存在 nodeB 满足这一要求,则 podA 会被驱逐到 nodeB 节点上。</p>
    </li>
    </ul>
    <h4 id="遵循机制">遵循机制</h4>
    <p>当 Descheduler 调度器决定于驱逐 pod 时,它将遵循下面的机制:</p>
    <ul>
    <li>
    <p>Critical pods (with annotations <a href="http://scheduler.alpha.kubernetes.io/critical-pod">scheduler.alpha.kubernetes.io/critical-pod</a>) are never evicted<br>
    关键 pod(带注释 <a href="http://scheduler.alpha.kubernetes.io/critical-pod%EF%BC%89%E6%B0%B8%E8%BF%9C%E4%B8%8D%E4%BC%9A%E8%A2%AB%E9%A9%B1%E9%80%90%E3%80%82">scheduler.alpha.kubernetes.io/critical-pod)永远不会被驱逐。</a></p>
    </li>
    <li>
    <p>Pods (static or mirrored pods or stand alone pods) not part of an RC, RS, Deployment or Jobs are never evicted because these pods won’t be recreated<br>
    不属于RC,RS,部署或作业的Pod(静态或镜像pod或独立pod)永远不会被驱逐,因为这些pod不会被重新创建。</p>
    </li>
    <li>
    <p>Pods associated with DaemonSets are never evicted<br>
    与 DaemonSets 关联的 Pod 永远不会被驱逐。</p>
    </li>
    <li>
    <p>Pods with local storage are never evicted<br>
    具有本地存储的 Pod 永远不会被驱逐。</p>
    </li>
    <li>
    <p>BestEffort pods are evicted before Burstable and Guaranteed pods<br>
    QoS 等级为 BestEffort 的 pod 将会在等级为 Burstable 和 Guaranteed 的 pod 之前被驱逐。</p>
    </li>
    </ul>
    <h4 id="工具使用">工具使用</h4>
    <p>Descheduler 会以 <a href="https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion">Job</a> 形式在 pod 内运行,因为 Job 具有多次运行而无需人为介入的优势。为了避免被自己驱逐 Descheduler 将会以 <strong>关键型</strong> pod 运行,因此它只能被创建建到 <code>kube-system</code> namespace 内。<br>
    关于 Critical pod 的介绍请参考:<a href="https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods">Guaranteed Scheduling For Critical Add-On Pods</a></p>
    <p>要使用 Descheduler,我们需要编译该工具并构建 Docker 镜像,创建 ClusterRole、ServiceAccount、ClusterRoleBinding、ConfigMap 以及 Job。</p>
    <p>由于文档中有一些小<a href="#%E9%97%AE%E9%A2%98%E5%A4%84%E7%90%86">问题</a>,手动执行这些步骤不会很顺利,我们推荐使用有人维护的现成 helm charts。<br>
    项目地址:<a href="https://github.com/komljen/helm-charts/tree/master/descheduler">https://github.com/komljen/helm-charts/tree/master/descheduler</a><br>
    使用方式:</p>
    <pre class=" language-bash"><code class="prism language-bash">helm repo add akomljen-charts \
    https://raw.githubusercontent.com/komljen/helm-charts/master/charts/

    helm <span class="token function">install</span> \
    --name ds \
    --namespace kube-system \
    akomljen-charts/descheduler
    </code></pre>
    <p>该 Chart 默认设置如下:</p>
    <ul>
    <li>Descheduler 以 CronJob 方式运行,每 30 分钟执行一次,可根据实际需要进行调整;</li>
    <li>在 ConfigMap 中同时内置了 4种策略,可根据实际需要禁用或调整;</li>
    </ul>
    <p>值得注意的是,Descheduler 项目文档中是以 Job 方式运行,属于一次性任务。</p>
    <h4 id="问题处理">问题处理</h4>
    <p>在手动编译构建 Descheduler 过程中,我们发现官方文档有个小问题。<br>
    比如,文档中 Job 的启动方式如下:</p>
    <pre class=" language-yaml"><code class="prism language-yaml"> <span class="token key atrule">command</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token string">"/bin/sh"</span>
    <span class="token punctuation">-</span> <span class="token string">"-ec"</span>
    <span class="token punctuation">-</span> <span class="token punctuation">|</span><span class="token scalar string">
    /bin/descheduler --policy-config-file /policy-dir/policy.yaml</span>
    </code></pre>
    <p>即,指定使用 <code>sh</code> 来运行 <code>descheduler</code>,然而该工具的 <a href="https://github.com/kubernetes-incubator/descheduler/blob/v0.8.0/Dockerfile">Dockerfile</a> 却是以白手起家(<a href="https://hub.docker.com/_/scratch">FROM scratch</a>)方式添加 descheduler 的编译产物到容器内,新容器并不包含工具<code>sh</code>, 这就导致 Job 在运行后因为没有 <code>sh</code> 而失败并不断拉起新的 Job,短时间内大量 Job 被创建, node 节点资源也逐渐被消耗。</p>
    <p>关于该问题我提交了一个 <a href="https://github.com/kubernetes-incubator/descheduler/issues/133">isusse #133</a>,解决办法有2种:</p>
    <ul>
    <li>从 command 中移除 <code>/bin/sh -ec</code></li>
    <li>修改 Dockerfile 中 <code>From scratch</code> 为 <code>From alpine</code> 或 busybox 或 centos 等</li>
    </ul>
    <p>然后重新构建并创建 Job。</p>
    <h2 id="参考文档">参考文档</h2>
    <p><a href="https://akomljen.com/meet-a-kubernetes-descheduler">https://akomljen.com/meet-a-kubernetes-descheduler</a></p>

    </div>
    </div>
    </body>

    </html>