Karpenter ノードオートスケーリング
Karpenter を使用したノードの自動プロビジョニングと最適化を学びます。NodePool 設計、Disruption 管理、KWOK によるローカル検証までを体系的に扱います。
目次
- Karpenter とは
- Cluster Autoscaler との比較
- アーキテクチャ
- コアコンセプト
- スケジューリングフロー
- Disruption(中断管 理)
- NodePool 設計パターン
- ローカル検証(KWOK プロバイダー)
- IDサービスでの想定構成
- チェックリスト
- 次のステップ
Karpenter とは
Karpenter は AWS が開発し、現在は Kubernetes SIGs(CNCF)でホストされるノードオートスケーラー。Pod のリソース要求に応じて、最適なインスタンスタイプのノードを直接プロビジョニングする。
従来の Cluster Autoscaler がノードグループ(ASG)単位でスケーリングするのに対し、Karpenter はノードグループに依存しない Group-less アーキテクチャ を採用している。
┌─────────────────────────────────────────────────────────────┐
│ Cluster Autoscaler(従来型) │
│ │
│ NodeGroup A (m5.large) NodeGroup B (c5.xlarge) │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Node 1│ │Node 2│ │Node 3│ │Node 4│ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ → グループごとに固定インスタンスタイプ │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ Karpenter(Group-less) │
│ │
│ NodePool(ポリシーのみ定義) │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │m5.lg │ │c5.xl │ │m5.xl │ │c5.lg │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ → Pod の要求に応じて最適なインスタンスを都度選択 │
│ │
└─────────────────────────────────────────────────────────────┘
- ノードグループ不要: 事前にインスタンスグループを定義する必要がない
- 直接プロビジョニング: クラウド API を直接呼び出してノードを作成
- 最適インスタンス選択: Pod の要求(CPU/メモリ/GPU)に基づき最適なインスタンスタイプを自動選択
- 高速スケーリング: ASG を経由しないため起動が速い
Cluster Autoscaler との比較
| 項目 | Cluster Autoscaler | Karpenter |
|---|---|---|
| スケジューリング方式 | ノードグループの容量を拡張 | Pod 要求から直接ノードを作成 |
| ノードグループ | 必須(ASG) | 不要(NodePool でポリシー定義) |
| インスタンス選択 | グループ内の固定タイプ | 要求に応じて動的に選択 |
| スケーリング速度 | 数分(ASG 経由) | 数十秒(直接プロビジョニング) |
| Bin Packing | 限定的 | Pod 要求を集約して最適なインスタンスを選択 |
| コスト最適化 | 手動でグループ設計が必要 | Spot / On-demand 混合を自動判断 |
| Consolidation | なし | 使用率の低いノードを自動統合 |
| Drift 検知 | なし | NodePool 変更時に自動でノードを置換 |
| クラウド対応 | AWS, GCP, Azure 等 | AWS(GA)、Azure(プレビュー) |
| API バージョン | Kubernetes Autoscaler SIG | karpenter.sh/v1 |
アーキテクチャ
全体構成
┌─────────────────────────────────────────────────────────────┐
│ Karpenter アーキテクチャ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Kubernetes Cluster │ │
│ │ │ │
│ │ ┌──────────┐ watch ┌──────────────────────┐ │ │
│ │ │ Pending │ ─────────► │ Karpenter │ │ │
│ │ │ Pods │ │ Controller │ │ │
│ │ └──────────┘ │ │ │ │
│ │ │ ┌────────────────┐ │ │ │
│ │ │ │ Provisioner │ │ │ │
│ │ │ │ - Bin Packing │ │ │ │
│ │ │ │ - Scheduling │ │ │ │
│ │ │ └───────┬────────┘ │ │ │
│ │ │ │ │ │ │
│ │ │ ┌───────▼────────┐ │ │ │
│ │ │ │ Disruption │ │ │ │
│ │ │ │ Controller │ │ │ │
│ │ │ └────────────────┘ │ │ │
│ │ └──────────┬───────────┘ │ │
│ │ │ │ │
│ └─────────────────────────────────────┼──────────────────┘ │
│ │ │
│ ┌─────────▼──────────┐ │
│ │ Cloud Provider API │ │
│ │ (EC2 / KWOK etc.) │ │
│ └─────────┬──────────┘ │
│ │ │
│ ┌─────────▼──────────┐ │
│ │ New Node │ │
│ │ (最適なインスタンス) │ │
│ └────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
コンポーネント
| コンポーネント | 役割 |
|---|---|
| Karpenter Controller | Pending Pod を監視し、ノードのプロビジョニングとライフサイクルを管理 |
| Provisioner | Pod の要求を分析し、Bin Packing で最適なノード構成を決定 |
| Disruption Controller | Consolidation、Drift、Expiration によるノードの中断を管理 |
| Cloud Provider | 実際のノード作成・削除をクラウド API 経由で実行 |
コアコンセプト
NodePool
NodePool はノードのプロビジョニングポリシーを定義するリソース。どのようなノードを作成するかの 制約 と 上限 を宣言する。
# nodepool.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
# アーキテクチャ制約
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
# OS 制約
- key: kubernetes.io/os
operator: In
values: ["linux"]
# 購入タイプ(Spot / On-demand)
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand", "spot"]
# インスタンスファミリー
- key: karpenter.k8s.aws/instance-family
operator: In
values: ["m5", "m6i", "c5", "c6i", "r5", "r6i"]
# NodeClass への参照
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
# ノードの有効期限(自動ローテーション)
expireAfter: 720h # 30日
# クラスタ全体のリソース上限
limits:
cpu: 100 # 最大 100 vCPU
memory: 200Gi # 最大 200 GiB
# 中断ポリシー
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30s
主要フィールド:
| フィールド | 説明 |
|---|---|
requirements | ノードに求める制約(arch, os, capacity-type, instance-family 等) |
nodeClassRef | クラウドプロバイダー固有設定への参照 |
expireAfter | ノードの最大生存期間(自動ローテーション) |
limits | この NodePool が管理するリソースの上限 |
disruption | Consolidation ポリシーの設定 |
NodeClass
NodeClass はクラウドプロバイダー固有の設定を定義する。AWS では EC2NodeClass、KWOK では KWOKNodeClass を使用する。
# ec2nodeclass.yaml(AWS の場合)
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
spec:
# AMI の選択
amiSelectorTerms:
- alias: al2023@latest # Amazon Linux 2023 の最新 AMI
# サブネットの選択
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
# セキュリティグループの選択
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
# IAM ロール
role: KarpenterNodeRole-my-cluster
# ブロックデバイスマッピング
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 100Gi
volumeType: gp3
encrypted: true
# kwok-nodeclass.yaml(KWOK ローカル検証の場合)
apiVersion: karpenter.kwok.sh/v1alpha1
kind: KWOKNodeClass
metadata:
name: default
NodeClaim
NodeClaim は Karpenter が内部的に生成するプロビジョニングリクエスト。ユーザーが直接作成することはなく、Karpenter Controller が NodePool のポリシーに基づいて自動生成する。
┌─────────────────────────────────────────────────────────────┐
│ NodeClaim ライフサイクル │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Created │──►│Registered│──►│ Ready │ │
│ │ │ │ │ │ │ │
│ │NodeClaim │ │Node が │ │Pod が │ │
│ │生成 │ │クラスタに │ │スケジュー │ │
│ │ │ │参加 │ │ル可能 │ │
│ └──────────┘ └──────────┘ └─────┬────┘ │
│ │ │
│ ┌───────────┼───────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │Consoli- │ │ Drift │ │Expired │ │
│ │dated │ │ │ │ │ │
│ └────┬─────┘ └────┬─────┘ └───┬────┘ │
│ │ │ │ │
│ └────────────┼───────────┘ │
│ ▼ │
│ ┌──────────┐ │
│ │ Deleted │ │
│ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
# NodeClaim の確認
kubectl get nodeclaim
# 出力例
# NAME TYPE CAPACITY ZONE NODE READY AGE
# default-abc12 m5.xlarge on-demand ap-northeast-1a ip-10-0-1-5 True 5m
スケジューリングフロー
Pod Pending からノード作成まで
┌─────────────────────────────────────────────────────────────┐
│ Karpenter スケジューリングフロー │
│ │
│ Step 1: Pod が Pending 状態になる │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Pod A │ │Pod B │ │Pod C │ ← リソース不足で Pending │
│ │1 CPU │ │2 CPU │ │1 CPU │ │
│ │2Gi │ │4Gi │ │2Gi │ │
│ └──────┘ └──────┘ └──────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Step 2: バッチスケジューリング(複数 Pod をまとめて評価) │
│ ┌─────────────────────────────────────────┐ │
│ │ Karpenter Controller │ │
│ │ 合計要求: 4 CPU, 8 Gi │ │
│ └────────────────────┬────────────── ──────┘ │
│ │ │
│ ▼ │
│ Step 3: Bin Packing(最適なインスタンスを選択) │
│ ┌─────────────────────────────────────────┐ │
│ │ 候補: │ │
│ │ m5.xlarge (4 CPU, 16Gi) ← 最適 ✓ │ │
│ │ m5.2xlarge (8 CPU, 32Gi) ← オーバースペック│ │
│ │ m5.large (2 CPU, 8Gi) ← リソース不足 ✗ │ │
│ └────────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ Step 4: ノード作成 → Pod スケジュール │
│ ┌─────────────────────────────────────────┐ │
│ │ Node (m5.xlarge) │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │Pod A │ │Pod B │ │Pod C │ │ │
│ │ └──────┘ └──────┘ └──────┘ │ │
│ └─────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
バッチスケジューリング
Karpenter は個々の Pending Pod に対して1ノードずつ作成するのではなく、一定時間(デフォルト10秒)の間に溜まった Pending Pod をまとめて評価する。これにより、複数の Pod を1つのノードに効率的に配置できる。
Bin Packing
Bin Packing は Pod のリソース要求を集約し、最もフィットするインスタンスタイプを選択するアルゴリズム。無駄なリソースを最小化しつつ、全 Pod の要求を満たすノードを選ぶ。
┌───────────────────────────────────────────── ────────────────┐
│ Bin Packing の例 │
│ │
│ 要求: Pod A (1CPU, 2Gi) + Pod B (2CPU, 4Gi) │
│ │
│ ✗ 2 × m5.large (各 2CPU, 8Gi) → 1CPU+4Gi の無駄 │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ [Pod A ] │ │ [Pod B ] │ │
│ │ [ 空き ] │ │ [ 空き ] │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ ✓ 1 × m5.xlarge (4CPU, 16Gi) → 最小構成で全 Pod 収容 │
│ ┌───────────────────────────┐ │
│ │ [Pod A] [Pod B] [ 空き ] │ │
│ └───────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Disruption(中断管理)
Karpenter はノードのライフサイクルを自動管理し、コスト最適化とセキュリティを維持する。
Consolidation
Consolidation はワークロードの減少時にノードを統合し、コストを削減する機能。
# nodepool.yaml
spec:
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30s