Amazon Web Services ブログ

Karpenter 1.0 がローンチされました

はじめに

2021 年 11 月、AWS は 新しいオープンソースの Kubernetes クラスターオートスケーリングプロジェクト「Karpenter v0.5」の発表を行いました。当初は Kubernetes の Cluster Autoscaler の柔軟で動的かつ高性能な代替手段として考案されていましたが、その後の約 3 年間で Karpenter は大幅に進化し、完全な機能を備えた Kubernetes ネイティブのノードライフサイクルマネージャーになりました。

このプロジェクトは、業界のリーダー企業によってミッションクリティカルなユースケースに採用されています。自動的に利用率を改善するように設計されたワークロード統合や、ユーザーがクラスター内で Karpenter がノードのライフサイクル管理操作を実行する方法とタイミングを指定できるようにする中断制御 (Disruption Controls) などの主要な機能が追加されました。2023 年 10 月には、このプロジェクトがベータ版に移行し、AWS は Kubernetes の Autoscaling Special Interest Group (SIG) を通じて、ベンダーニュートラルなプロジェクトのコアを Cloud Native Computing Foundation (CNCF) に貢献しました。Karpenter コミュニティからの関与により、GitHub の星の数でAWS のオープンソースプロジェクトのトップ 10の 1 つとなり、AWS 以外のコミュニティメンバーからの貢献も、数と範囲の両面で増加しています。この進化を支えているのはユーザーの成功事例や、新機能、コミュニティの貢献です。AWS の Karpenter チームは、プロジェクトの成熟度と運用の安定性を高めるために熱心に取り組んでいます。

本日、Karpenter v1.0.0 のリリースにより、Karpenter がベータ版から卒業したことを誇りに思います。このリリースでは、安定版の Karpenter API、すなわち NodePoolEC2NodeClass が今後の 1.0 マイナーバージョンリリースでも同様に利用可能で、マイナーリリース間で互換性のない変更が加えられることはありません。この記事では、現行の Karpenter v0.37 と v1.0.0 の変更点について説明します。

v1.0.0 の変更点

v1.0.0 リリースの一環として、カスタムリソース定義 (CRD) のアプリケーションプログラミングインターフェイス (API) グループと Kind 名は変更されていません。また、ベータ版から安定版への移行をよりシームレスにするために、変換用の Webhook を作成しました。Karpenter の v1 (v1.1.0) 以降のマイナーバージョンでは、v1beta1 API のサポートを廃止する予定です。以下に新機能と変更点の概要を示します。

中断理由ごとの中断制御の強化

Karpenter リリース v0.34.0 では、Karpenter がノードを終了する方法とタイミングをユーザーに制御させる中断制御が導入されました。これにより、コスト効率、セキュリティ、アプリケーションの可用性のバランスを改善することができます。この中断予算 (Disruption Budgets) は、表現力のある cron 構文に従い、特定の時間帯、曜日、時間、分に適用されるようスケジューリングできるため、アプリケーションの可用性をさらに保護できます。Karpenter の設定で disruption ブロックに設定がない場合、デフォルトでは常に 10% のノードの中断に制限されます。

Karpenter v1 は、中断理由ごとの中断予算をサポートしました。サポートされるのは UnderutilizedEmptyDrifted です。これにより、ユーザーは特定の中断理由に適用される中断予算をより細かく制御できるようになります。たとえば、次の中断予算は、ユーザーが以下のようなコントロールを実装する方法を定義しています。

  • 月曜日から金曜日の 9:00 UTC から 8 時間の間は、Drifted もしくは Underutilized の場合でもノードの 0% が中断の対象になります
  • すべての時間において、Empty の場合はノードの 100% が中断の対象になります
  • その他の時間帯では、 Drifted もしくは Underutilized の場合にノードの 10% の中断が許可されます。ただし、より厳しい予算設定が有効でない場合に限ります。

ユーザーは、このバジェットを使用して、アプリケーショントラフィックのピーク時に空きノードを終了し、コンピューティングを最適化できます。中断理由が設定されていない場合、中断予算はすべての中断理由に適用されます。

...
 disruption:
  budgets:
  - nodes: “ 0 ”
    schedule: "0 9 * * mon-fri"
    duration: 8h 
    reasons:
    - Drifted 
    - Underutilized 
  - nodes: "100%"
    reasons:
    - Empty 
  - nodes: "10%"
    reasons:
    - Drifted 
    - Underutilized 
