Amazon Web Services ブログ

Karpenter が beta 版に昇格しました

イントロダクション

Karpenter は AWS によって開発された Kubernetes のノードライフサイクルマネージャーで、クラスターのノードの設定を最小化することを目的として、2021 年にリリースされました。この 1 年で、GitHub の Star 数は 4900 を超え、200 人以上のコントリビューターによるコードがマージされるなど、素晴らしい成長を遂げています。現在、Kubernetes Autoscaling Special Interest Group の一部として、Cloud Native Computing Foundation (CNCF) に寄贈されるプロセスにあります。

このような成長の一貫として、alpha 版で行われた数々の破壊的な変更に対処したくないというユーザーに対して、より厳格な安定性を保証する Kubernetes API の成熟の需要が高まっています。これは、プロジェクトの進化において重要なマイルストーンになります。この移行によって顧客は、beta 版が提供する API の安定性と成熟度の向上による恩恵を受けます。またこれは、後方互換性を優先するという我々からのコミットメントを示しています。顧客は将来的な破壊的な変更に悩まされる必要なく、新しい機能や機能の拡張を自信を持って採用できます。このリリースは、以前のリリースと同様に、オープンソースコミュニティからのフィードバックを取り入れています。

API の変更は、Karpenter のバージョン 0.32.0 リリースの一部として展開されます。既存の Deployment をこのバージョンにアップグレードする必要があります。この記事で移行パスの概略について説明しており、Karpenter アップグレードガイドでさらに詳しく説明されています。

既存の alpha API は非推奨となり、この単一のバージョンでのみ利用可能です。v0.33.0 のリリースから、Karpenter は v1beta1 API のみをサポートします。

Karpenter の API は alpha → beta → stable という成熟の過程をたどります。

alpha 版から beta 版への昇格には、この記事で強調している API の重大な変更を必要としました。beta 版から stable 版への昇格には、同じレベルの変更は必要ないと予測しています。

Kubernetes API の昇格プロセスについて興味がある方は、こちらの記事をご覧ください。

変更点について

stable v1 に到達するまでの過程において、alpha 版から beta 版への移行に際して API に重要な変更を加えました。ユーザーにとってよく問題となる API の領域を削除することによって、使いやすさを向上させるためです。これらの領域のひとつがネーミングでした。provisioner という言葉の使用に際して混乱が生じていて (ストレージの領域では、多重定義された用語)、ユーザーが考える必要がある概念の数を減らしたいと考えていました。

今回のリリースで、Karpenter は Provisioner・AWSNodeTemplate・Machine API を廃止し、NodePool・EC2NodeClass・NodeClaim を導入しました。全体的な視点を捉え、Node という単一の概念を中心に API を合理化しました。

ウォークスルー

API グループ と kind のネーミング

v1beta1 バージョンでは、以下の新しい API が導入されている一方で、既存の API は廃止されています。

  • karpenter.sh/Provisioner は karpenter.sh/NodePool になる
  • karpenter.sh/Machine は karpenter.sh/NodeClaim になる
  • karpenter.k8s.aws/AWSNodeTemplate は karpenter.k8s.aws/EC2NodeClass になる

これらのネーミングの変更にはそれぞれ、Karpenter の最新バージョンに更新する際に考慮する必要があるスキーマの変更が含まれます。各々の変更点と、新しい API 定義がどのようなものかを見てみましょう。

v1alpha5/Provisioner → v1beta1/NodePool

NodePool は Provisioner の後継として機能し、スケジューリング中に Node と Pod 間の互換性に影響を与える、設定ベースのパラメータ (要件、Taint、Label など)を公開します。また Karpenter のスケジューリングやデプロビジョニングの意思決定を微調整するための、振る舞いベースの設定も含まれています。

NodePool はインスタンスタイプとサイズの組み合わせを解決する一方で、ワークロードがリソースをリクエストする方法には制限を課します。これは、プロビジョニングとデプロビジョニングの動作のグルーピングを促進します。重要なのは、ポータブルな設定を維持するためには、プールにクラウド固有の設定を持つべきではないということです。

