コンピューティングと自動スケーリング - Amazon EKS

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

コンピューティングと自動スケーリング

開発者は、CPU やメモリなど、アプリケーションのリソース要件について見積もりを行いますが、継続的に調整しないと、古くなったり、コストが増加し、パフォーマンスや信頼性が低下する可能性があります。アプリケーションのリソース要件を継続的に調整することは、初めて正しく行うよりも重要です。

以下に説明するベストプラクティスは、コストを最小限に抑え、組織が投資収益率を最大化しながら、ビジネス成果を達成するコスト対応ワークロードを構築して運用するのに役立ちます。クラスターのコンピューティングコストを最適化するために重要度の高い順序は次のとおりです。

  1. 適切なサイズのワークロード

  2. 未使用の容量を減らす

  3. コンピューティングキャパシティタイプ (スポットなど) とアクセラレーター (GPUs) を最適化する

ワークロードの適切なサイズ設定

ほとんどの EKS クラスターでは、コストの大部分はコンテナ化されたワークロードの実行に使用される EC2 インスタンスから発生します。ワークロードの要件を理解しないと、コンピューティングリソースのサイズを適正化することはできません。このため、適切なリクエストと制限を使用し、必要に応じてそれらの設定を調整することが不可欠です。さらに、インスタンスサイズやストレージの選択などの依存関係は、ワークロードのパフォーマンスに影響を与える可能性があり、コストや信頼性に意図しないさまざまな影響を与える可能性があります。

リクエストは実際の使用率と一致する必要があります。コンテナのリクエストが高すぎると、未使用の容量が発生するため、クラスターの合計コストに大きな影響を与えます。アプリケーションやサイドカーなど、ポッド内の各コンテナには、ポッドの集約制限が可能な限り正確になるように、独自のリクエストと制限を設定する必要があります。

コンテナのリソースリクエストと制限を見積もる、GoldilocksKRRKubecost などのツールを使用します。アプリケーションの性質、パフォーマンス/コスト要件、複雑さに応じて、どのメトリクスをスケールするのが最適か、アプリケーションのパフォーマンスが低下する時点 (飽和点)、それに応じてリクエストと制限を調整する方法を評価する必要があります。このトピックの詳細については、「アプリケーションの適切なサイズ設定」を参照してください。

Horizontal Pod Autoscaler (HPA) を使用して、実行中のアプリケーションのレプリカの数を制御し、Vertical Pod Autoscaler (VPA) を使用してレプリカごとにアプリケーションに必要なリクエストの数を調整して制限し、Karpenter Cluster Autoscaler などのノードオートスケーラーを使用してクラスター内のノードの合計数を継続的に調整することをお勧めします。Karpenter と Cluster Autoscaler を使用したコスト最適化手法については、このドキュメントの後半セクションで説明します。

Vertical Pod Autoscaler は、コンテナに割り当てられたリクエストと制限を調整して、ワークロードが最適に実行されるようにします。VPA は監査モードで実行する必要があります。これにより、ポッドを自動的に変更して再起動しなくなります。観測されたメトリクスに基づいて変更を提案します。本番稼働用ワークロードに影響する変更は、アプリケーションの信頼性とパフォーマンスに影響を与える可能性があるため、本番稼働用以外の環境で最初に変更を確認してテストする必要があります。

消費量の削減

コストを節約する最善の方法は、プロビジョニングするリソースを減らすことです。そのための 1 つの方法は、現在の要件に基づいてワークロードを調整することです。コスト最適化の取り組みは、ワークロードが要件を定義し、動的にスケールするようにすることから始める必要があります。そのためには、アプリケーションからメトリクスを取得し、 PodDisruptionBudgetsPod Readiness Gates などの設定を行って、アプリケーションが動的に安全にスケールアップおよびスケールダウンできるようにする必要があります。Cluster Autoscaler と Karpenter の両方が PodDisruptionBudgets を優先するため、制限付きの PodDisruptionBudgets が Cluster Autoscaler と Karpenter のノードのスケールダウンを防ぐことができることを考慮することが重要です。PodDisruptionBudget のminAvailable」値は、常にデプロイ内のポッド数よりも小さく、2 つの 間に適切なバッファを保持する必要があります。たとえば、6 つのポッドのデプロイで、常に 4 つ以上のポッドを実行する場合は、PodDisruptionBidget のminAvailable」を 4 に設定します。これにより、Cluster Autoscaler と Karpenter は、ノードのスケールダウンイベント中に、使用率の低いノードからポッドを安全にドレインおよび削除できます。Cluster Autoscaler のよくある質問ドキュメントを参照してください。

Horizontal Pod Autoscaler は、アプリケーションのパフォーマンスと信頼性の要件を満たすために必要なレプリカの数を調整できる柔軟なワークロードオートスケーラーです。CPU、メモリ、キューの深さ、ポッドへの接続数などのカスタムメトリクスなど、さまざまなメトリクスに基づいてスケールアップおよびスケールダウンするタイミングを定義する柔軟なモデルがあります。

