K8Sアプリケーションの優先度、追放、変動性、動的なリソース調整

K8Sアプリケーションの優先度、追放、変動性、動的なリソース調整

アプリケーションの優先順位

要求およびコンフィギュレーションの限界を示したリソースを除くと、リソースの使用を制限するには、隠された効果があります。それは、ポッドのQoSレベルを決定します

1に、私たちは詳細を述べた:ポッドは限界が設定されていない場合は、多くの利用可能なリソースを使用することができますよう、それはノードです。このようなポッドのリソースを使用するための柔軟性が、それはまた、ポッドのこのタイプのために私たちはそれにあまりにも多くのリソースを取る必要があり、不安定で危険につながったノードのリソースの制約の処分につながります。むしろ、要求の範囲内でポッドに自分のリソースを扱うよりも、このようなポッドの優先順位は、非常に合理的な考え方であり、それはポッドのQoSの意味である:重要性の異なるレベルにポッドポッドのリソース要求によると。

3つのQoSクラスへのポッドKubernetes:

  • 保証:最高の優先順位は、データベースアプリケーション、またはいくつかの重要なビジネス・アプリケーションを考えてみましょう。ポッドは、多くの圧力が限界を超える、またはノードのメモリを使用し、何のQoSそうでない場合、彼らは殺されないであろう下ポッドは、存在しない場合を除き。
  • バースト可能な:この種類のポッドは、いずれかの一般的または補助金の適用、(設定されていない、あなたが利用可能なリソースのホストのいずれかを使用することができれば制限し、制限で指定された上限値)要求された、独自のリソース以上のものが、重要性が比較的低いと思うかもしれません処理タスク。
  • ベストエフォート:最低の優先順位は、それはいくつかの一時的な重要でないアプリケーションすることができ、リソースに関係なく、ポッドクラスタリソース要求、スケジュールを知りません(ビューのリソースの観点から)任意のノード上で実行することができます。ポッドは、ノード上のすべての利用可能なリソースを使用することができますが、優先順位は、リソースの不足で殺されます。

次の表でまとめたこれら三つのQoSクラスに対応する要求とどのようにポッドの制限:

IMG

質問:あなたが要求して制限を設定しない場合は、QoSをポッドが最も低いことが判明しましたはい、あなたがQoSの概念を理解することが推奨され、オンデマンドでポッド設定要求を与えるとパラメータを制限しなければならない、より正確なスケジュールにするだけでなく、システムをより安定させることができるだけでなく、。

ポッドはまた、QoSのコンテナOOM(メモリ不足)の値を決定し、次のように、その対応関係は以下のとおりです。

IMG

QoSの高い下ポッドOOM値、より多くのシステムによって殺さすることは困難Bustableポッドのために、そのに基づいて要求および関節全決定ノードのメモリ:

oomScoreAdjust := 1000 - (1000*memoryRequest)/memoryCapacity

どのmemoryRequestリソースポッドアプリケーション、あるmemoryCapacityメモリノードの合計額。あなたはOOM値が低いほど、また殺されにくく、より多くのメモリアプリケーション、見ることができます。

ポッドプライオリティ(優先順位)

QoSのに加えて、Kubernetesはまたのようなポッドの優先順位を、カスタマイズするために私達にできます。

apiVersion: scheduling.k8s.io/v1alpha1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for XYZ service Pods only."

比較的簡単な使用優先順位は、唯一必要Pod.spec.PriorityClassName即ち、現在の優先レベルはポッドに対応する値に設定することができる、名前を指定するために使用される優先順位を。

スケジューリングをするために使用されるポッドの優先順位まず、ポッドは同じキューにスケジュールされた後、優先順位ポッドは、有効に前倒し、前面に優先度の高いポッドのサイズの優先順位に基づいて、スケジューラを。

派遣した場合や、リソース不足が原因のポッドは、右のノードを見つけることができない見つけ、スケジューラは、ロジックのプリエンプトしようとします。簡単に言えば、スケジューラは、このようなノードを検索しようとします:スケジュールするために、現在のポッドポッドよりも低い優先順位の上にそれをすべて見つけ、そして彼らは、することができテン十分なリソースを殺した場合、スケジューラは、削除を行うことができ、ポッドは、スケジュールノード。詳細はを参照することができます:ポッドの優先順位とプリエンプション - Kubernetesを。

