従来のスケーリングにおける課題
Kubernetesを大規模に運用する場合、リソースの無駄との戦いになることがよくあります。アプリケーションの応答性を維持したい一方で、過剰なプロビジョニングはAWSの請求額を増大させます。長年、Kubernetes Cluster Autoscaler (CA) がこの役割を担う唯一の実質的なツールでした。それなりに機能してはいましたが、決して高速でもスマートでもありませんでした。
私は、Cluster Autoscaler of the reactionを待つ間、エラー率が上昇していくのをストレスを感じながら見守る時間を何度も経験してきました。CAはAWS Auto Scaling Group (ASG) をトリガーし、EC2インスタンスの起動を待ち、最終的にノードを登録する必要があります。多忙な本番環境では、ポッドが Pending 状態のまま待たされる4〜5分間は、永遠のように感じられることがあります。
Karpenterは、仲介役を排除することでこの状況を一変させます。Auto Scaling Groupを完全にバイパスし、EC2 Fleet APIと直接通信します。このアプローチにより、ノード管理がより高速で柔軟になり、大幅なコスト削減が可能になります。
なぜKarpenterはCluster Autoscalerより優れているのか
多くのチームがKarpenterに移行している理由を理解するには、インフラストラクチャの処理方法における根本的な変化に注目する必要があります。
CAのリアクティブ(受動的)な性質
Cluster Autoscalerは厳格にリアクティブです。「スケジューリング不能」なポッドを検知すると、既存のノードグループをスキャンします。適合するものが見つかれば、そのASGの「希望する容量(desired capacity)」を増やします。このプロセスは硬直的です。もしポッドが特定のGPUや、事前定義されたグループに含まれていない大容量メモリのインスタンスを必要としている場合、CAでは対応できません。
Karpenterのジャストインタイム・ロジック
Karpenterはプロアクティブ(能動的)であり、「グループレス」です。保留中のポッドの正確な要件(CPU、RAM、アーキテクチャ(ARM64 vs x86)、アベイラビリティゾーンなど)を評価します。そして、それらのニーズに適合する、最もコスト効率の高い単一のインスタンスをAWSに要求します。ポッドが2 vCPUを必要とする場合、Karpenterはグループの一部だからといって16 vCPUの m5.4xlarge を起動することはありません。代わりに t3.medium を選択する可能性があり、その特定のワークロードの計算コストを約70%節約できます。
トレードオフ:導入すべきか?
メリット
- 驚異的なスピード: 通常、ノードは45〜60秒でクラスターに参加します。CAが同じタスクを完了するには3〜5分かかることがよくあります。
- 積極的なビンパッキング(集約): Karpenterは常に統合の機会を探します。コスト削減につながる場合、ポッドをより小さなノードに移動し、古いノードを削除します。
- 設定の簡素化: 数十個の特化型Auto Scaling Groupを、単一のKarpenter設定に置き換えることができます。
- スマートなスポットインスタンス処理: AWSから中断通知が発行されると、インスタンスが実際に停止する前に、プロアクティブにスポットインスタンスを置き換えます。
課題
- AWS中心: プロジェクトはプラットフォームに依存しないことを目指していますが、現在、最も成熟した機能はAWS専用です。
- 初期セットアップ: IAMロールやOIDCプロバイダーの設定には、コンソールで「マネージド型ノードグループを作成」をクリックするよりも正確な操作が求められます。
- 進化の速いAPI: Karpenterは急速に進化しています。一部の設定スキーマが最近変更されたように、バージョンの更新には注意を払う必要があります。
導入の前提条件
移行を開始する前に、環境が以下の要件を満たしてください:
- Kubernetes: バージョン1.25以上を推奨。
- 環境: 既存のAmazon EKSクラスター。
- ローカルツール:
helm、kubectl、および最新のaws-cli。 - アクセス権限: IAMロールの作成およびOpenID Connect (OIDC) プロバイダーを管理するための管理者権限。
ステップバイステップのインストール手順
ここでは、Karpenterコントローラーのデプロイと必要な権限の設定に焦点を当てます。このガイドは、既存のEKSクラスターがあることを前提としています。
1. IAMロールのプロビジョニング
Karpenterは、ユーザーに代わってEC2インスタンスをプロビジョニングする権限を必要とします。Karpenterが作成するノード用と、コントローラー自体の用の2つの異なるロールが必要です。
# ノード用のIAMロールを作成
aws iam create-role --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--assume-role-policy-document file://node-trust-policy.json
# 必要なポリシーをアタッチ
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
2. Helmによるコントローラーのデプロイ
IAMロールのマッピングが完了したら、Helmを使用してコントローラーをインストールします。このコンポーネントは、スケジューラーが配置できないポッドがないかAPIサーバーを監視します。
helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter \
--version v0.32.1 \
--namespace karpenter --create-namespace \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${KARPENTER_IAM_ROLE_ARN} \
--set settings.aws.clusterName=${CLUSTER_NAME} \
--set settings.aws.defaultInstanceProfile=KarpenterNodeInstanceProfile-${CLUSTER_NAME} \
--wait
3. NodePoolの定義
これがスケーリングロジックの中核です。バージョン0.32以降、Karpenterは NodePool と EC2NodeClass を使用します。NodePoolはインスタンスの制約を定義し、EC2NodeClassはAWS固有のネットワーク設定を処理します。
nodepool.yaml を作成します:
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64", "arm64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
nodeClassRef:
name: default
disruption:
consolidationPolicy: WhenUnderutilized
expireAfter: 720h
そして、サブネットをリンクするための EC2NodeClass を作成します:
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: AL2
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: ${CLUSTER_NAME}
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: ${CLUSTER_NAME}
4. セットアップのテスト
Karpenterの動作を確認するために、ダミーのデプロイメントをスケールさせます。何もしないでリソースだけを消費する “pause” イメージの使用をお勧めします。
kubectl create deployment inflate --image=public.ecr.aws/eks-distro/kubernetes/pause:3.7
kubectl scale deployment inflate --replicas=15
ログを監視します: kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter。Karpenterが即座にリソース不足を計算し、新しいインスタンスをプロビジョニングするのが確認できるはずです。私のテストでは、通常40秒以内に kubectl get nodes で新しいノードが Ready 状態になります。
まとめ
Cluster AutoscalerからKarpenterへの切り替えは、地図からリアルタイムのGPSにアップグレードするようなものです。サーバーの個別のプールを管理するのをやめ、アプリケーションのニーズを定義することに集中できるようになります。初期のIAMセットアップは少し手間がかかりますが、その見返りとして、より速くスケーリングし、コストを抑えられるクラスターが手に入ります。EKSで大規模な本番ワークロードを運用している人にとって、Karpenterはもはや単なる選択肢ではなく、現代の標準と言えるでしょう。

