Cluster Autoscaler - Amazon EKS

Cluster Autoscaler

Kubernetes の Cluster Autoscalerは、ポッドが失敗したり、他のノードに再スケジュールされた場合に、クラスター内のノード数を自動的に調整します。Cluster Autoscaler は、通常、クラスター内のデプロイとしてインストールされます。これはリーダー選挙を使用して高可用性を保証しますが、スケーリングは一度に 1 つのレプリカによって実行されます。

Cluster Autoscaler を展開する前に、Kubernetes のコンセプトが AWS の機能とどのようにインターフェイスで接続するかを理解していることが必要です。このトピックでは、次の用語を使用します。

  • Kubernetes Cluster Autoscaler – スケジューリングとスケーリングを決定する、Kubernetes コントロールプレーンの中核コンポーネントです。詳細については、GitHub の「Kubernetes Control Plane FAQ (Kubernetes コントロールプレーンに関するよくある質問)」を参照してください。。

  • AWS クラウドプロバイダーの実装 – Kubernetes Cluster Autoscaler の拡張機能で、AWS 製品やサービス (Amazon EC2 など) と通信することによって、Kubernetes Cluster Autoscaler の決定機能を実装します。詳細については、GitHub の「Cluster Autoscaler on AWS (AWS での Cluster Autoscaler)」を参照してください。

  • ノードグループ – クラスター内のノードグループの Kubernetes における抽象化です。ノードグループは真の Kubernetes リソースではありませんが、Cluster Autoscaler、クラスター API、およびその他のコンポーネント内に抽象化された形態で存在します。単一のノードグループ内に存在するノードは、ラベルやテイントなど、いくつかのプロパティを共有している場合があります。この場合も、複数のアベイラビリティーゾーンまたはインスタンスタイプで構成することはできます。

  • Amazon EC2 Auto Scaling グループ – Cluster Autoscaler によって使用される AWS の機能です。Auto Scaling グループは、ユースケースが多数におよぶ場合に適しています。Amazon EC2 Auto Scaling グループは、Kubernetes クラスターに自動的に参加するインスタンスを、起動するように構成されています。また、Kubernetes API 内の対応するノードリソースにラベルとテイントを適用します。

ちなみに マネージド型ノードグループ は、Amazon EC2 Auto Scaling グループを使用して管理されるものであり、Cluster Autoscalerとの互換性を持ちます。

このトピックでは、Cluster Autoscaler を Amazon EKS クラスターに デプロイする方法と、Amazon EC2 Auto Scaling グループを変更するために設定する方法について説明します。

Prerequisites

Cluster Autoscaler をデプロイする際には、以下の前提条件を満たしている必要があります。

  • 既存の Amazon EKS クラスターがある – クラスターがない場合は「Amazon EKS クラスターの作成」を参照してください。

  • クラスター用の既存 IAM OIDC プロバイダー。既に存在しているかどうかを確認する、または作成するには「クラスターの IAM OIDC プロバイダーを作成するには」を参照してください。

  • Auto Scaling グループタグの付いたノードグループ – Cluster Autoscaler では、Auto Scaling グループの自動検出を可能にするために、以下のタグを必要とします。

    • eksctl を使用してノードグループを作成している場合は、これらのタグが自動的に適用されています。

    • eksctl を使用しなかった場合は、Auto Scaling グループに以下のタグを手動でタグ付けする必要があります。詳細については、 Linux インスタンス用の Amazon EC2 ユーザーガイドの「Amazon EC2 リソースのタグ付け」を参照してください。

    キー
    k8s.io/cluster-autoscaler/<cluster-name>

    owned

    k8s.io/cluster-autoscaler/enabled TRUE

IAM ポリシーとロールを作成する