...

統合ポリシー名を WhenUnderutilized から WhenEmptyOrUnderutilized に変更

統合ポリシーの WhenUnderutilized の名称が WhenEmptyOrUnderutilized に変更されました。v1beta1 のときと機能は同じで、consolidationPolicy=WhenUnderutilized の場合、Karpenter は部分的に利用されているノードまたは空のノードを統合します。新しい名前 WhenEmptyOrUnderutilized は、条件を明示的に正しく反映しています。

apiVersion: karpenter.sh/v1 
 kind: NodePool 
 metadata:
  name: default 
 spec:
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized 

低利用ノードの統合制御 consolidateAfter

Karpenter は、スケジューリングされた Pod の数が最小になるようにノードを統合することを優先します。需要の急激な増加や中断可能なジョブがあるワークロードを持つユーザーは Pod の入れ替えが多く発生する可能性があるため、Karpenter のノードを統合しようとする速度を調整できるようにしてほしいと要望していました。以前は、consolidateAfterconsolidationPolicy=WhenEmpty の場合のみ使用できました。つまり、最後の Pod が削除された時のみ適用されました。consolidateAfter は、現在 consolidationPolicy= WhenEmptyOrUnderutilized でも使用できるようになりました。これにより、ユーザーは Pod が追加または削除された後、Karpenter が統合を行うまでの時間を時間、分、秒単位で指定できるようになりました。v1beta1 の WhenUnderutilizedと同じ動作を望む場合は、consolidationPolicy=WhenEmptyOrUnderutilized にし、consolidateAfter0m に設定してください。

新しい中断制御 terminationGracePeriod

クラスター管理者は、Karpenter 内でノードの最長ライフタイムを強制する方法を求めており、それがセキュリティ要件に準拠していることが望ましいです。Karpenter は、Pod Disruption Budget (PDB)、Pod の terminationGracePeriodSeconds、および karpenter.sh/do-not-disrupt アノテーションを尊重することで、ノードを適切に中断します。これらの設定が誤っていた場合、Karpenter はノードの中断を無期限に待ち続けるため、クラスター管理者が新しい Amazon Machine Image (AMI) をロールアウトできなくなります。

そのため、terminationGracePeriod が導入されました。terminationGracePeriod は、ノードが強制的に削除される前に drain できる最大時間です。またノードの有効期限を過ぎても置換ノードを待機しません。ノードの最大ライフタイムは、terminationGracePeriod + expireAfter です。この変更に伴い、expireAfter の設定も disruption ブロックから template.spec に移動されました。

次の例では、クラスター管理者が NodePool を構成して、ノードが 30 日後に drain 開始するようにし、強制終了される前に 24 時間の猶予期間を設けることで、既存のワークロード (長時間実行されるバッチジョブなど) が強制終了される前に完了する時間を十分に確保できます。

apiVersion: karpenter.sh/v1 
 kind: NodePool 
 metadata:
  name: default 
 spec:
  template:
    spec:
      terminationGracePeriod: 24h 
      expireAfter: 720h 
...

Drift フィーチャーゲートの削除

Karpenter の Drift 機能は、ノードが望ましい状態から外れた場合 (例えば古い AMI を使用している) に、そのノードを置き換えます。v1 では、Drift 機能が安定版に昇格し、フィーチャーゲートが削除されました。つまり、デフォルトでノードが ドリフトするようになりました。v1beta1 で Drift 機能のフィーチャーゲートを無効にしていたユーザーは、今後は中断理由ごとの中断予算を使用してドリフトを制御できます。

amiSelectorTerms の必須化

Karpenter v1beta1 API で amiSelectorTerms を指定せずに amiFamily を指定した場合、Karpenter はその AMI ファミリの新しいバージョンの Amazon EKS 最適化 AMI がリリースされると、Drift 機能を通じてノードを自動的に更新していました。これは、常に最新バージョンにアップグレードされるのが望ましいテスト用の環境では機能しますが、本番環境では望ましくない場合があります。Karpenter では、ユーザーに本番環境で AMI をピン留めすることを推奨しています。AMI の管理方法の詳細は、Karpenter のドキュメントを参照してください。