Karpenter の v1beta1 では、全ての振る舞いに関わらないフィールドは NodePool テンプレートのフィールド内部でカプセル化されます。Karpenter の場合、NodePool が NodeClaims をテンプレート化し、それらは Karpenter コントローラーによってオーケストレートされます。これは Deployment コントローラーによって Pod がテンプレート化されオーケストレーションされる、Deployment のコンセプトを反映しています。

NodePool の詳細については、ドキュメントをご覧ください。NodePool の例は以下のとおりです。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
...
spec:
  template:
    metadata:
      annotations:
        custom-annotation: custom-value
      labels:
        team: team-a
        custom-label: custom-value
    spec:
      nodeClassRef:
        name: default
      requirements:
      - key: karpenter.k8s.aws/instance-category
        operator: In
        values: ["c", "m", "r"]
      ...
      kubelet:
        systemReserved:
          cpu: 100m
          memory: 100Mi
          ephemeral-storage: 1Gi
        maxPods: 20
  disruption:
    expireAfter: 360h
    consolidationPolicy: WhenUnderutilized
Apache Configuration

spec の例を見ると、disruption という新しいセクションがあることに気がつくでしょう。これにより、Consolidation、Expiration、空のノードに関する以前の設定 (ttlSecondsAfterEmptyttlSecondsUntilExipredconsolidation.enabled) がグループ化されます。

NodePool マニフェストが適用される時に明示的に指定されていない場合、Karpenter は disruption をデフォルトで設定します。デフォルト値は以下で強調されています。こららのフィールドの振る舞いの詳細については、ドキュメントをご覧ください。

Field

Default

spec.disruption.consolidationPolicy WhenUnderutilized
spec.disruption.expireAfter 720h

v1alpha1/AWSNodeTemplate → v1beta1/EC2NodeClass

EC2NodeClass は AWSNodeTemplate の後継として機能し、Node の起動やブートストラッププロセスに影響するクラウドプロバイダー固有のフィールドを公開します。これには、使用したい Amazon Machine Image (AMI)、セキュリティグループ、サブネットの設定、更にはブロックストレージ、ユーザーデータ、インタンスメタデータの設定に関する詳細が含まれます。

Karpenter の spec.instanceProfile フィールドは EC2NodeClass から削除され、spec.role フィールドが選択されました。(訳注:spec.instanceProfile フィールドは v0.32.2 で追加されています。現在指定可能なフィールドについては、公式ドキュメントを参照してください。) Karpenter は、ユーザーが指定したロールが定義された EC2NodeClass に基づいて、インスタンスプロファイルを自動生成するようになりました。

既に非推奨となっていた管理対象外の起動テンプレートを参照するための spec.launchTemplateName フィールドが削除されました。そのため、このフィールドを使用している場合は、EC2NodeClass に移行する際に、管理対象外の起動テンプレートから、Karpenter が管理する起動テンプレートに移行する必要があります。

NodeClass の詳細については、ドキュメントをご覧ください。EC2NodeClass の例は以下のとおりです。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiFamily: Bottlerocket
  role: KarpenterNodeRole-karpenter-demo
  subnetSelectorTerms:
  - tags:
      karpenter.sh/discovery: karpenter-demo
  securityGroupSelectorTerms:
  - tags:
      karpenter.sh/discovery: karpenter-demo
  tags:
    test-tag: test-value
Apache Configuration

v1alpha5/Machine→ v1beta1/NodeClaim

Karpenter v0.28.0 では、Machine と呼ばれる新しいリソースタイプが追加されました。これにより、複数のノードのプロビジョニングが改善され、ネイティブの Kubernetes コントローラーがノードをクラスターに参加させながら、Karpenter がノードを管理および追跡できるようになりました。v0.28.0 以前の Karpenter のバージョンを使用している場合、このリソースタイプを使用することはできません。

v0.32.0 のリリースで、NodeClaim に変更されました。NodeClaim はクラスター管理者によって作成されることを意図したものではなく、かわりに Karpenter によって作成および削除されます。NodeClaim が機能するために何も変更する必要はないはずです。クラスター内のノードをトラブルシューティングする際に、Karpenter が管理しているノードのライフサイクルと状態を確認できます。