IAM ロールの使用の際に Cluster Autoscaler が必要とするアクセス許可を付与する IAM ポリシーを作成します。この手順全体を通して、<example-values> (<> を含む) はすべて、独自の値に置き換えます。

  1. IAM ポリシーを作成します。

    1. 次の内容を cluster-autoscaler-policy.json という名前のファイルに保存します。既存のノードグループが eksctl を使用して作成されており、その際に --asg-access オプションが指定されている場合には、このポリシーは既にに存在しているため、このままステップ 2 に進むことができます。

      { "Version": "2012-10-17", "Statement": [ { "Action": [ "autoscaling:DescribeAutoScalingGroups", "autoscaling:DescribeAutoScalingInstances", "autoscaling:DescribeLaunchConfigurations", "autoscaling:DescribeTags", "autoscaling:SetDesiredCapacity", "autoscaling:TerminateInstanceInAutoScalingGroup", "ec2:DescribeLaunchTemplateVersions" ], "Resource": "*", "Effect": "Allow" } ] }
    2. 次のコマンドを使用してポリシーを作成します。policy-name の値は変更することが可能です。

      aws iam create-policy \ --policy-name AmazonEKSClusterAutoscalerPolicy \ --policy-document file://cluster-autoscaler-policy.json

      出力で返される Amazon リソースネーム (ARN) を書き留めます。ID は後の手順で使用する必要があります。

  2. eksctl または AWS Management Console を使用しながら IAM ロールを作成して、そのロールに IAM ポリシーをアタッチすることができます。次の手順で目的のタブを選択します。

    eksctl
    1. eksctl を使用して Amazon EKS クラスターを作成している場合は、次のコマンドを実行します。--asg-access オプションを指定しながらノードグループを作成している場合には、<AmazonEKSClusterAutoscalerPolicy> を、eksctl により作成された IAM ポリシーの名前に置き換えます。このポリシー名は、例えば次のようになります: eksctl-<cluster-name>-nodegroup-ng-<xxxxxxxx>-PolicyAutoScaling

      eksctl create iamserviceaccount \ --cluster=<my-cluster> \ --namespace=kube-system \ --name=cluster-autoscaler \ --attach-policy-arn=arn:aws:iam::<AWS_ACCOUNT_ID>:policy/<AmazonEKSClusterAutoscalerPolicy> \ --override-existing-serviceaccounts \ --approve
    2. --asg-access オプションを指定しながらノードグループを作成した場合は、この IAM ポリシーをデタッチすることをお勧めします (このポリシーは、eksctl により作成され、ノードグループ用に eksctl が作成した Amazon EKS ノードの IAM ロール に対しアタッチされています)。クラスター自動スケーラーが正しく機能するように、ノード IAM ロールからポリシーをデタッチします。ポリシーをデタッチしても、ノード上の他の Pod にポリシーのアクセス権限が付与されることはありません。詳細については、Linux インスタンス用の Amazon EC2 ユーザーガイドの「IAM ID アクセス許可の削除」を参照してください。

    AWS Management Console
    1. https://console.aws.amazon.com/iam/ で IAM コンソールを開きます。

    2. ナビゲーションペインで [Roles (ロール)]、[Create Role (ロールを作成)] の順に選択します。

    3. [Select type of trusted entity (信頼されたエンティティの種類を選択)] セクションで、[Web identity (ウェブ ID)] を選択します。

    4. [Choose a web identity provider (ウェブ ID プロバイダーを選択)] セクションで、次の操作を行います。

      1. ID プロバイダーで、Amazon EKS クラスターの URL を選択します。

      2. [Audience (対象者)] で [sts.amazonaws.com] を選択します。

    5. [Next: Permissions (次へ: アクセス許可)] を選択します。

    6. [Attach Policy (ポリシーのアタッチ)] セクションで、サービスアカウントで使用するために、ステップ 1 で作成した AmazonEKSClusterAutoscalerPolicy ポリシーを選択します。

    7. [次へ: タグ] を選択します。

    8. [Add tags (optional) (タグの追加 (オプション))] 画面で、アカウントのタグを追加できます。[Next: Review] を選択します。

    9. [Role Name (ロール名)] に、ロールの名前 (AmazonEKSClusterAutoscalerRole など) を入力し、[Create Role (ロールを作成)] を選択します。

    10. ロールが作成されたら、コンソールでロールを選択して編集用に開きます。

    11. [Trust relationships] タブを選択し、続いて [Edit trust relationship] を選択します。

    12. 次のように表示されます。

      "oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E:aud": "sts.amazonaws.com"

      これを次の行のように変更します。<EXAMPLED539D4633E53DE1B716D3041E> (<> を含む) をクラスターの OIDC プロバイダー ID に置き換え、<region-code> はクラスターがあるリージョンコードに置き換えます。

      "oidc.eks.<region-code>.amazonaws.com/id/<EXAMPLED539D4633E53DE1B716D3041E>:sub": "system:serviceaccount:kube-system:cluster-autoscaler"
    13. [Update Trust Policy (信頼ポリシーの更新)] を選択して終了します。

Cluster Auto Scaling をデプロイする

Cluster Autoscaler をデプロイするには、以下の手順を完了します。実稼働段階のクラスターに Cluster Autoscaler をデプロイする前に、デプロイに関する考慮事項 を確認した上で、デプロイを最適化することをお勧めします。