労働条件Kubernetes理想の言う、我々は完全に十分なリソースを想定し、アプリケーションは指定された範囲内のリソースの使用でもあります。

クラスタを管理するには、私たちはしばしば、我々がしなければならない。その場合には、リソースの不足に遭遇クラスタ全体が使用可能であることを確認し、可能な限り損失アプリケーションを減らすためにクラスタが理解しやすいことを確認するために使用することができ、我々は、最初に通常のシステム・レベルのコアプロセスを確認する必要があり、そして第二に、それ自体は問題ではありませんKubernetes組立プロセスを確実にするために、どのようにそれを使用することの損失を定量化するために?まず第一のは、あなたがポッドを殺したい場合は、合計数を削減しようとすることであると考えることができます。そして、関連ポッドの優先順位上の別の、それは重要なアプリケーションが影響を受けないように、重要度の低いアプリケーションを殺すことです。

Kubeletが動的にノードのリソースの使用状況にリアルタイムで変化を感知されるので、ポッド追放はKubeletに実装されています。コアロジックは次のとおりです。Kubeletリアルタイム監視ノード上のさまざまなリソースの使用は、かつて非圧縮性リソースはノードが正常に動作することができるように、ノード上のポッドを終了するためのイニシアチブをとるだろう、排出されるように見えました。ポッドは、すべてのコンテナが停止します終了し、ステータスが失敗に設定されています。

現在、3つのケースがある:実際のメモリの不足、ファイル・システム・スペース利用可能なノード(サイズおよび残留inodeファイルシステムの数)が不足し、画像ファイルシステムの空き容量不足(ファイル・システムのサイズと残りのinodeの数を含みます)。

この図は、特定のトリガ条件を下回っています。

IMG

有了数据的来源,另外一个问题是触发的时机,也就是到什么程度需要触发驱逐程序?Kubernetes 运行用户自己配置,并且支持两种模式:按照百分比和按照绝对数量。比如对于一个 32G 内存的节点当可用内存少于 10% 时启动驱逐程序,可以配置 memory.available<10%或者 memory.available<3.2Gi

NOTE:默认情况下,Kubelet 的驱逐规则是 memory.available<100Mi,对于生产环境这个配置是不可接受的,所以一定要根据实际情况进行修改。

因为驱逐 Pod 是具有毁坏性的行为,因此必须要谨慎。有时候内存使用率增高只是暂时性的,有可能 20s 内就能恢复,这时候启动驱逐程序意义不大,而且可能会导致应用的不稳定,我们要考虑到这种情况应该如何处理;另外需要注意的是,如果内存使用率过高,比如高于 95%(或者 90%,取决于主机内存大小和应用对稳定性的要求),那么我们不应该再多做评估和考虑,而是赶紧启动驱逐程序,因为这种情况再花费时间去判断可能会导致内存继续增长,系统完全崩溃。

为了解决这个问题,Kubernetes 引入了 Soft Eviction 和 Hard Eviction 的概念。

软驱逐可以在资源紧缺情况并没有哪些严重的时候触发,比如内存使用率为 85%,软驱逐还需要配置一个时间指定软驱逐条件持续多久才触发,也就是说 Kubelet 在发现资源使用率达到设定的阈值之后,并不会立即触发驱逐程序,而是继续观察一段时间,如果资源使用率高于阈值的情况持续一定时间,才开始驱逐。并且驱逐 Pod 的时候,会遵循 Grace Period ,等待 Pod 处理完清理逻辑。和软驱逐相关的启动参数是:

  • --eviction-soft:软驱逐触发条件,比如 memory.available<1Gi
  • --eviction-sfot-grace-period:触发条件持续多久才开始驱逐,比如 memory.available=2m30s
  • --eviction-max-Pod-grace-period:Kill Pod 时等待 Grace Period 的时间让 Pod 做一些清理工作,如果到时间还没有结束就做 Kill。

前面两个参数必须同时配置,软驱逐才能正常工作;后一个参数会和 Pod 本身配置的 Grace Period 比较,选择较小的一个生效。

