Autoscaling - Amazon EKS

Autoscaling

オートスケーリングとは、需要の変化に合わせてリソースを自動的に増減させる機能です。これは Kubernetes の主要な機能であり、この機能がなければ、手動で実行するために膨大な人的リソースが必要になります。

Amazon EKS は 2 つのオートスケーリング製品をサポートしています。Kubernetes の [Cluster Autoscaler] (クラスターオートスケール) と [Karpenter] (カーペンター) はオープンソースのオートスケーリングプロジェクトです。クラスターオートスケーラーは AWS のスケーリンググループを使用しますが、Karpenter は Amazon EC2 フリートで直接動作します。

Cluster Autoscaler

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

Cluster Autoscaler をデプロイする前に、Kubernetes のコンセプトが AWS の機能とどのようにインターフェイスするかを把握している必要があります。このトピックでは、次の用語を使用します。

  • Kubernetes Cluster Autoscaler - スケジューリングとスケーリングを決定する、Kubernetes コントロールプレーンの主要なコンポーネント。詳細については、「GitHub」の「Kubernetes コントロールプレーンのよくある質問」を参照してください。

  • AWS クラウドプロバイダーの実装 - Kubernetes Cluster Autoscaler の拡張機能で、AWS 製品やサービス (Amazon EC2 など) と通信することによって、Kubernetes Cluster Autoscaler の決定機能を実装します。詳細については、「GitHub」の「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 グループを変更するために設定する方法について説明します。

前提条件

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

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

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

  • Auto Scaling グループのタグのついたノードグループ。Cluster Auto Scaling で自動検を実行するには、Auto Scaling グループに以下のタグが必要です。

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

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

    キー
    k8s.io/cluster-autoscaler/my-cluster

    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": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "autoscaling:SetDesiredCapacity", "autoscaling:TerminateInstanceInAutoScalingGroup" ], "Resource": "*", "Condition": { "StringEquals": { "aws:ResourceTag/k8s.io/cluster-autoscaler/my-cluster": "owned" } } }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": [ "autoscaling:DescribeAutoScalingInstances", "autoscaling:DescribeAutoScalingGroups", "ec2:DescribeLaunchTemplateVersions", "autoscaling:DescribeTags", "autoscaling:DescribeLaunchConfigurations", "ec2:DescribeInstanceTypes" ], "Resource": "*" } ] }
    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-my-cluster-nodegroup-ng-xxxxxxxx-PolicyAutoScaling

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

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

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

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

    4. [Web identity] (ウェブ アイデンティティ) セクションで、以下の操作を実行します。

      1. [Identity provider] (アイデンティティプロバイダー) で、クラスターの [OpenID Connect provider URL] ( プロバイダー URL) を選択します (Amazon EKS のクラスター [Overview] (概要) タブに表示されます)。

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

    5. [Next] (次へ) をクリックします。

    6. [Filter policies] (フィルタポリシー) ボックスに AmazonEKSClusterAutoscalerPolicy と入力します。次に、検索で返されたポリシー名の左側にあるチェックボックスを選択します。

    7. [Next] (次へ) をクリックします。

    8. [Role name] (ロール名) に、AmazonEKSClusterAutoscalerRole などのロールの一意の名前を入力します。

    9. [Description] (説明) には、Amazon EKS - Cluster autoscaler role のような説明文を入力します。

    10. [Create role] (ロールの作成) を選択します。

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

    12. [Trust relationships] (信頼関係) タブを選択し、続いて [Edit trust policy] (信頼ポリシーの編集) を選択します。

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

      "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"

      これを次の行のように変更します。EXAMPLED539D4633E53DE1B71EXAMPLE をクラスターの OIDC プロバイダー ID に置き換えます。region-code をクラスターのある AWS リージョン に置き換えます。

      "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:kube-system:cluster-autoscaler"
    14. [Update policy] (ポリシーの更新) を選択して終了します。

Cluster Auto Scaling をデプロイする

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