Cluster Auto Scaling をデプロイするには

  1. Cluster Autoscaler をデプロイする

    kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
  2. cluster-autoscaler サービスアカウントを、先に作成した IAM ロールの ARN に対しアノテートします。<example values> は独自の値に置き換えます。

    kubectl annotate serviceaccount cluster-autoscaler \ -n kube-system \ eks.amazonaws.com/role-arn=arn:aws:iam::<ACCOUNT_ID>:role/<AmazonEKSClusterAutoscalerRole>
  3. 次のコマンドを使用して、cluster-autoscaler.kubernetes.io/safe-to-evict のアノテーションを Cluster Autoscaler ポッドに追加するうように、デプロイにパッチを適用します。

    kubectl patch deployment cluster-autoscaler \ -n kube-system \ -p '{"spec":{"template":{"metadata":{"annotations":{"cluster-autoscaler.kubernetes.io/safe-to-evict": "false"}}}}}'
  4. 次のコマンドを使用して Cluster Autoscaler デプロイを編集します。

    kubectl -n kube-system edit deployment.apps/cluster-autoscaler

    cluster-autoscaler コンテナのコマンドを編集して、<YOUR CLUSTER NAME> (<> を含む) をクラスター名に置き換え、以下のオプションを追加します。

    • --balance-similar-node-groups

    • --skip-nodes-with-system-pods=false

    spec: containers: - command: - ./cluster-autoscaler - --v=4 - --stderrthreshold=info - --cloud-provider=aws - --skip-nodes-with-local-storage=false - --expander=least-waste - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/<YOUR CLUSTER NAME> - --balance-similar-node-groups - --skip-nodes-with-system-pods=false

    ファイルを保存して閉じ、変更を適用します。

  5. ウェブブラウザで、GitHub の Cluster Autoscaler リリースページを開き、最新の (クラスターの Kubernetes のメジャーおよびマイナーバージョンに一致する) Cluster Autoscaler バージョンを見つけます。ととえば、クラスターの Kubernetes バージョンが 1.21 の場合、1.21 で始まる Cluster Autoscaler リリースを見つけます。次のステップで使用するので、そのリリースのセマンティックバージョン番号 (1.21.n) を書き留めておきます。

  6. 次のコマンドを使用して、Cluster Autoscaler イメージタグを、前のステップで書き留めたバージョンに設定します。1.21.n を独自の値に置き換えます。

    kubectl set image deployment cluster-autoscaler \ -n kube-system \ cluster-autoscaler=k8s.gcr.io/autoscaling/cluster-autoscaler:v<1.21.n>

Cluster Autoscaler ログを表示する

Cluster Autoscaler をデプロイしたら、ログを表示してクラスターの負荷をモニタリングしていることを確認できます。

次のコマンドを使用して Cluster Autoscaler ログを表示します。

kubectl -n kube-system logs -f deployment.apps/cluster-autoscaler

出力は次のとおりです。

I0926 23:15:55.165842 1 static_autoscaler.go:138] Starting main loop I0926 23:15:55.166279 1 utils.go:595] No pod using affinity / antiaffinity found in cluster, disabling affinity predicate for this loop I0926 23:15:55.166293 1 static_autoscaler.go:294] Filtering out schedulables I0926 23:15:55.166330 1 static_autoscaler.go:311] No schedulable pods I0926 23:15:55.166338 1 static_autoscaler.go:319] No unschedulable pods I0926 23:15:55.166345 1 static_autoscaler.go:366] Calculating unneeded nodes I0926 23:15:55.166357 1 utils.go:552] Skipping ip-192-168-3-111.<region-code>.compute.internal - node group min size reached I0926 23:15:55.166365 1 utils.go:552] Skipping ip-192-168-71-83.<region-code>.compute.internal - node group min size reached I0926 23:15:55.166373 1 utils.go:552] Skipping ip-192-168-60-191.<region-code>.compute.internal - node group min size reached I0926 23:15:55.166435 1 static_autoscaler.go:393] Scale down status: unneededOnly=false lastScaleUpTime=2019-09-26 21:42:40.908059094 ... I0926 23:15:55.166458 1 static_autoscaler.go:403] Starting scale down I0926 23:15:55.166488 1 scale_down.go:706] No candidates for scale down

デプロイに関する考慮事項

Cluster Autoscaler のデプロイを最適化するために、次の考慮事項を確認してください。

スケーリングに関する考慮事項

Cluster Autoscaler は、ノードの追加機能に対応するように構成できます。これらの機能には、ノードにアタッチされた Amazon EBS ボリューム、ノードの Amazon EC2 インスタンスタイプ、または GPU アクセラレータが含まれます。

複数のアベイラビリティーゾーンにまたがるノードグループのスコープ