硬驱逐更加直接干脆,Kubelet 发现节点达到配置的硬驱逐阈值后,立即开始驱逐程序,并且不会遵循 Grace Period,也就是说立即强制杀死 Pod。对应的配置参数只有一个 --evictio-hard,可以选择上面表格中的任意条件搭配。

设置这两种驱逐程序是为了平衡节点稳定性和对 Pod 的影响,软驱逐照顾到了 Pod 的优雅退出,减少驱逐对 Pod 的影响;而硬驱逐则照顾到节点的稳定性,防止资源的快速消耗导致节点不可用。

软驱逐和硬驱逐可以单独配置,不过还是推荐两者都进行配置,一起使用。

上面已经整体介绍了 Kubelet 驱逐 Pod 的逻辑和过程。牵涉到一个具体的问题:要驱逐哪些 Pod?驱逐的重要原则是尽量减少对应用程序的影响。

如果是存储资源不足,Kubelet 会根据情况清理状态为 Dead 的 Pod 和它的所有容器,以及清理所有没有使用的镜像。如果上述清理并没有让节点回归正常,Kubelet 就开始清理 Pod。

一个节点上会运行多个 Pod,驱逐所有的 Pods 显然是不必要的,因此要做出一个抉择:在节点上运行的所有 Pod 中选择一部分来驱逐。虽然这些 Pod 乍看起来没有区别,但是它们的地位是不一样的,

系统组件的 Pod 要比普通的 Pod 更重要,另外运行数据库的 Pod 自然要比运行一个无状态应用的 Pod 更重要。Kubernetes 又是怎么决定 Pod 的优先级的呢?这个问题的答案就藏在我们之前已经介绍过的内容里:Pod Requests 和 Limits、优先级(Priority),以及 Pod 实际的资源使用。

简单来说,Kubelet 会根据以下内容对 Pod 进行排序:Pod 是否使用了超过请求的紧张资源、Pod 的优先级、然后是使用的紧缺资源和请求的紧张资源之间的比例。具体来说,Kubelet 会按照如下的顺序驱逐 Pod:

  • 使用的紧张资源超过请求数量的 BestEffortBurstable Pod,这些 Pod 内部又会按照优先级和使用比例进行排序。
  • 紧张资源使用量低于 Requests 的 BurstableGuaranteed 的 Pod 后面才会驱逐,只有当系统组件(Kubelet、Docker、Journald 等)内存不够,并且没有上面 QoS 比较低的 Pod 时才会做。执行的时候还会根据 Priority 排序,优先选择优先级低的 Pod。

波动有两种情况,第一种。驱逐条件出发后,如果 Kubelet 驱逐一部分 Pod,让资源使用率低于阈值就停止,那么很可能过一段时间资源使用率又会达到阈值,从而再次出发驱逐,如此循环往复……为了处理这种问题,我们可以使用 --eviction-minimum-reclaim解决,这个参数配置每次驱逐至少清理出来多少资源才会停止。

另外一个波动情况是这样的:Pod 被驱逐之后并不会从此消失不见,常见的情况是 Kubernetes 会自动生成一个新的 Pod 来取代,并经过调度选择一个节点继续运行。如果不做额外处理,有理由相信 Pod 选择原来节点的可能性比较大(因为调度逻辑没变,而它上次调度选择的就是该节点),之所以说可能而不是绝对会再次选择该节点,是因为集群 Pod 的运行和分布和上次调度时极有可能发生了变化。

​ 无论如何,如果被驱逐的 Pod 再次调度到原来的节点,很可能会再次触发驱逐程序,然后 Pod 再次被调度到当前节点,循环往复…… 这种事情当然是我们不愿意看到的,虽然看似复杂,但这个问题解决起来非常简单:驱逐发生后,Kubelet 更新节点状态,调度器感知到这一情况,暂时不往该节点调度 Pod 即可。--eviction-pressure-transition-period 参数可以指定 Kubelet 多久才上报节点的状态,因为默认的上报状态周期比较短,频繁更改节点状态会导致驱逐波动。

​ 使用了上面多种参数的驱逐配置实例:

–eviction-soft=memory.available<80%,nodefs.available<2Gi \
–eviction-soft-grace-period=memory.available=1m30s,nodefs.available=1m30s \
–eviction-max-Pod-grace-period=120 \
–eviction-hard=memory.available<500Mi,nodefs.available<1Gi \
–eviction-pressure-transition-period=30s \
--eviction-minimum-reclaim="memory.available=0Mi,nodefs.available=500Mi,imagefs.available=2Gi"