Kubernetes メトリクスサーバーは、CPU やメモリの使用量などの組み込みメトリクスに応じてスケーリングを有効にしますが、Amazon CloudWatch や SQS キューの深さなどの他のメトリクスに基づいてスケーリングする場合は、KEDA などのイベント駆動型自動スケーリングプロジェクトを検討する必要があります。CloudWatch メトリクスで KEDA を使用する方法については、このブログ記事を参照してください。モニタリングおよびスケーリングの基準となるメトリクスが不明な場合は、重要なメトリクスのモニタリングに関するベストプラクティスを確認してください。

ワークロードの消費量を減らすと、クラスターに過剰な容量が発生し、適切な自動スケーリング設定により、ノードを自動的にスケールダウンし、総支出を削減できます。コンピューティング容量を手動で最適化しないことをお勧めします。Kubernetes スケジューラとノードオートスケーラは、このプロセスを処理するように設計されています。

未使用の容量を減らす

アプリケーションの正しいサイズを決定し、過剰なリクエストを減らしたら、プロビジョニングされたコンピューティング容量を減らし始めることができます。上記のセクションでワークロードのサイズを正しく設定する時間を確保した場合は、これを動的に実行できます。AWS の Kubernetes で使用されるプライマリノードオートスケーラーは 2 つあります。

Karpenter と Cluster Autoscaler

Karpenter と Kubernetes Cluster Autoscaler の両方が、ポッドの作成または削除とコンピューティング要件の変更に応じて、クラスター内のノード数をスケーリングします。両方の主な目標は同じですが、Karpenter はノード管理のプロビジョニングとプロビジョニング解除に異なるアプローチを採用しているため、コストを削減し、クラスター全体の使用量を最適化できます。

クラスターのサイズが大きくなり、ワークロードの種類が増えるにつれて、ノードグループとインスタンスを事前設定することが困難になります。ワークロードリクエストと同様に、初期ベースラインを設定し、必要に応じて継続的に調整することが重要です。

Cluster Autoscaler を使用している場合、各 Auto Scaling グループ (ASG) の「最小」値と「最大」値を尊重し、「希望する」値のみを調整します。Cluster Autoscaler は「最小」数を超えて ASG をスケールダウンできないため、基盤となる ASG にこれらの値を設定するときは注意することが重要です。「希望する」カウントを通常の営業時間に必要なノード数として設定し、「最小」カウントを営業時間外に必要なノード数として設定します。Cluster Autoscaler のよくある質問ドキュメントを参照してください。

Cluster Autoscaler Priority Expander

Kubernetes Cluster Autoscaler は、ノードグループと呼ばれるノードのグループをスケールアップおよびスケールダウンすることで機能します。ワークロードを動的にスケーリングしていない場合、Cluster Autoscaler はコスト削減には役立ちません。Cluster Autoscaler では、ワークロードが消費されるように、クラスター管理者が事前にノードグループを作成する必要があります。ノードグループは、同じ「プロファイル」を持つインスタンス、つまり CPU とメモリのほぼ同じ量を使用するように設定する必要があります。

複数のノードグループを持つことができ、Cluster Autoscaler は優先度スケーリングレベルを設定するように設定でき、各ノードグループには異なるサイズのノードを含めることができます。ノードグループは異なるキャパシティタイプを持つことができ、優先度エクスパンダーを使用して、より安価なグループを最初にスケーリングできます。