複数のノードグループを構成し、各グループで 1 つのアベイラビリティーゾーンにスコープし、--balance-similar-node-groups 機能を有効化することをお勧めします。ノードグループを 1 つだけ作成する場合には、そのノードグループを複数のアベイラビリティーゾーンにまたがるようにスコープします。

ノードグループの最適化

Cluster Autoscaler は、ノードグループの使用方法について仮定します。これには、グループ内で使用するインスタンスタイプが含まれます。これらの推定結果に合致させるために、次の考慮事項や推奨事項に基づいてノードグループを構成します。

  • ノードグループ内の各ノードは、同一のスケジューリングプロパティを持つ必要があります。これには、ラベル、汚染、およびリソースが含まれます。

    • MixedInstancePolicies については、インスタンスタイプには互換性のある CPU、メモリ、および GPU 仕様が必要です。

    • ポリシーで指定された最初のインスタンスタイプが、スケジューリングをシミュレートします。

    • ポリシーに、より多くのリソースを使用する追加のインスタンスタイプが含まれている場合、スケールアウト後に、これらのリソースが無駄になる可能性があります。

    • ポリシーに、元のインスタンスタイプよりも少ないリソースを使用する追加のインスタンスタイプが含まれる場合、ポッドがインスタンスでのスケジュールに失敗することがあります。

  • ノードグループの数を減らしてグループごとのノードの数を増やすように構成してください。反対の構成ではスケーラビリティに悪影響を及ぼす可能性があります。

  • 両方のシステムがサポートしているときはいつでも Amazon EC2 の機能を使用してください (例: リージョンと MixedInstancePolicy。)

可能な限り、マネージド型ノードグループ の使用をお勧めします。マネージド型ノードグループには、強力な管理機能が付属しています。これには、Amazon EC2 Auto Scaling グループの自動検出やノードの正常な終了など、Cluster Autoscaler の機能が含まれます。

EBS ボリュームを永続的ストレージとして使用する

永続的ストレージは、データベースや分散キャッシュなどのステートフルなアプリケーションを構築するために重要です。Amazon EBS ボリュームを使用すると、Kubernetes でステートフルなアプリケーションを構築できます。ただし、構築は単一のアベイラビリティーゾーンに制限されます。詳細については、「Amazon EKS で永続的ストレージを使用する方法を教えてください。」を参照してください。より良いソリューションとして、アベイラビリティーゾーンごとに別々の Amazon EBS ボリュームを使用して、複数のアベイラビリティーゾーンにまたがってシャードされるステートフルなアプリケーションの構築を検討してください。これでアプリケーションの可用性が高くなります。さらに、Cluster Autoscalerは Amazon EC2 Auto Scaling グループ間のスケーリングでバランスをとることができます。これを実現するには、以下の条件が満たされていることを確認してください。

  • balance-similar-node-groups=true を設定することで、ノードグループのバランシングが有効化されている。

  • ノードグループは同じ内容で設定されています (複数のアベイラビリティーゾーンに存在し、異なる Amazon EBS ボリュームを使用する以外)。

共同スケジューリング

機械学習の分散型トレーニングジョブでは、共通のゾーンを使用するノード構成によりレイテンシーを最小化できるので、大きなメリットが得られます。これらのワークロードは、複数のポッドを特定のゾーンにデプロイします。そのためには、topologyKey: topology.kubernetes.io/zone を使用して同じスケジュールを持つすべてのポッドのアフィニティを設定するか、もしくはノードのアフィニティを設定します。この構成を使用して、Cluster Autoscaler は要求に合わせて特定のゾーンをスケールアウトします。複数の Amazon EC2 Auto Scaling グループを、1 つずつアベイラビリティーゾーンごとに割り当てて、共同スケジュールされたワークロード全体のフェイルオーバーを有効にします。この場合は、以下の条件が満たされていることを確認してください。

  • balance-similar-node-groups=true を設定することで、ノードグループのバランシングが有効化されている。

  • ノードのアフィニティ、もしくはポッドプリエンプション、またはその両方は、クラスターにリージョン的なノードグループならびにゾーン的なノードグループの両方が含まれる場合に使用されます。

    • ノードのアフィニティを使用して、リージョン的なポッドを強制または奨励することで、ゾーン的なノードグループを回避することができます。

    • リージョン的なノードグループにゾーン的なポッドをスケジュールしないでください。リージョン的なノードの容量が不均衡になる可能性があります。

    • ゾーン的なワークロードが中断や再配置に対応できる場合は、ポッドのプリエンプションを構成します。これにより、地域的にスケーリングされたポッドに対して、競合の少ないゾーンでのプリエンプションと再スケジュールが実施されます。

アクセラレータとGPU

