Auto Scaling
オートスケーリングとは、需要の変化に合わせてリソースを自動的に増減させる機能です。これは Kubernetes の主要な機能であり、この機能がなければ、手動で実行するために膨大な人的リソースが必要になります。
Amazon EKS は 2 つのオートスケーリング製品をサポートしています。Kubernetes の Cluster Autoscaler
Cluster Autoscaler
Kubernetes の Cluster Autoscaler
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
を参照してください。 -
ノードグループ – クラスター内のノードグループの 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>
を含む) はすべて、独自の値に置き換えます。<>
-
IAM ポリシーを作成します。
-
次の内容を
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" } ] }
-
次のコマンドを使用してポリシーを作成します。
policy-name
の値は変更することが可能です。aws iam create-policy \ --policy-name AmazonEKSClusterAutoscalerPolicy \ --policy-document file://cluster-autoscaler-policy.json
出力で返される Amazon リソースネーム (ARN) を書き留めます。ID は後の手順で使用する必要があります。
-
-
eksctl
または AWS Management Console を使用しながら IAM ロールを作成して、そのロールに IAM ポリシーをアタッチすることができます。次の手順で目的のタブを選択します。
Cluster Auto Scaling をデプロイする
Cluster Autoscaler をデプロイするには、以下の手順を完了します。実稼働段階のクラスターに Cluster Autoscaler をデプロイする前に、デプロイに関する考慮事項 を確認した上で、デプロイを最適化することをお勧めします。
Cluster Auto Scaling をデプロイするには
-
Cluster Autoscaler の YAML ファイルをダウンロードします。
curl -o cluster-autoscaler-autodiscover.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
-
YAML ファイルを編集し、その中の
<YOUR CLUSTER NAME>
の部分を、使用するクラスターの名前に置き換えます。 -
YAML ファイルをクラスターに適用します。
kubectl apply -f cluster-autoscaler-autodiscover.yaml
-
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>
-
次のコマンドを使用して、
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"}}}}}'
-
次のコマンドを使用して 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ファイルを保存して閉じ、変更を適用します。
-
-
ウェブブラウザで、GitHub の Cluster Autoscaler リリース
ページを開き、最新の (クラスターの Kubernetes のメジャーおよびマイナーバージョンに一致する) Cluster Autoscaler バージョンを見つけます。ととえば、クラスターの Kubernetes バージョンが 1.21 の場合、1.21 で始まる Cluster Autoscaler リリースを見つけます。次のステップで使用するので、そのリリースのセマンティックバージョン番号 ( 1.21.n
) を書き留めておきます。 -
次のコマンドを使用して、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 つだけ作成する場合には、そのノードグループを複数のアベイラビリティーゾーンにまたがるようにスコープします。
--balance-similar-node-groups
を true に設定するときは、Cluster Autoscaler でバランス調整するノードグループに、一致するラベル (自動的に追加されたゾーンラベル以外) が存在することを確認してください。異なるラベルを持つノードに --balancing-ignore-label
フラグを渡すと、それらに関係なくバランスを調整できますが、この実行方法は必要な場合にのみ使用してください。
ノードグループの最適化
Cluster Autoscaler は、ノードグループの使用方法について仮定します。これには、グループ内で使用するインスタンスタイプが含まれます。これらの推定結果に合致させるために、次の考慮事項や推奨事項に基づいてノードグループを構成します。
-
ノードグループ内の各ノードは、同一のスケジューリングプロパティを持つ必要があります。これには、ラベル、汚染、およびリソースが含まれます。
-
MixedInstancePolicies
については、インスタンスタイプには互換性のある CPU、メモリ、および GPU 仕様が必要です。 -
ポリシーで指定された最初のインスタンスタイプが、スケジューリングをシミュレートします。
-
ポリシーに、より多くのリソースを使用する追加のインスタンスタイプが含まれている場合、スケールアウト後に、これらのリソースが無駄になる可能性があります。
-
ポリシーに、元のインスタンスタイプよりも少ないリソースを使用する追加のインスタンスタイプが含まれる場合、ポッドがインスタンスでのスケジュールに失敗することがあります。
-
-
ノードグループの数を減らしてグループごとのノードの数を増やすように構成してください。反対の構成ではスケーラビリティに悪影響を及ぼす可能性があります。
-
両方のシステムがサポートしているときはいつでも Amazon EC2 の機能を使用してください (例: リージョンと
MixedInstancePolicy
。)
可能な限り、マネージド型ノードグループ の使用をお勧めします。マネージド型ノードグループには、強力な管理機能が付属しています。これには、Amazon EC2 Auto Scaling グループの自動検出やノードの正常な終了など、Cluster Autoscaler の機能が含まれます。
EBS ボリュームを永続的ストレージとして使用する
永続的ストレージは、データベースや分散キャッシュなどのステートフルなアプリケーションを構築するために重要です。Amazon EBS ボリュームを使用すると、Kubernetes でステートフルなアプリケーションを構築できます。ただし、構築は単一のアベイラビリティーゾーンに制限されます。詳細については、「Amazon EKS で永続的ストレージを使用する方法を教えてください。
-
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 は、デプロイのリソースに対するリクエストを増やすことで大規模なクラスタにスケーリングできます。これは最も簡単な方法の1つです。大規模なクラスターに合わせてメモリと CPU の両方を増やします。メモリと CPU をどれだけ増やすべきかは、特定のクラスターサイズによって大きく変わってきます。オートスケーリングのアルゴリズムでは、すべてのポッドとノードがメモリに格納されています。これにより、メモリフットプリントが 1 GB を超える場合があります。通常、リソースは手動で増やす必要があります。リソースを手動で増やさなければならない回数が多い場合は、アドオンリサイザー
ノードグループの数を減らす
ノードグループの数を減らして、大規模なクラスタでの Cluster Autoscaler のパフォーマンスを向上させることができます。個々のチームまたはアプリケーションベースでノードグループを構造化する場合には、この作業は難しいかもしれません。Kubernetes API には、このための完全なサポートが用意されていますが、これはスケーラビリティに影響を与え得る、反 Cluster Autoscaler のパターンだと考えられます。たとえば、スポットインスタンスと GPU インスタンスの両方を使用する複数のノードグループを使用することには、多くの利点があります。そして多くの場合は、少数のグループを使用しながら同じ効果を達成できる、代替的な設計法が存在します。この場合は、以下の条件が満たされていることを確認してください。
-
ノードグループではなく名前空間を使用して、ポッドを分離している。
-
低信頼マルチテナントクラスターでは、この操作を実行できないことがあります。
-
ポッド の
ResourceRequests
とResourceLimits
を適切に設定し、リソースの競合を回避します。 -
インスタンスタイプを大きくするほどビンのパッキングが最適に行え、システムポッドのオーバーヘッドが軽減されます。
-
-
ポッドのスケジューリングに
NodeTaints
やNodeSelectors
は使用しないでください。これらは限られた基準でのみ使用してください。 -
リージョンごとのリソースを、複数のアベイラビリティーゾーンを持つ 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 ノード終了ハンドラー
混在インスタンスポリシーの設定時には、すべてのインスタンスタイプが同様のリソース容量を持つことが重要です。Autoscaler のスケジューリングシミュレータは、混成インスタンスポリシーにある、最初のインスタンスタイプを使用します。後続に、より大きなインスタンスタイプがある場合、スケールアップ後にリソースが浪費される可能性があります。インスタンスがより小さい場合には、容量不足のために、ポッドは新しいインスタンスでのスケジュールに失敗することがあります。例えば、M4
、M5
、M5a,
、および 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 分に設定されており、応答性の高いノードグループではこの値を減らすこともできます。ただし、値が低すぎると、不要なスケールアウトが発生する可能性があります。
オーバープロビジョニング
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
のラベルを付けます。
Karpenter
Amazon EKS は Karpenter というオープンソースのオートスケーリングプロジェクトをサポートしています。これをデプロイするには、Karpenter
Karpenter について
Karpenter は、アプリケーションの可用性とクラスターの効率の向上に役立つ柔軟で高性能な Kubernetes クラスターオートスケーラーです。Karpenter は、アプリケーションの負荷の変化に応じて、適切なサイズのコンピューティングリソース (Amazon EC2 インスタンスなど) を 1 分未満で起動します。Kubernetes と AWS との統合を通じて、Karpenter は、ワークロードの要件を正確に満たすジャストインタイムコンピューティングリソースをプロビジョンできます。Karpenter は、クラスターワークロードの具体的な要件に基づいて、新しいコンピューティングリソースを自動的にプロビジョンします。これには、コンピューティング、ストレージ、高速化、スケジューリングの各要件が含まれます。Amazon EKS は Karpenter を使用したクラスターをサポートしていますが、Karpenter は適合するいずれの Kubernetes クラスターでも動作します。
Karpenter の仕組み
Karpenter は、クラスターの存続期間にわたって着信ポッドを監視することにより、Kubernetes スケジューラと連携して動作します。アプリケーションの可用性とクラスターの使用率を最大化するために、ノードを起動または終了します。クラスターに十分な容量がある場合、Kubernetes スケジューラは通常どおり着信ポッドを配置します。クラスターの既存の容量を使用してスケジュールできないポッドが起動された場合、Karpenter は Kubernetes スケジューラをバイパスし、プロバイダーのコンピューティングサービス (Amazon EC2 など) と直接連携して、それらのポッドに合わせた必要最小限のコンピューティングリソースを起動し、プロビジョンされたノードにポッドをバインドします。ポッドが削除されるか、他のノードに再スケジュールされると、Karpenter は、使用率の低いノードを終了しようとします。ノードを大きくして、クラスターで実行する数を減らすと、デーモンセットと Kubernetes システムコンポーネントのオーバーヘッドが軽減され、ビンパッキングの効率が向上する可能性が高くなります。
前提条件
Karpenter をデプロイする前に、次の前提条件を満たす必要があります。
-
既存の Amazon EKS クラスター - クラスターがない場合は、「Amazon EKS クラスターの作成」を参照してください。
-
クラスター用の既存 IAM OIDC プロバイダー。既に存在しているかどうかを確認する、または作成するには「クラスターの IAM OIDC プロバイダーを作成するには」を参照してください。
-
クラスターを作成する権限を持つユーザーまたはロール。
-
AWS CLI
eksctl を使用して Karpenter をデプロイすることもできます。「eksctl のインストール」を参照してください。