amiSelectorTerms は必須フィールドになり、新しい用語 alias が導入されました。alias は AMI ファミリーとバージョン (family@version) で構成されています。EC2NodeClassalias が存在する場合、Karpenter はそのファミリーの Amazon EKS 最適化 AMI を選択します。この新機能により、ユーザーは特定のバージョンの Amazon EKS 最適化 AMI を指定できるようになりました。設定できる Amazon EKS 最適化 AMI ファミリーは、AL2AL2023BottlerocketWindows2019Windows2022 です。次のセクションでは例を示します。

Amazon EKS 最適化 AMI の使用

この例では、Karpenter は Bottlerocket の v1.20.3 Amazon EKS 最適化 AMI でノードをプロビジョニングします。AWS が Bottlerocket Amazon EKS 最適化 AMI の新しいバージョンをリリースしても、ワーカーノードはドリフトしません。

apiVersion: karpenter.k8s.aws/v1 
 kind: EC2NodeClass 
 metadata:
  name: default 
 spec:
...
  amiSelectorTerms:
    - alias: bottlerocket@v1.20.3 
...

カスタム AMI の使用

EC2NodeClassalias 項目を指定しない場合、amiFamily で使用するユーザーデータを設定する必要があります。amiFamily は、AL2AL2023BottlerocketWindows2019Windows2022 のいずれかを設定して事前生成されたユーザーデータを選択するか、ユーザー自身がユーザーデータを提供する場合は Custom を設定できます。amiSelectorTerms 内の既存のタグ、名前、ID フィールドを使用して AMI を選択できます。Amazon EKS 最適化 AMI ファミリーのユーザーデータの注入例は、Karpenter のドキュメントにあります。

次の例では、EC2NodeClass がユーザー指定の AMI (ID “ami-123”) を選択し、Bottlerocket が生成するユーザーデータを使用します。

apiVersion: karpenter.k8s.aws/v1 
 kind: EC2NodeClass 
 metadata:
  name: default 
 spec:
...
  amiFamily: Bottlerocket 
  amiSelectorTerms:
    - id: ami-123   
...

Ubuntu AMI ファミリーの選択の削除

v1 以降、Ubuntu AMI ファミリーは削除されました。Ubuntu AMI を引き続き使用するには、amiSelectorTerms で最新の Ubuntu AMI ID に固定された AMI を構成できます。さらに、EC2NodeClassamiFamily: AL2 を参照すると、以前と同じユーザーデータ構成を取得できます。以下は例です。

apiVersion: karpenter.k8s.aws/v1 
 kind: EC2NodeClass 
 metadata:
  name: default 
 spec:
...
  amiFamily: AL2 
  amiSelectorTerms:
    - id: ami-123   
...

コンテナからのインスタンスメタデータサービスへのアクセスをデフォルトで制限

Amazon EKS のベストプラクティスでは、アプリケーションに必要な権限のみを付与し、ノードの権限を付与しないよう、Pod がノードに割り当てられた AWS Identity Access and Management (IAM) インスタンスプロファイルにアクセスできないよう制限することが推奨されています。そのため、デフォルトでは新しい EC2NodeClass では、ホップカウントを 1 (httpPutResponseHopLimit:1) に設定し、IMDSv2 (httpTokens: required) を要求することで、Instance Metadata Service (IMDS) へのアクセスがブロックされます。ホストネットワークモードを使用する Pod は引き続き IMDS にアクセスできます。ユーザーは、Amazon EKS Pod Identity または IAM roles for service accounts を使用して、Podに AWS サービスへのアクセス権限を付与する必要があります。

kubelet 設定を EC2NodeClass に移行

Karpenter では、kubelet 引数のサブセットを指定して追加のカスタマイズができます。Karpenter v1 では、kubelet 構成が EC2NodeClass API に移動しました。カスタムの kubelet 構成を提供し、単一の EC2NodeClass を参照する異なる kubelet 構成を持つ複数の NodePool がある場合は、複数の EC2NodeClass を使用する必要があります。Karpenter v1 の Conversion Webhooks はこの互換性を維持します。ただし、v1.1.x に移行する前に、ユーザーは NodePool を正しい EC2NodeClass を参照するように更新する必要があり、その結果ノードがドリフトします。

NodeClaims がイミュータブルに

Karpenter v1beta1 では NodeClaim の不変性は強制されませんでしたが、作成後にユーザーがこれらのオブジェクトに対して操作しないことを前提としていました。そのため、NodeClaim ライフサイクルコントローラーは初回のインスタンス起動後の変更に反応しないため、NodeClaim はイミュータブルになります。