クラスターによっては、専用 GPU などの特殊なハードウェアアクセラレーターを利用するものもあります。スケールアウトが行われた場合、アクセラレーターがリソースをクラスターにアドバタイズするのに、数分かかることがあります。この期間中、Cluster Autoscaler は、このノードにアクセラレーターがあることをシミュレートします。ただし、アクセラレーターの準備が完了し、ノードで使用可能なリソースが更新されるまで、保留中のポッドをノード上でスケジュールすることはできません。これは、不要なスケールアウトが繰り返されることにつがなります。

アクセラレーターを搭載し、CPU またはメモリ使用率が高いノードは、そのアクセラレーターが使用されていない場合でもスケールダウンの対象にはなりません。ただし、不必要なコストにつながる可能性はあります。Cluster Autoscaler では、こういったコストを回避するための特別なルールを適用して、使用されていないアクセラレーターがあるノードを、スケールダウンの対象に含めることができます。

これらのケースにおける正しい動作を保証するために、アクセラレーターノードで kubelet を構成することで、クラスターに加わる前のノードにラベルを付けます。Cluster Autoscaler は、このラベルセレクタを使用してアクセラレーターに最適化された動作を呼び出します。この場合は、以下の条件が満たされていることを確認してください。

  • GPU ノードの kubelet--node-labels k8s.amazonaws.com/accelerator=$ACCELERATOR_TYPE に設定されている。

  • アクセラレーターを持つ各ノードは、同じスケジューリングプロパティルールに従っている。

ゼロからのスケーリング

Cluster Autoscaler は、ノードグループをゼロにスケーリングできます。これによりコストを大幅に削減できる可能性があります。Cluster Autoscaler が、Auto Scaling グループの CPU、メモリ、および GPU の各リソースは、LaunchConfiguration または LaunchTemplate で指定されている InstanceType を調査することで検出します。WindowsENI または PrivateIPv4Address のような追加リソースを必要とするポッドもあります。または、特定のNodeSelectors あるいは Taints を必要とするポッドもあります。最後の 2 つは LaunchConfiguration では見つけられません。ただし、Cluster Autoscaler では、これらの要因を Auto Scaling グループの次のようなタグから検出することで、それに対応しています。

Key: k8s.io/cluster-autoscaler/node-template/resources/$RESOURCE_NAME Value: 5 Key: k8s.io/cluster-autoscaler/node-template/label/$LABEL_KEY Value: $LABEL_VALUE Key: k8s.io/cluster-autoscaler/node-template/taint/$TAINT_KEY Value: NoSchedule
注記
  • ゼロにスケーリングすると、使用していた容量が Amazon EC2 に戻されるので、将来使用できなくなる可能性があります。

  • DescribeNodeGroup を使用して、ゼロへのスケーリングおよびゼロからのスケーリング時に管理対象ノードグループの問題を診断できます。

その他の設定パラメータ

Cluster Autoscaler には、動作とパフォーマンスを調整するために使用できる多くの設定オプションが用意されています。パラメータの詳細なリストについては、GitHub の「What are the parameters to CA? (CAのためのパラメータとは何ですか?)」を参照してください。

パフォーマンスに関する考慮事項

Cluster Autoscaler のパフォーマンスとスケーラビリティを調整するために変更できる重要な項目がいくつかあります。主なものは、プロセスに提供されるすべてのリソース、アルゴリズムのスキャン間隔、およびクラスタ内のノードグループ数です。しかし、このアルゴリズムの真のランタイムの複雑さに関与するいくつかの他の要因もあります。これには、プラグインの複雑さのスケジューリングとポッドの数が含まれます。これらのパラメーターは、クラスターのワークロードの本質に関係しており容易に調整できないため、構成できないパラメーターとして認識されています。

スケーラビリティは、Kubernetes クラスター内のポッドとノードの数が増加するにつれて、Cluster Autoscaler がどの程度うまく機能するかを表します。スケーラビリティのクォータが上限に達すると、Cluster Autoscaler のパフォーマンスと機能性が低下します。さらに、スケーラビリティのクォータを超えた場合には、Cluster Autoscaler はクラスター内のノードの追加または削除を実行できなくなります。

パフォーマンスは、Cluster Autoscaler が、いかに速くスケーリングに関する決定を下し実装できるのかを示します。完全に動作している Cluster Autoscaler では、ポッドのスケジューリングが不能になるなどの特定条件では即座に決定を行い、スケーリングアクションを呼び出します。

自動スケーリングアルゴリズムのランタイムの複雑さを理解することが必要です。より大規模なクラスタ (1,000 ノード) のオペレーションに対して Cluster Autoscaler をチューニングしやすくなります。