ラベルの変更

Karpenter の v1beta1 では、karpenter.sh/do-not-evictkarpenter.sh/do-not-consolidate の共通ラベルに変更が加えられました。これらは廃止され、karpenter.sh/do-not-disrupt という単一のラベルに統一されました。これらは Pod と Node の両方に適用でき、Karpenter がノードの中断や Pod の退避を実行することを防ぎます。

NodeClass の AMI、サブネット、セキュリティグループのためのより柔軟なセレクター

現在のセレクターの設定では、プロビジョニングされるノードに対して異なる設定を識別し使用する能力が、いくらか制限されていました。既存の動作では AND ロジックが適用されるため、様々なクラスターやリージョンで設定を一致させることが困難でした。これに対処するためにセレクターを拡張し、複数の条件を指定できるようにしました。これらの条件は OR ロジックを使って組み合わさるようになり、一致するものが特定されるまで、まとめて評価されることを意味します。

名前が my-name1 あるいは my-name-2 で、所有者が 123456789 または amazon の AMI を照合する場合の例は、以下のとおりです。

amiSelectorTerms:
- name: my-name1
  owner: 123456789
- name: my-name2
  owner: 123456789
- name: my-name1
  owner: amazon
- name: my-name2
  owner: amazon
Apache Configuration

subnetSelectorTermssecurityGroupSelectorTerms についても同様の設定を行うことができます。詳細については Karpenter のドキュメントをご覧ください。

securityGroupSelectorTerms:
- id: abc-123
  name: default-security-group # Not the same as the name tag
  tags:
    key: value
# Selector Terms are ORed
- id: abc-123
  name: custom-security-group # Not the same as the name tag
  tags:
    key: value
Apache Configuration

Drift がデフォルトで有効に

次のリリース (v0.33.0) から、Drift 機能はデフォルトで有効になります。Drift のフィーチャーゲートを指定しなかったら、この機能は有効であるとみなされます。Karpenter のコマンドライン引数で --feature-gates DriftEnabled=false を指定することで、Drift 機能を無効化できます。このフィーチャーゲートは core API (NodePool、NodeClaim) が v1 にバージョンアップされた時に、完全に削除される予定です。

移行パス

Karpenter コントローラーの AWS IAM ロールを更新する

Karpenter コントローラーは、AWS Identity and Access Management (AWS IAM) を使用して、AWS アカウント内で Amazon Elastic Compute Cloud (Amazon EC2) インスタンスを起動および操作する権限を付与します。アップグレードの一貫として、以下のとおり新しいアクセス権限ポリシーを作成します。

  1. ec2:RunInstancesec2:CreateFleetec2:CreateLaunchTemplate に、以前のタグキー karpenter.sh/provisioner-name の代わりに、タグベースの制約 karpenter.sh/nodepool を追加しました。
  2. iam:CreateInstanceProfileiam:AddRoleToInstanceProfileiam:RemoveRoleFromInstanceProfileiam:DeleteInstanceProfileiam:GetInstanceProfile といったアクションの許可を与えました。これらのアクセス権限は全てタグベースのポリシーによって制約され、コントローラーが作成に責務を持つインスタンスプロファイルのみを操作する権限を持っていることを保証します。これらは Karpenter が管理するインスタンスプロファイルをサポートするために必要です。

移行が完了し、以下の詳細の説明に従って新しいノードをロールアウトしたら、以前のアクセス権限ポリシーを安全に削除できます。

アクセス権限ポリシーの例は Karpenter の GitHub リポジトリにあります。またプロジェクトを開始する AWS CloudFormation テンプレートの一部として配布されています。

API の移行

alpha 版から新しい v1beta1 版の API に移行するには、まず新しい v1beta1 の Custom Resource Definitions (CRD) をインストールする必要があります。その後、Provisioner と AWSNodeTemplates の両方について、alpha 版 API に相当する beta 版 のリソースを作成する必要があります。Machine から NodeClaim への移行は、カスタムリソースを Provisioner から NodePool に移行する際に Karpenter によって管理され、ユーザーにとってはシームレスである点に注目してください。

