Amazon EKS Blueprints を使用して Karpenter を動かしてみる
はじめに
Kubernetesクラスターの運用において、ワークロードの需要に応じたノードの自動スケーリングは重要な課題です。従来のCluster AutoscalerやEKS Managed Node Groupsでは、スケーリング速度やコスト効率に課題がありました。
今回は、Kubernetesノード管理ツールKarpenterを、AWS公式のAmazon EKS Blueprints for Terraformを使って構築し、実際の動作を検証してみました。
Amazon EKS Blueprints for Terraformとは
Amazon EKS Blueprints for Terraformは、AWSが公式提供するEKSクラスター構築のベストプラクティス集です。
今回は、EKS BlueprintsのKarpenter on EKS MNG パターンを使用します。このパターンでは、Karpenter専用のEKS Managed Node Groupを使用した構成を提供しています。
Karpenterとは
KarpenterはAWSが開発したオープンソースのKubernetesノードプロビジョナーです。
従来のCluster Autoscalerとの違い
項目 | Cluster Autoscaler | Karpenter |
---|---|---|
スケーリング速度 | 3-5分 | 30秒-2分 |
インスタンス選択 | 事前定義されたノードグループ | 300種類以上から最適選択 |
コスト最適化 | 限定的 | Spot/Mixed/On-Demandを動的選択 |
設定複雑さ | 複数のノードグループ管理 | 宣言的な要件定義 |
Karpenterの主な特徴
- 高速プロビジョニング: Pending状態のPodを検知して即座にノード作成
- インテリジェントな選択: 60種類以上のインスタンスから最適なものを自動選択
- コスト最適化: Spotインスタンスを積極活用
- 自動クリーンアップ: 不要になったノードを30秒で自動削除
今回の構成
アーキテクチャ概要
今回構築したKarpenter環境は、以下の2層構造になっています:
Karpenter専用ノード(固定・EKS Managed Node Group)
- Karpenterコントローラー:ノードの作成・削除を判断
- CoreDNS:クラスター内DNS(特別なTolerationで配置)
- システムコンポーネント:kube-proxy、VPC CNI等
- 特徴:taint設定により一般ワークロードは配置されない
一般ワークロード用ノード(動的・Karpenter管理)
- アプリケーションPod:実際のワークロード
- 自動スケーリング:Pod需要に応じてノードを作成
- コスト最適化:Spotインスタンス優先、不要時は自動削除
- 特徴:300種類以上のインスタンスから最適選択
使用技術
- Infrastructure as Code: Terraform
- EKS管理: Amazon EKS Blueprints for Terraform
- ノードOS: Bottlerocket(コンテナ最適化OS)
- ネットワーク: VPC with Private/Public subnets
- 権限管理: Pod Identity
環境構築手順
前提条件
- AWS CLI設定済み
- Terraform 設定済み
- kubectl インストール済み
1. EKS Blueprintsパターンの取得
今回は公式のKarpenter MNGパターンを使用します
git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git
cd terraform-aws-eks-blueprints/patterns/karpenter-mng
2. EKS Blueprintsによるインフラ構築
EKS Blueprintsでは、ベストプラクティスに基づいた設定が事前に定義されています:
# eks.tf
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.24"
cluster_name = local.name
cluster_version = "1.30"
# Karpenterコントローラー専用ノードグループ
eks_managed_node_groups = {
karpenter = {
ami_type = "BOTTLEROCKET_x86_64"
instance_types = ["m5.large"]
min_size = 2
max_size = 3
desired_size = 2
# 重要: Karpenter専用の設定
labels = {
"karpenter.sh/controller" = "true"
}
taints = {
karpenter = {
key = "karpenter.sh/controller"
value = "true"
effect = "NO_SCHEDULE"
}
}
}
}
}
2. Karpenterリソースの設定
EKS Blueprintsでは、Karpenterの複雑な権限設定も自動化されています:
# karpenter.tf
module "karpenter" {
source = "terraform-aws-modules/eks/aws//modules/karpenter"
version = "~> 20.24"
cluster_name = module.eks.cluster_name
enable_v1_permissions = true
namespace = "karpenter"
create_pod_identity_association = true
node_iam_role_name = local.name
depends_on = [aws_iam_service_linked_role.ec2_spot]
}
3. Terraformでのデプロイ
terraform init
terraform plan
terraform apply
# kubeconfigの更新
aws eks --region us-west-2 update-kubeconfig --name ex-karpenter-mng
4. Karpenterリソースの適用
# NodePool/EC2NodeClassの適用
kubectl apply --server-side -f karpenter.yaml
# リソースの確認
kubectl get nodepool
kubectl get ec2nodeclass
5. ノード設定の詳細
EKS Blueprintsで作成されるKarpenter設定
# EC2NodeClass: インスタンスの物理仕様
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
spec:
amiSelectorTerms:
- alias: bottlerocket@latest # コンテナ最適化OS
role: ex-karpenter-mng
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: ex-karpenter-mng
# NodePool: ワークロード要件とポリシー
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: "karpenter.k8s.aws/instance-category"
values: ["c", "m", "r"] # CPU/汎用/メモリ最適化
- key: "karpenter.k8s.aws/instance-cpu"
values: ["4", "8", "16", "32"] # 4-32 vCPU
- key: "karpenter.k8s.aws/instance-generation"
operator: Gt
values: ["2"] # 第3世代以降
limits:
cpu: 1000 # 最大1000 CPU
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 30s # 30秒で空ノード削除
EKS Blueprintsの利点
1. 設定の簡素化
従来の手動設定では50行以上のIAM権限設定が必要でしたが、EKS Blueprintsでは:
module "karpenter" {
enable_v1_permissions = true # この1行でベストプラクティス権限を適用
create_pod_identity_association = true
}
また、Karpenterモジュールは内部で以下のリソースを自動作成します
- IAMロール: Karpenterコントローラー用の権限(60行以上のポリシー文)
- IAMポリシー: EC2操作、SQS、EKS等への細かい権限設定
- Pod Identity Association: EKS Pod IdentityによるServiceAccount連携
- SQSキュー: Spot中断通知用(EventBridge連携含む)
- EventBridgeルール: EC2状態変更通知の自動設定
手動では数十のリソース定義が必要なところを、わずか2行で実現しています。
2. セキュリティベストプラクティス
- Pod Identity方式による権限管理
- 最小権限の原則
- プライベートサブネットでの運用
- Bottlerocket(セキュア軽量OS)の使用
3. 運用最適化
- 高可用性設計(2つのKarpenterコントローラー)
- 自動スケーリング設定
- ログとメトリクス設定
- 適切なタグ付けによるリソース管理
4. Taint/Tolerationによる適切な分離
Karpenterコントローラーは専用ノードで動作し、一般的なワークロードは動的に作成されるノードで動作します。
# Karpenter専用ノードのTaint
taints:
- key: "karpenter.sh/controller"
value: "true"
effect: "NoSchedule"
# CoreDNSの特別な設定(システム起動時の課題解決)
tolerations:
- key: "karpenter.sh/controller"
value: "true"
effect: "NoSchedule"
5. 高可用性設計
Karpenterコントローラーは複数のレプリカで動作し、Kubernetesネイティブなリーダー選出機能により高可用性を実現しています。
リーダー選出機能
Karpenterは、複数のコントローラーレプリカが競合することなく並行して実行できるKubernetesネイティブ機能であるリーダー選出をサポートしています。1つのレプリカがリーダーとして意思決定を行い、他のレプリカはスタンバイ状態で待機します。
デフォルト構成
公式のKarpenter Helmチャートでは、デフォルトで2つのレプリカが設定されており、Pod Disruption Budget(maxUnavailable: 1
)も併せて構成されています。
# values.yaml(公式Helmチャート)
replicas: 2
podDisruptionBudget:
maxUnavailable: 1
動作メカニズムの確認
# リーダー選出の状態確認
kubectl get lease -n karpenter karpenter-leader-election -o yaml
# 現在のリーダーを確認
kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter | grep -i "leader"
# レプリカ数の確認
kubectl get deployment karpenter -n karpenter
高可用性の仕組み
- アクティブ/パッシブ構成: 1つのレプリカがリーダーとして動作、他はスタンバイ状態
- 自動フェイルオーバー: リーダーに障害が発生すると、スタンバイレプリカが自動的に引き継ぎ
- 状態の同期: Kubernetes APIサーバーを介してすべての状態情報を共有
- 競合回避: リーダー選出により、レプリカ間での重複したノード作成・削除操作を防止
- Pod Disruption Budget: ローリングアップデート時やメンテナンス時の可用性を保証
動作検証
テストアプリケーションのデプロイ
EKS Blueprintsにはテスト用のサンプルアプリケーションも含まれています。
# サンプルアプリケーションの適用
kubectl apply --server-side -f example.yaml
# 最小限のテスト用Pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 0 # 初期は0
template:
spec:
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
resources:
requests:
cpu: 1 # 1 vCPU要求
スケーリングテスト
# 3つのPodを作成
kubectl scale deployment inflate --replicas=3
# リアルタイムで監視
kubectl get nodes --watch
kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter -f
実際のKarpenterログ
// 1. Pending Pod検知 (瞬時)
{"message":"found provisionable pod(s)","Pods":"default/inflate-xxx","duration":"51.617574ms"}
// 2. ノード計算 (即座)
{"message":"computed new nodeclaim(s)","nodeclaims":1,"pods":3}
// 3. 最適インスタンス選択 (10ms)
{"message":"created nodeclaim","instance-types":"c5.xlarge, c5a.xlarge, c5ad.xlarge, c5d.xlarge, c5n.xlarge and 55 other(s)"}
// 4. Spotインスタンス起動 (3秒)
{"message":"launched instance","instance-type":"c5d.xlarge","zone":"us-west-2b","capacity-type":"spot"}
// 5. ノード初期化完了 (30秒)
{"message":"initialized nodeclaim","allocatable":{"cpu":"3920m","memory":"6584Mi","pods":"58"}}
注意点
Karpenterが初回にSpotインスタンスを使用する際、AWSServiceRoleForEC2Spotが必要ですが、Karpenter自身には作成権限がありません。
エラー例:
AuthFailure.ServiceLinkedRoleCreationNotPermitted:
The provided credentials do not have permission to create
the service-linked role for EC2 Spot Instances.
解決策: terraform で明示的に作成する
resource "aws_iam_service_linked_role" "ec2_spot" {
aws_service_name = "spot.amazonaws.com"
lifecycle {
ignore_changes = all # 既存環境での競合回避
}
}
まとめ
Amazon EKS Blueprints for TerraformとKarpenterの組み合わせにより、簡単にノードの起動からPodのスケジューリングまで動かすことができました。
参考資料
- Amazon EKS Blueprints for Terraform
- Karpenter Documentation
- AWS EKS Best Practices Guide
- EKS Karpenter: A Deep Dive and Best Practices
使用したリソース
Discussion