Cluster Autoscaler は、クラスター全体の状態をメモリにロードします。これにはポッド、ノード、およびノードグループが含まれます。各スキャン間隔中、このアルゴリズムによりスケジュール不能なポッドが識別され、各ノードグループのためにスケジューリングがシミュレートされます。これらの要因をさまざまな方法でチューニングすると、引き換えに他で変更が必要になる場合があることを理解しておいてください。

垂直的自動スケーリング

Cluster Autoscaler は、デプロイのリソースに対するリクエストを増やすことで大規模なクラスタにスケーリングできます。これは最も簡単な方法の1つです。大規模なクラスターに合わせてメモリと CPU の両方を増やします。メモリと CPU をどれだけ増やすべきかは、特定のクラスターサイズによって大きく変わってきます。オートスケーリングのアルゴリズムでは、すべてのポッドとノードがメモリに格納されています。これにより、メモリフットプリントが 1 GB を超える場合があります。通常、リソースは手動で増やす必要があります。リソースを手動で増やさなければならない回数が多い場合は、アドオンリサイザーまたは Vertical Pod Autoscaler を使用してプロセスを自動化します。

ノードグループの数を減らす

ノードグループの数を減らして、大規模なクラスタでの Cluster Autoscaler のパフォーマンスを向上させることができます。個々のチームまたはアプリケーションベースでノードグループを構造化する場合には、この作業は難しいかもしれません。Kubernetes API には、このための完全なサポートが用意されていますが、これはスケーラビリティに影響を与え得る、反 Cluster Autoscaler のパターンだと考えられます。たとえば、スポットインスタンスと GPU インスタンスの両方を使用する複数のノードグループを使用することには、多くの利点があります。そして多くの場合は、少数のグループを使用しながら同じ効果を達成できる、代替的な設計法が存在します。この場合は、以下の条件が満たされていることを確認してください。

  • ノードグループではなく名前空間を使用して、ポッドを分離している。

    • 低信頼マルチテナントクラスターでは、この操作を実行できないことがあります。

    • ポッド の ResourceRequestsResourceLimits を適切に設定し、リソースの競合を回避します。

    • インスタンスタイプを大きくするほどビンのパッキングが最適に行え、システムポッドのオーバーヘッドが軽減されます。

  • ポッドのスケジューリングに NodeTaintsNodeSelectors は使用しないでください。これらは限られた基準でのみ使用してください。

  • リージョンごとのリソースを、複数のアベイラビリティーゾーンを持つ 1 つの Amazon EC2 Auto Scaling グループとして定義します。

スキャン間隔の短縮

スキャン間隔を (10 秒のデフォルト設定など) 短くすることで、ポッドがスケジューリング不能になった際には、Cluster Autoscaler が可能な限り迅速に応答できます。ただし、各スキャンでは、Kubernetes API と Amazon EC2 Auto Scaling グループ、または Amazon EKS マネージド型ノードグループ API への、多数の API 呼び出しが発生します。これらの API 呼び出しにより、Kubernetes コントロールプレーンでレート制限が発生したり、サービスが利用できなくなることさえあります。

デフォルトのスキャン間隔は 10 秒ですが、AWS では、ノードの起動時に新しいインスタンスを起動するために、それより大幅に長い時間が必要です。つまり、全体的なスケールアップ時間を大幅に増やすことなく、スキャン間隔を増やすことが可能だということです。例えば、ノードの起動に 2 分かかる場合、間隔は 1 分に変更できません。変更すると API 呼び出しが 6 倍減少するのに対し、スケールアップが 38% 遅くなるというトレードオフになります。

ノードグループ間のシャーディング

Cluster Autoscaler は、特定のノードグループのセットで動作するように構成できます。この機能を使用すると、Cluster Autoscaler の複数のインスタンスをデプロイできます。異なるノードグループのセットで動作するように各インスタンスを設定します。任意に多数のノードグループを使用することができるようになり、スケーラビリティとコストの間のトレードオフを図れます。ただし、この手段は Cluster Autoscaler のパフォーマンスを向上させるための最後の手段としてのみ行うことをお勧めします。

この構成には欠点があります。複数のノードグループから不要なスケールアウトが発生する可能性があります。余分なノードは、scale-down-delay の後にスケールバックします。

metadata: name: cluster-autoscaler namespace: cluster-autoscaler-1 ... --nodes=1:10:k8s-worker-asg-1 --nodes=1:10:k8s-worker-asg-2 --- metadata: name: cluster-autoscaler namespace: cluster-autoscaler-2 ... --nodes=1:10:k8s-worker-asg-3 --nodes=1:10:k8s-worker-asg-4