NodePool と EC2NodeClass オブジェクトの作成を効率化するために設計されたコマンドラインユーティリティツールである karpenter-convert を紹介できることを嬉しく思います。以下に、このツールを効果的に利用するための手順を示します。

  1. コマンドラインユーティリティをインストールします。: go install github.com/aws/karpenter/tools/karpenter-convert/cmd/karpenter-convert@latest
  2. 各 Provisioner を NodePool に移行します。: karpenter-convert -f provisioner.yaml > nodepool.yaml
  3. 各 AWSNodeTemplate を EC2NodeClass に移行します。: karpenter-convert -f nodetemplate.yaml > nodeclass.yaml
  4. ツールによって生成された各 EC2NodeClass に対して、AWS IAM ロールを手動で指定する必要があります。ツールはプレースホルダー $KARPENTER_NODE_ROLE を残すので、実際のロール名に置き換える必要があります。

各 Provisioner のリソースについて、ノードを 1 つずつ入れ替えるか、全ての Provisioner ノードを一気に入れ替えるかを決定する必要があります。詳細な手順のガイドについては、以下のセクションに記載されています。

Drift による段階的なノードの入れ替え

Drift を有効にした状態で、クラスター内の各 Provisioner に対して次のアクションを実行します。

  1. alpha 版の CRD を v1beta1 に移行します。
  2. karpenter.sh/legacy=true:NoSchedule のような Taint を古い Provisioner に追加します。
  3. Karpenter の Drift は、その Provisioner によって所有される全てのマシン・ノードをドリフト済としてマークします。
  4. Karpenter の Drift は、新しい NodePool リソースのノードを代替ノードとして起動します。
    1. 現在、Karpenter は一度に 1 つのノードの入れ替えのみサポートしています。すなわち、Karpenter が 1 つの Provisioner 配下の全てのノードを入れ替えるには、時間がかかる場合があります。

強制的な削除

クラスター内の各 Provisioner について、以下のアクションを実行します。

  1. クラスター内に、v1alpha5 Provisioner・AWSNodeTemplate に対応する NodePool・EC2NodeClass を作成します
  2. kubectl delete provisioner <provisioner-name> --cascade=foreground で古い Provisioner を削除します
    1. Karpenter は、Provisioner によって所有される各々の Node を削除し、全ての Node に対して同時に排出を行い、Node が排出中の状態になったら新しく Pending 状態になった Pod 用の Node を起動します

手動での入れ替え

クラスター内の各 Provisioner について、次の操作を実行します。

  1. v1alpha5 のProvisioner・AWSNodeTemplate に対応する v1/beta1 NodePool・EC2NodeClass をクラスター内に作成します。
  2. 古い Provisioner に karpenter.sh/legacy=true:NoSchedule のような Taint を追加します。
  3. kubectl delete node <node-name> を実行して、Provisioner によって所有される各ノードを 1 つずつ削除します。

まとめ

この記事では、新しい API によって導入された変更を紹介し、コミュニティからのフィードバックによって形作られたこれらの変更の背景にある理由についての洞察を提供しました。Karpenter プロジェクトの成熟度の高まりを目の当たりにできてとれも嬉しいです。これらの変更の大部分は、最終的には stable v1 API に移行すると予想しています。これにより、幅広いユーザーベースが、ワークロードネイティブなノードのプロビジョニングにおける Karpenter の能力を最大限に活用できるようになります。

この記事では取り上げなかった廃止や変更が他にもいくつかあります。包括的な移行ガイドラインについては、Karpenter アップグレードガイドをご覧ください。

Karpenter を v0.32.0 にアップグレードする前に、リリースノートを全て読むことを推奨します。質問があれば、Kubernetes slack #karpenter チャンネルまたは GitHub までお気軽にご連絡ください。新機能の優先順位付けと開発に役立つフィードバックをお待ちしています。

翻訳はソリューションアーキテクトの後藤が担当しました。原文はこちらです。