Kubernetes 的调度器在为 Pod 选择运行节点的时候,只会考虑到调度那个时间点集群的状态,经过一系列的算法选择一个当时最合适的节点。但是集群的状态是不断变化的,用户创建的 Pod 也是动态的,随着时间变化,原来调度到某个节点上的 Pod 现在看来可能有更好的节点可以选择。比如考虑到下面这些情况:

  • 调度 Pod 的条件已经不再满足,比如节点的 Taints 和 Labels 发生了变化。
  • 新节点加入了集群。如果默认配置了把 Pod 打散,那么应该有一些 Pod 最好运行在新节点上。
  • 节点的使用率不均匀。调度后,有些节点的分配率和使用率比较高,另外一些比较低。
  • 节点上有资源碎片。有些节点调度之后还剩余部分资源,但是又低于任何 Pod 的请求资源;或者 Memory 资源已经用完,但是 CPU 还有挺多没有使用。

想要解决上述的这些问题,都需要把 Pod 重新进行调度(把 Pod 从当前节点移动到另外一个节点)。但是默认情况下,一旦 Pod 被调度到节点上,除非给杀死否则不会移动到另外一个节点的。

Kubernetes 社区孵化了一个称为 Descheduler 的项目,专门用来做重调度。重调度的逻辑很简单:找到上面几种情况中已经不是最优的 Pod,把它们驱逐掉(Eviction)。

Descheduler 不会决定驱逐的 Pod 应该调度到哪台机器,而是假定默认的调度器会做出正确的调度抉择。也就是说,之所以 Pod 目前不合适,不是因为调度器的算法有问题,而是因为集群的情况发生了变化。如果让调度器重新选择,调度器现在会把 Pod 放到合适的节点上。这种做法让 Descheduler 逻辑比较简单,而且避免了调度逻辑出现在两个组件中。

Descheduler 执行的逻辑是可以配置的,目前有几种场景:

  • RemoveDuplicates:RS、Deployment 中的 Pod 不能同时出现在一台机器上。
  • LowNodeUtilization:找到资源使用率比较低的 Node,然后驱逐其他资源使用率比较高节点上的 Pod,期望调度器能够重新调度让资源更均衡。
  • RemovePodsViolatingInterPodAntiAffinity:找到已经违反 Pod Anti Affinity 规则的 Pods 进行驱逐,可能是因为反亲和是后面加上去的。
  • RemovePodsViolatingNodeAffinity:找到违反 Node Affinity 规则的 Pods 进行驱逐,可能是因为 Node 后面修改了 Label。

当然,为了保证应用的稳定性,Descheduler 并不会随意地驱逐 Pod,还是会尊重 Pod 运行的规则,包括 Pod 的优先级(不会驱逐 Critical Pod,并且按照优先级顺序进行驱逐)和 PDB(如果违反了 PDB,则不会进行驱逐),并且不会驱逐没有 Deployment、RS、Jobs 的 Pod 不会驱逐,Daemonset Pod 不会驱逐,有 Local storage 的 Pod 也不会驱逐。

Descheduler 不是一个常驻的任务,每次执行完之后会退出,因此推荐使用 CronJob 来运行。

总的来说,Descheduler 是对原生调度器的补充,用来解决原生调度器的调度决策随着时间会变得失效,或者不够优化的缺陷。

动态调整的思路:应用的实际流量会不断变化,因此使用率也是不断变化的,为了应对应用流量的变化,我们应用能够自动调整应用的资源。比如在线商品应用在促销的时候访问量会增加,我们应该自动增加 Pod 运算能力来应对;当促销结束后,有需要自动降低 Pod 的运算能力防止浪费。

运算能力的增减有两种方式:改变单个 Pod 的资源,以及增减 Pod 的数量。这两种方式对应了 Kubernetes 的 HPA 和 VPA。

IMG

横向 Pod 自动扩展的思路是这样的:Kubernetes 会运行一个 Controller,周期性地监听 Pod 的资源使用情况,当高于设定的阈值时,会自动增加 Pod 的数量;当低于某个阈值时,会自动减少 Pod 的数量。自然,这里的阈值以及 Pod 的上限和下限的数量都是需要用户配置的。