以下は、 を使用してオンデマンドインスタンスを使用する前にリザーブドキャパシティConfigMap`に優先順位を付けるクラスター設定のスニペットの例です。同じ手法を使用して、他のタイプよりも Graviton インスタンスまたはスポットインスタンスに優先順位を付けることができます。

apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: my-cluster managedNodeGroups: - name: managed-ondemand minSize: 1 maxSize: 7 instanceType: m5.xlarge - name: managed-reserved minSize: 2 maxSize: 10 instanceType: c5.2xlarge
apiVersion: v1 kind: ConfigMap metadata: name: cluster-autoscaler-priority-expander namespace: kube-system data: priorities: |- 10: - .*ondemand.* 50: - .*reserved.*

ノードグループを使用すると、基盤となるコンピューティングリソースがデフォルトで期待されることを実行するのに役立ちます。たとえば、ノードを AZs に分散させるなどです。ただし、すべてのワークロードが同じ要件や期待値を持つわけではありません。アプリケーションに要件を明示的に宣言させることをお勧めします。Cluster Autoscaler の詳細については、「 のベストプラクティス」セクションを参照してください。

デスケジューラ

Cluster Autoscaler は、スケジュールする必要がある新しいポッドまたは十分に活用されていないノードに基づいて、クラスターからノード容量を追加および削除できます。ノードにスケジュールされた後、ポッド配置の完全リストビューは表示されません。Cluster Autoscaler を使用している場合は、クラスターの容量の浪費を避けるために、Kubernetes デスケジューラも参照する必要があります。

クラスターに 10 個のノードがあり、各ノードが 60% 使用されている場合、クラスター内のプロビジョニングされた容量の 40% を使用していません。Cluster Autoscaler を使用すると、ノードあたりの使用率しきい値を 60% に設定できますが、使用率が 60% を下回った後にのみ、1 つのノードをスケールダウンしようとします。

デスケジューラを使用すると、ポッドがスケジュールされた後、またはノードがクラスターに追加された後に、クラスターの容量と使用率を確認できます。クラスターの合計容量を指定されたしきい値以上に維持しようとします。また、ノードテイントまたはクラスターに参加する新しいノードに基づいてポッドを削除して、ポッドが最適なコンピューティング環境で実行されていることを確認することもできます。デスケジューラは削除されたポッドの置き換えをスケジュールしませんが、そのためにデフォルトのスケジューラに依存することに注意してください。

Karpenter の統合

Karpenter はノード管理に「グループレス」アプローチを採用しています。このアプローチは、さまざまなワークロードタイプに対してより柔軟であり、クラスター管理者の事前設定が少なくて済みます。Karpenter は、ワークロードのニーズに合わせてグループを事前定義し、各グループをスケーリングする代わりに、プロビジョナーとノードテンプレートを使用して、作成できる EC2 インスタンスのタイプと、作成時にインスタンスに関する設定を広く定義します。

ビンパッキングは、より多くのワークロードをより少ない最適なサイズのインスタンスにパッキングすることで、インスタンスのリソースをさらに活用する手法です。これにより、ワークロードが使用するリソースのみをプロビジョニングすることでコンピューティングコストを削減できますが、トレードオフがあります。特に大規模なスケーリングイベント中に、クラスターに容量を追加する必要があるため、新しいワークロードの開始に時間がかかる場合があります。ビンパッキングを設定するときは、コストの最適化、パフォーマンス、可用性のバランスを考慮してください。

Karpenter は、インスタンスリソースの使用率を向上させ、コンピューティングコストを削減するために、継続的にモニタリングとバイナリパックを行うことができます。Karpenter は、ワークロードによりコスト効率の高いワーカーノードを選択することもできます。これは、プロビジョナーで「統合」フラグを true にすることで実現できます (以下のサンプルコードスニペット)。以下の例は、統合を有効にするプロビジョナーの例を示しています。このガイドを書いている時点で、Karpenter は実行中のスポットインスタンスをより安価なスポットインスタンスに置き換えません。Karpenter の統合の詳細については、このブログを参照してください。

apiVersion: karpenter.sh/v1 kind: Provisioner metadata: name: enable-binpacking spec: consolidation: enabled: true

チェックポイントなしで長時間実行されるバッチジョブなど、中断できないワークロードの場合は、do-not-evict注釈でポッドに注釈を付けることを検討してください。ポッドをエビクションからオプトアウトすることで、Karpenter に、このポッドを含むノードを自発的に削除しないように指示します。ただし、ノードのドレイン中にdo-not-evictポッドがノードに追加された場合、残りのポッドは引き続き削除されますが、そのポッドは削除されるまで終了をブロックします。いずれの場合も、ノードは、ノードで追加の作業がスケジュールされないように接続されます。注釈の設定方法の例を次に示します。

8"" linenumbering="unnumbered">apiVersion: v1 kind: Pod metadata: name: label-demo labels: environment: production annotations: + "karpenter.sh/do-not-evict": "true" spec: containers: * name: nginx image: nginx ports: ** containerPort: 80

Cluster Autoscaler パラメータを調整して使用率の低いノードを削除する

ノード使用率は、リクエストされたリソースの合計を容量で割ったものとして定義されます。デフォルトでは、 scale-down-utilization-thresholdは 50% に設定されています。このパラメータは、 および とともに使用できます。これによりscale-down-unneeded-time、ノードがスケールダウンの対象となるまでに必要ない時間を決定します。デフォルトは 10 分です。スケールダウンされたノードでまだ実行されているポッドは、kube-scheduler によって他のノードでスケジュールされます。これらの設定を調整すると、十分に活用されていないノードを削除できますが、クラスターを強制的にスケールダウンしないように、まずこれらの値をテストすることが重要です。

削除にコストがかかるポッドが Cluster Autoscaler によって認識されるラベルによって保護されるようにすることで、スケールダウンの発生を防ぐことができます。これを行うには、削除にコストがかかるポッドに注釈 があることを確認しますcluster-autoscaler.kubernetes.io/safe-to-evict=false。以下は、注釈を設定するための yaml の例です。

8"" linenumbering="unnumbered">apiVersion: v1 kind: Pod metadata: name: label-demo labels: environment: production annotations: + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" spec: containers: * name: nginx image: nginx ports: ** containerPort: 80