NodePool の nodeClassRef フィールドすべての必須化と apiVersion フィールドの group への名称変更

Karpenter v1beta1 では、ユーザーが参照する NodeClassapiVersionkind を設定する必要はありませんでした。Karpenter v1 では、ユーザーはすべての nodeClassRef フィールドを設定する必要があります。さらに、nodeClassRefapiVersion フィールドは group に名前が変更されました。

...
  nodeClassRef:
    group: karpenter.k8s.aws 
    kind: EC2NodeClass 
    name: default 
...

Karpenter の Prometheus メトリクスの変更

Karpenter は、Karpenter コントローラーとクラスターのプロビジョニングステータスを監視できるように、Prometheus 形式のメトリクスをいくつか提供しています。Karpenter v1 リリースの一環として、v1beta1 のメトリクスの一部が変更されました。そのため、これらのメトリクスを使用するクエリを含むダッシュボードを使用しているユーザーは、更新する必要があります。メトリクスの変更の詳細リストについては、Karpenter v1 アップグレードドキュメントを確認してください。

計画済みの非推奨化機能の削除

この変更に伴い、v1 では以下のベータ版の非推奨機能が削除されました。

  • karpenter.sh/do-not-evict アノテーションは、アルファ版で Pod レベルの制御として導入されました。この制御は、Pod が実行されているノードに対する中断操作を無効にする
  • karpenter.sh/do-not-disrupt アノテーションに置き換えられました。karpenter.sh/do-not-evict アノテーションは、ベータ版を通して非推奨と宣言され、v1 では削除されました。
  • karpenter.sh/do-not-consolidate アノテーションは、アルファ版でノードレベルの制御として導入されました。この制御は、単に統合だけでなく中断操作を無効にする
  • karpenter.sh/do-not-disrupt アノテーションに置き換えられました。karpenter.sh/do-not-consolidate アノテーションは、ベータ版を通して非推奨と宣言され、v1 では削除されました。
    ConfigMap ベースの構成は v1beta1 で非推奨となり、v1 で完全に削除されました。この構成は、より簡単な CLI/環境変数ベースの構成に置き換えられました。
    クラスター名をその値に格納する karpenter.sh/managed-by タグのサポートは、eks:eks-cluster-name に置き換えられました。

新機能、変更点、廃止された機能の完全なリストについては、詳細な変更ログをお読みください。

移行パス

Karpenter の v1 API は API グループやリソースの変更を伴わないため、Kubernetes の Webhook conversion プロセスを利用して、ノードのロールアウトなしに API をインプレースでアップグレードできます。アップグレードする前に、NodePoolNodeClaimEC2NodeClass などの v1beta1 API をサポートする (0.33.0 以降の) Karpenter バージョンを使用している必要があります。

アップグレードプロセスの概要 (ベータ版から v1 への移行) は次のとおりです。

  1. 更新された v1 の NodePoolNodeClaimEC2NodeClass CRD を適用します
  2. Karpenter コントローラーを v1.0.0 バージョンにアップグレードします。この Karpenter バージョンは、API リクエストで v1 API スキーマに基づいて推論を開始します。アップストリームの Karpenter プロジェクトとプロバイダー (EC2NodeClass の変更) によって提供される Conversion Webhook を使用して、リソースは v1beta1 から v1 バージョンに自動的に変換されます。
  3. 次に、Karpenter v1.1.0 へのアップグレードに備えて、ユーザーは v1beta1 マニフェストを新しい v1 バージョンを使用するように更新する必要があります。この際、リリースの API 変更を考慮する必要があります。詳細については、v1 移行ドキュメントの「Before upgrading to v1.1.0」を参照してください。

詳細なアップグレードの手順については、Karpenter v1 移行ドキュメントを参照してください。

まとめ

この記事では、Karpenter v1.0.0 リリースと、新機能および変更点の概要について学びました。Karpenter を v1.0.0 にアップグレードする前に、完全な Karpenter v1 移行ドキュメントを読み、本番環境以外の環境でアップグレードプロセスをテストすることをお勧めします。質問やフィードバックがある場合は、Kubernetes Slack の #karpenter チャンネルまたは GitHub でフィードバックを共有してください。