以下の条件に該当することを確認します。

  • 各シャードは、Amazon EC2 Auto Scaling グループの一意のセットを指すように設定されている。

  • リーダー選挙での競合を避けるために、各シャードは別々の名前空間にデプロイされている。

コスト効率と可用性

Cluster Autoscaler のコスト効率を調整するための主なオプションは、Amazon EC2 インスタンスのプロビジョニングに関連しています。さらに、コスト効率は可用性とバランスをとる必要があります。このセクションでは、スポットインスタンスを使用したコストの削減方法、ならびに、オーバープロビジョニングを使用しての、新しいノード作成時のレイテンシーの低減方法などの戦略について説明します。

  • アベイラビリティー – ポッドは、中断することなく迅速にスケジューリングが可能です。これは、新しく作成されたポッドでスケジューリングが必要な場合や、スケールダウンされたノードが、それにスケジューリングされた残りのポッドを終了する場合にも当てはまります。

  • コスト – スケールアウトおよびスケールインのイベントの背後の要素で決定されます。既存のノードが十分に活用されていない場合や、受信ポッドには大きすぎる新しいノードが追加された場合、リソースが無駄になります。特定のユースケースによっては、積極的にスケールダウンが決定されることで、ポッドの早期終了に伴うコストが発生することがあります。

スポットインスタンス

ノードグループでスポットインスタンスを使用すると、オンデマンド料金から最大 90% の割引が得られます。これには、Amazon EC2 が容量を取り戻す必要がある場合に、いつでもスポットインスタンスが中断される可能性があるというトレードオフが存在します。 使用可能な容量が不足しているために Amazon EC2 Auto Scaling グループがスケールアップできない場合には、任意のタイミングで Insufficient Capacity Errors が発生します。さまざまなインスタンスファミリーを選択できることには、主に 2 つの利点があります。第 1 に、多くのスポット容量プールを利用することで、希望するスケールを達成する機会を増やすことができます。第 2 に、スポットインスタンスの中断によるクラスターの可用性への影響も低減できます。スポットインスタンスにより多種類のインスタンスポリシーを使用することは、ノードグループの数を増やすことなく多様性を高める優れた方法です。ただし、保証されたリソースが必要な場合は、スポットインスタンスではなくオンデマンドインスタンスを使用してください。

スポットインスタンスは、インスタンスの需要が増加したときに終了することがあります。詳細については、Amazon EC2 Linux インスタンス用ユーザーガイドの「スポットインスタンス中断」を参照してください。AWS ノード終了ハンドラープロジェクトは、ノードがダウンすると自動的に Kubernetes コントロールプレーンに警告を発します。このプロジェクトは、Kubernetes API を使用してノードを遮断し、そこで新しい作業がスケジュールされていないことを確認した上で廃棄を行い、また既存の作業の削除も行います。

混在インスタンスポリシーの設定時には、すべてのインスタンスタイプが同様のリソース容量を持つことが重要です。Autoscaler のスケジューリングシミュレータは、混成インスタンスポリシーにある、最初のインスタンスタイプを使用します。後続に、より大きなインスタンスタイプがある場合、スケールアップ後にリソースが浪費される可能性があります。インスタンスがより小さい場合には、容量不足のために、ポッドは新しいインスタンスでのスケジュールに失敗することがあります。例えば、M4M5M5a,、および M5n インスタンスはすべて CPU とメモリの量が似ており、混成インスタンスポリシーの候補として最適です。Amazon EC2 Instance Selector ツールは、類似したインスタンスタイプを識別するのに役立ちます。詳細については、GitHub の「Amazon EC2 Instance Selector」を参照してください。

オンデマンドインスタンス容量とスポットインスタンス容量は、別々の Amazon EC2 Auto Scaling グループに分離することをお勧めします。これは、基本容量戦略を使用することよりも推奨されます。オンデマンドインスタンスとスポットインスタンスでは、それぞれスケジューリングプロパティが異なるためです。スポットインスタンスはいつでも中断できます。Amazon EC2 が容量を取り戻す必要がある場合、プリエンプティブノードがしばしばテイントされるため、ポッドには、プリエンプション動作に対する明示的な許容力が必要になります。これが、ノードのスケジューリングプロパティが異っている理由です。つまり、複数の Amazon EC2 Auto Scaling グループに分割する必要が生じます。

Cluster Autoscaler は、エキスパンダー の概念と関係があります。これらにより、スケールするノードグループを選択するためのさまざまな戦略が、集約的に提供されます。戦略 --expander=least-waste は、平均的な汎用デフォルト設定です。前述のように、スポットインスタンスの多様化に対応し複数のノードグループを使用する場合は、スケーリングアクティビティの後に最適に活用されるようにグループをスケーリングすることで、ノードグループのコストをさらに最適化できます。