Cluster Auto Scaling をデプロイするには
  1. Cluster Autoscaler の YAML ファイルをダウンロードします。

    curl -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
  2. YAML ファイルを編集し、その中の <YOUR CLUSTER NAME> の部分を、使用するクラスターの名前に置き換えます。また、cpu および memory を、ご使用の環境によって決まる値に置き換えることも検討してください。

  3. YAML ファイルをクラスターに適用します。

    kubectl apply -f cluster-autoscaler-autodiscover.yaml
  4. 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
  5. 次のコマンドを使用して、cluster-autoscaler.kubernetes.io/safe-to-evict のアノテーションを Cluster Autoscaler pods に追加するうように、デプロイにパッチを適用します。

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

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

    cluster-autoscaler コンテナコマンドを編集し、以下のオプションを追加します。--balance-similar-node-groups は、すべてのアベイラビリティーゾーンに使用可能な計算能力が十分にあることを保証します。--skip-nodes-with-system-pods=false は、ゼロへのスケーリングが問題なく行えることを保証します。

    • --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/my-cluster - --balance-similar-node-groups - --skip-nodes-with-system-pods=false

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

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

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

    kubectl set image deployment cluster-autoscaler \ -n kube-system \ cluster-autoscaler=registry.k8s.io/autoscaling/cluster-autoscaler:v1.26.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 つだけ作成する場合には、そのノードグループを複数のアベイラビリティーゾーンにまたがるようにスコープします。

--balance-similar-node-groups を true に設定するときは、Cluster Autoscaler でバランス調整するノードグループに、一致するラベル (自動的に追加されたゾーンラベル以外) が存在することを確認してください。異なるラベルを持つノードに --balancing-ignore-label フラグを渡すと、それらに関係なくバランスを調整できますが、この実行方法は必要な場合にのみ使用してください。

ノードグループの最適化

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

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

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

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

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

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

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

  • 両方のシステムがサポートしているときはいつでも 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 ボリュームを使用する以外)。

共同スケジューリング

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

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

  • クラスターにリージョナルノードグループとゾーンノードグループの両方が含まれる場合、ノードアフィニティpod プリエンプション、またはその両方が使用されます。

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

    • ゾーン pods をリージョナルノードグループにスケジュールしないでください。これを行うと、リージョナル pods の容量が不均衡になる可能性があります。

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

アクセラレータとGPU

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

アクセラレーターを搭載し、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 を調査することで検出します。WindowsENIPrivateIPv4Address のような追加リソースを必要とする pods もあります。または、特定の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 を使用して、ゼロへのスケーリングおよびゼロからのスケーリング時に管理対象ノードグループの問題を診断できます。

Kubernetes 1.24 以降のクラスターの動作は単純化されています。以前のバージョンでは、基盤となる Amazon EC2 Auto Scaling グループに、そのグループが担当していたノードの詳細をタグ付けする必要があります。Kubernetes 1.24 以降のクラスターでは、マネージド型ノードグループに実行中のノードがない場合、Cluster Autoscaler は Amazon EKS DescribeNodegroup API オペレーションを呼び出します。この API オペレーションは、Cluster Autoscaler がマネージド型ノードグループのリソース、ラベル、テイントについて必要とする情報を提供します。この機能を使用するには、Cluster Autoscaler サービスアカウントの IAM ポリシーに eks:DescribeNodegroup アクセス許可を追加する必要があります。Amazon EKS マネージド型ノードグループを強化する Auto Scaling グループの Cluster Autoscaler タグの値がノードグループ自体と競合する場合、Cluster Autoscaler は Auto Scaling グループタグの値を使用します。これは、必要に応じて値をオーバーライドできるようにするためです。

その他の設定パラメータ

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

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

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

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

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

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

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

垂直的自動スケーリング

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

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

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

  • ノードグループではなく名前空間を使用して、pods を分離します。

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

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

    • より最適なビンパッキングとシステム pod オーバーヘッドの削減のために、より大きなインスタンスタイプを使用してください。

  • pods のスケジュールに NodeTaints または NodeSelectors を使用することは避けてください。これらは限られた基準でのみ使用してください。

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

スキャン間隔の短縮