一个重要的信息:HPA 只能和 RC、Deployment、RS 这些可以动态修改 Replicas 的对象一起使用,而无法用于单个 Pod、Daemonset(因为它控制的 Pod 数量不能随便修改)等对象。

目前官方的监控数据来源是 Metrics Server 项目,可以配置的资源只有 CPU,但是用户可以使用自定义的监控数据(比如:Prometheus)。其他资源(比如:Memory)的 HPA 支持也已经在路上了。

和 HPA 的思路相似,只不过 VPA 调整的是单个 Pod 的 Request 值(包括 CPU 和 Memory)。VPA 包括三个组件

  • Recommander:消费 Metrics Server 或者其他监控组件的数据,然后计算 Pod 的资源推荐值。
  • Updater:找到被 VPA 接管的 Pod 中和计算出来的推荐值差距过大的,对其做 Update 操作(目前是 Evict,新建的 Pod 在下面 Admission Controller 中会使用推荐的资源值作为 Request)。
  • Admission Controller:新建的 Pod 会经过该 Admission Controller,如果 Pod 是被 VPA 接管的,会使用 Recommander 计算出来的推荐值。

可以看到,这三个组件的功能是互相补充的,共同实现了动态修改 Pod 请求资源的功能。相对于 HPA,目前 VPA 还处于 Alpha,并且还没有合并到官方的 Kubernetes Release 中,后续的接口和功能很可能会发生变化。

随着业务的发展,应用会逐渐增多,每个应用使用的资源也会增加,总会出现集群资源不足的情况。为了动态地应对这一状况,我们还需要 CLuster Auto Scaler,能够根据整个集群的资源使用情况来增减节点。

パブリッククラウドの場合は、クラスタオートスケーラーは、マシンの作成を要求したり、マシンを破壊するパブリック・クラウド・インタフェースを呼び出すために、ユーザが設定したしきい値に基づいて、リソース不足や保留中ポッドのクラスタを監視することです。プライベートクラウドのために、我々は内部管理プラットフォームをドッキングする必要があります。

これは、HPAとVPAと、現在の互換性はありません、唯一の使用を選択することができますそれ以外の場合は2が互いに干渉します。そして、VPAを調整ポッドを再起動する必要がポッドのリソースを変更することは比較的大きな変化であるので、Apiserverそれを再取る必要があり、スケジューリング処理、システム全体が問題ありませんことを確認してください。現在、コミュニティにもそれを行うための場所にアップグレードする予定再スケジュールする新しいポッドポッド殺害の方法によってではなく、直接更新するには、元のポッドを変更します。

理論的にはVPAおよびHPAが一緒に働いている、HPAは、VPAは、他のリソースを担当し、ボトルネックリソースの責任です例えば、CPU集約型アプリケーションは、HPAの使用は、CPU使用率モニタポッドの数を調整し、その後、動的にこれらのリソースのサイズに拡大するVPA要求と共に他のリソース(メモリ、IO)をリッスン。もちろん、これは唯一の理想的な状況で、

クラスタリソースの使用は、静的ではなく、常に時間をかけて変化する、現在のKubernetesスケジューリングの決定は、動的Kubelet追放手続きによって行われるリソースを調整した静的リソーススケジューリングクラスタセクションに基づいていますHPAとVPAおよびその他のプログラムはまた、我々は背後にKubernetesは、よりインテリジェントせ、この点で機能を改善し続けることを信じて、進められています。

リソース管理とスケジューリング、アプリケーションの優先順位、監視、ミラーリング中心部や他の多くの関連の事、非常に複雑な領域です。具体的な実装と運用時には、多くの場合、ターゲットを絞った調整を行うために、企業内のアカウントに特定の状況やニーズを取って、そして一緒に仕事を別のグループの開発者、システム管理者、SRE、および他の監視チームが必要です。しかし、全体的に、この給与は、ビジネスの省資源の費用対効果の高い利用率を向上させるために、それは価値があるが、また、アプリケーションが、より良い役割を再生することができます。

おすすめ

転載: www.cnblogs.com/h-gallop/p/11682100.html