ノードグループまたは Auto Scaling グループの優先順位付け

Priority エクスパンダを使用すると、プライオリティベースのオートスケーリングを設定することもできます。--expander=priority を指定することで、クラスターがノードグループまたは Auto Scaling グループの優先付けを行います 。何らかの理由でスケーリングができない場合は、優先順位リスト上で次のノードグループが選択されます。これは、GPU が提供するパフォーマンスがワークロードに最適なため、P3 インスタンスタイプを使用したいと思うものの、もう 1 つのオプションとして P2 インスタンスタイプも用意しておく、といった場合に便利です。以下に例を示します。

apiVersion: v1 kind: ConfigMap metadata: name: cluster-autoscaler-priority-expander namespace: kube-system data: priorities: |- 10: - .*p2-node-group.* 50: - .*p3-node-group.*

Cluster Autoscaler は、名前が p3-node-group と一致する Amazon EC2 Auto Scaling グループのスケールアップを試みます。このオペレーションが --max-node-provision-time の間に正常に完了しなかった場合は、名前が p2-node-group と一致する Amazon EC2 Auto Scaling グループのスケーリングが試行されます。この値はデフォルトで 15 分に設定されており、応答性の高いノードグループではこの値を減らすこともできます。ただし、値が低すぎると、不要なスケールアウトが発生する可能性があります。

Overprovisioning

Cluster Autoscaler は、必要性がある場合にのみノードがクラスタに追加され、使用されなくなった際には削除されるようにすることで、コストを最小限に抑える手助けをします。この構成では、スケジューリングされる前の多くのポッドが、ノードのスケールアップを待たざるを得ないため、デプロイのレイテンシーに大きな影響を与えます。ノードが使用可能になるまでに数分かかることがあり、ポッドのスケジューリングのレイテンシーが桁違いに増加する可能性があります。

この問題は、オーバープロビジョニングにより、スケジューリングのレイテンシーをコストとトレードオフすることで緩和できます。オーバープロビジョニングは、負の優先順位を持つ一時的なポッドを使用して実装されます。これらのポッドは、クラスター内のスペースを占有します。新しく作成された優先順位の高いポッドがスケジュール不可能な場合、一時的なポッドがプリエンプトされ配置されます。その後、一時的なポッドがスケジュール不能になった場合に、Cluster Autoscaler は、オーバープロビジョニングされた新しいノードをスケールアウトします。

オーバープロビジョニングには他にも利点があります。オーバープロビジョニングを行わなければ、使用率の高いクラスターにあるポッドでは、最適なスケジューリングの (preferredDuringSchedulingIgnoredDuringExecution ルールを使用した) 決定が難しくなります。一般的にこのようなユースケースは、高い可用性が必要なアプリケーションのために、AntiAffinity を使用して、ポッドをアベイラビリティーゾーン間で分離する場合があてはまります。オーバープロビジョニングにより、目的のゾーンでノードが使用可能状態である可能性を、大幅に高めることができます。

オーバープロビジョニングの程度は適切に選ぶことが重要です。適切な量を選択できる 1 つの方法として、平均スケールアップ頻度を取り、これを新しいノードをスケールアップするのにかかる時間で割る方法があります。例えば、平均して 30 秒ごとに新しいノードが必要で、Amazon EC2 が新しいノードのプロビジョニングするのに 30 秒かかる場合、オーバープロビジョニングにより、常に使用可能な追加のノードが 1 つ待機していることが保証されます。これにより、追加の Amazon EC2 インスタンスを 1 つ用意するコストで、スケジューリングのレイテンシーを 30 秒短縮できます。また、Amazon EC2 Auto Scaling グループのアベイラビリティーゾーン数とノード数が等しくなるようにオーバープロビジョニングすることで、ゾーンスケジューリングの決定を改善できます。これにより、スケジューラが受信ポッドに最適なゾーンを選択できるようになります。

スケールダウンの削除の防止

一部のワークロードでは、削除にコストがかかります。ビッグデータ分析、機械学習タスク、およびテストランナーは、完了までに長い時間がかかることがあり、中断した場合の再起動も必要です。Cluster Autoscaler 機能は、scale-down-utilization-threshold の状態のノードをスケールダウンの手助けをします。これにより、ノード上の残りのポッドがすべて中断されます。ただし、削除にコストがかかるポッドを保護するために、Cluster Autoscaler で認識可能なラベルをそのポッドに付けることで、中断を防ぐことができます。これを行うには、削除にコストがかかるポッドに cluster-autoscaler.kubernetes.io/safe-to-evict=false のラベルを付けます。