スキャン間隔を短くすると (デフォルト設定の 10 秒など)、pods がスケジューリング不能になった際に、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 インスタンスのプロビジョニングに関連しています。さらに、コスト効率は可用性とバランスをとる必要があります。このセクションでは、スポットインスタンスを使用したコストの削減方法、ならびに、オーバープロビジョニングを使用しての、新しいノード作成時のレイテンシーの低減方法などの戦略について説明します。

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

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

スポットインスタンス

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

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

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

オンデマンドインスタンス容量とスポットインスタンス容量は、別々の Amazon EC2 Auto Scaling グループに分離することをお勧めします。これは、基本容量戦略を使用することよりも推奨されます。オンデマンドインスタンスとスポットインスタンスでは、それぞれスケジューリングプロパティが異なるためです。スポットインスタンスはいつでも中断できます。Amazon EC2 が容量を取り戻す必要がある場合、プリエンプティブノードがしばしばテイントされるため、プリエンプション動作に対する明示的な pod 許容力が必要になります。これが、ノードのスケジューリングプロパティが異っている理由です。つまり、複数の 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 分に設定されており、応答性の高いノードグループではこの値を減らすこともできます。ただし、値が低すぎると、不要なスケールアウトが発生する可能性があります。

オーバープロビジョニング

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

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

オーバープロビジョニングには他にも利点があります。オーバープロビジョニングを行わないと、使用率の高いクラスター内の pods は、preferredDuringSchedulingIgnoredDuringExecution ルールを使用して最適でないスケジューリング決定を行います。これの一般的な使用例は、AntiAffinity を使用してアベイラビリティーゾーン全体で可用性の高いアプリケーションの pods を分離することです。オーバープロビジョニングにより、目的のゾーンでノードが使用可能状態である可能性を、大幅に高めることができます。

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

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

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

Karpenter

Amazon EKS は Karpenter というオープンソースのオートスケーリングプロジェクトをサポートしています。これをデプロイするには、Karpenter のドキュメントを参照してください。

Karpenter について

Karpenter は、アプリケーションの可用性とクラスターの効率性の向上に役立つ、柔軟で高性能な Kubernetes クラスターオートスケーラーです。Karpenter は、アプリケーションの負荷の変化に応じて、適切なサイズのコンピューティングリソース (Amazon EC2 インスタンスなど) を 1 分未満で起動します。Kubernetes を AWS と統合することで、Karpenter は、ワークロードの要件を正確に満たすジャストインタイムコンピューティングリソースをプロビジョンできます。Karpenter は、クラスターワークロードの具体的な要件に基づいて、新しいコンピューティングリソースを自動的にプロビジョンします。これには、コンピューティング、ストレージ、高速化、スケジューリングの各要件が含まれます。Amazon EKS は Karpenter を使用したクラスターをサポートしていますが、Karpenter は適合するいずれの Kubernetes クラスターでも動作します。

Karpenter の仕組み

Karpenter は、クラスターの存続期間にわたって受信 Kubernetes をモニタリングすることにより、pods スケジューラと連携して動作します。アプリケーションの可用性とクラスターの使用率を最大化するために、ノードを起動または終了します。クラスターに十分な容量がある場合、Kubernetes スケジューラは通常どおり受信 pods を配置します。クラスターの既存キャパシティを使用してスケジュールできない pods が起動されたとき、それらの pods に合わせた必要最小限のコンピューティングリソースを起動し、kube-scheduler がその後に pods を準備ができたノードにバインドするため、Karpenter はプロバイダーのコンピューティングサービス (例えば、Amazon EC2 など) と直接連携します。pods が削除されるか、他のノードに再スケジュールされると、Karpenter は、使用率の低いノードを終了しようとします。ノードを大きくして、クラスターで実行する数を減らすと、デーモンセットと Kubernetes システムコンポーネントのオーバーヘッドが軽減され、ビンパッキングの効率性が向上する可能性が高くなります。

前提条件

Karpenter をデプロイする前に、次の前提条件を満たす必要があります。

eksctl を使用して Karpenter をデプロイすることもできます。「eksctl のインストールまたは更新」を参照してください。