Amazon Web Services ブログ

Karpenter のご紹介 – オープンソースの高性能 Kubernetes Cluster Autoscaler

11 月 29 日(米国時間)、Karpenter を本番環境で利用する準備が整ったことを発表しました。Karpenter は、AWS で構築された、柔軟で高パフォーマンスのオープンソース Kubernetes クラスターオートスケーラーです。アプリケーションの負荷の変化に応じて適切なサイズのコンピューティングリソースを迅速に起動することで、アプリケーションの可用性とクラスターの効率を向上させるのに役立ちます。また、Karpenter は、アプリケーションのニーズを満たすジャストインタイムのコンピューティングリソースを提供し、間もなくクラスターのコンピューティングリソースのフットプリントを自動的に最適化して、コストを削減し、パフォーマンスを向上させます。

以前、Kubernetes ユーザーは、Amazon EC2 Auto Scaling グループKubernetes Cluster Autoscaler を使用するアプリケーションをサポートするために、クラスターのコンピューティング性能を動的に調整する必要がありました。AWS を利用している Kubernetes のお客様の半数近くが、Kubernetes Cluster Autoscaler を使用してクラスターのオートスケーリングを設定するのは困難で制限的であると報告しています。

Karpenter がクラスターにインストールされると、Karpenter はスケジュールされていないポッドの集約リソースリクエストを監視し、新しいノードを起動して終了する決定を下し、スケジュールのレイテンシーとインフラストラクチャのコストを削減します。Karpenter は Kubernetes クラスター内のイベントを監視し、Amazon EC2 などの基盤となるクラウドプロバイダーのコンピューティングサービスにコマンドを送信することでこれを行います。

Karpenter は Apache ライセンス 2.0 の下でライセンスされたオープンソースプロジェクトです。主要なクラウドプロバイダーやオンプレミス環境など、あらゆる環境で実行されている Kubernetes クラスターと連携するように設計されています。追加のクラウドプロバイダーを構築したり、プロジェクトのコア機能を改善したりするためのご意見を歓迎します。バグを見つけたり、提案があったり、役立てるものがあれば、GitHub で当社までご連絡ください。

AWS での Karpenter の使用開始
Kubernetes クラスターで Karpenter を使い始めるには、利用可能なコンピューティング性能があることを確認し、パブリックリポジトリにある Helm チャートを使用してインストールします。Karpenter には、選択したプロバイダーでコンピューティングリソースをプロビジョニングするアクセス許可も必要です。

クラスターにインストールされると、デフォルトの Karpenter プロビジョナーは受信 Kubernetes ポッドを監視します。Kubernetes Pod はクラスター内のコンピューティングリソースが不足しているためにスケジュールできず、スケジュールとリソースの要件を満たすために新しいリソースを自動的に起動します。

AWS での Karpenter の開始方法に基づいて、Amazon EKS クラスターで Karpenter をすばやく使用開始する方法を説明したいと思います。AWS Command Line Interface (AWS CLI)、kubectleksctl、および Helm (Kubernetes のパッケージマネージャー) をインストールする必要があります。これらのツールを設定したら、eksctl を使用してクラスターを作成します。この設定ファイルの例では、初期ノードが 1 つある基本クラスターを指定します。

cat <<EOF > cluster.yaml
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: eks-karpenter-demo
  region: us-east-1
  version: "1.20"
managedNodeGroups:
  - instanceType: m5.large
    amiFamily: AmazonLinux2
    name: eks-kapenter-demo-ng
    desiredCapacity: 1
    minSize: 1
    maxSize: 5
EOF
$ eksctl create cluster -f cluster.yaml

Karpenter 自体は、セルフマネージドノードグループマネージドノードグループAWS Fargate など、どこでも実行できます。Karpenter はお客様のアカウントで EC2 インスタンスをプロビジョニングします。

次に、AWS CloudFormation テンプレートと IAM Roles for Service Accounts (IRSA) を使用して必要な AWS Identity and Access Management (IAM) リソースを作成し、Karpenter コントローラーがドキュメントに従ってインスタンスの起動などのアクセス許可を取得できるようにする必要があります。また、Karpenter をクラスターにデプロイするには、Helm チャートをインストールする必要があります。

$ helm repo add karpenter https://charts.karpenter.sh
$ helm repo update
$ helm upgrade --install --skip-crds karpenter karpenter/karpenter --namespace karpenter \
  --create-namespace --set serviceAccount.create=false --version 0.5.0 \
  --set controller.clusterName=eks-karpenter-demo
  --set controller.clusterEndpoint=$(aws eks describe-cluster --name eks-karpenter-demo --query "cluster.endpoint" --output json) \
  --wait # for the defaulting webhook to install before creating a Provisioner

Karpenter プロビジョナーは、クラスター内の Karpenter の動作を設定できる Kubernetes リソースです。Karpenter がクラスター内のコンピューティングリソースをプロビジョニングするために必要なもの以外にカスタマイズを行わずに、デフォルトのプロビジョナーを作成すると、Karpenter はインスタンスタイプ、ゾーン、アーキテクチャ、オペレーティングシステム、インスタンスの購入タイプなどのノードプロパティを自動的に検出します。明示的なビジネス要件がない場合は、spec:requirement を定義する必要はありません。

cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: default
spec:
#Requirements that constrain the parameters of provisioned nodes.
#Operators { In, NotIn } are supported to enable including or excluding values
  requirements:
    - key: node.k8s.aws/instance-type #If not included, all instance types are considered
      operator: In
      values: ["m5.large", "m5.2xlarge"]
    - key: "topology.kubernetes.io/zone" #If not included, all zones are considered
      operator: In
      values: ["us-east-1a", "us-east-1b"]
    - key: "kubernetes.io/arch" #If not included, all architectures are considered
      values: ["arm64", "amd64"]
    - key: " karpenter.sh/capacity-type" #If not included, the webhook for the AWS cloud provider will default to on-demand
      operator: In
      values: ["spot", "on-demand"]
  provider:
    instanceProfile: KarpenterNodeInstanceProfile-eks-karpenter-demo
  ttlSecondsAfterEmpty: 30  
EOF

ttlSecondsAfterEmpty 値は、空のノードを終了するように Karpenter を設定します。この値を無効にすると、使用率が低いためにノードがスケールダウンすることはありません。詳細については、Karpenter サイトの「プロビジョナーのカスタムリソース定義 (CRD)」を参照してください。

Karpenter がアクティブになり、クラスター内のノードのプロビジョニングを開始する準備が整いました。デプロイを使用していくつかのポッドを作成し、Karpenter がそれに応じてノードをプロビジョニングするのを見守ります。

$ kubectl create deployment --name inflate \
          --image=public.ecr.aws/eks-distro/kubernetes/pause:3.2

デプロイをスケーリングして、Karpenter コントローラーのログを確認してみましょう。

$ kubectl scale deployment inflate --replicas 10
$ kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)
2021-11-23T04:46:11.280Z        INFO    controller.allocation.provisioner/default       Starting provisioning loop      {"commit": "abc12345"}
2021-11-23T04:46:11.280Z        INFO    controller.allocation.provisioner/default       Waiting to batch additional pods        {"commit": "abc123456"}
2021-11-23T04:46:12.452Z        INFO    controller.allocation.provisioner/default       Found 9 provisionable pods      {"commit": "abc12345"}
2021-11-23T04:46:13.689Z        INFO    controller.allocation.provisioner/default       Computed packing for 10 pod(s) with instance type option(s) [m5.large]  {"commit": " abc123456"}
2021-11-23T04:46:16.228Z        INFO    controller.allocation.provisioner/default       Launched instance: i-01234abcdef, type: m5.large, zone: us-east-1a, hostname: ip-192-168-0-0.ec2.internal    {"commit": "abc12345"}
2021-11-23T04:46:16.265Z        INFO    controller.allocation.provisioner/default       Bound 9 pod(s) to node ip-192-168-0-0.ec2.internal  {"commit": "abc12345"}
2021-11-23T04:46:16.265Z        INFO    controller.allocation.provisioner/default       Watching for pod events {"commit": "abc12345"}

プロビジョナーのコントローラーはポッドの変更をリッスンし、新しいインスタンスを起動し、プロビジョニング可能な Pod を新しいノードにバインドします。

ここで、デプロイを削除します。30 秒後 (ttlSecondsAfterEmpty = 30)、Karpenter は空のノードを終了するはずです。

$ kubectl delete deployment inflate
$ kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)
2021-11-23T04:46:18.953Z        INFO    controller.allocation.provisioner/default       Watching for pod events {"commit": "abc12345"}
2021-11-23T04:49:05.805Z        INFO    controller.Node Added TTL to empty node ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
2021-11-23T04:49:35.823Z        INFO    controller.Node Triggering termination after 30s for empty node ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
2021-11-23T04:49:35.849Z        INFO    controller.Termination  Cordoned node ip-192-168-116-109.ec2.internal   {"commit": "abc12345"}
2021-11-23T04:49:36.521Z        INFO    controller.Termination  Deleted node ip-192-168-0-0.ec2.internal    {"commit": "abc12345"}

kubectl でノードを削除すると、Karpenter は対応するインスタンスを正常に遮断、ドレイン、シャットダウンします。内部では、Karpenter はノードオブジェクトにファイナライザーを追加します。これにより、すべてのポッドがドレインされ、インスタンスが終了するまで削除をブロックします。

留意点
Karpenter の機能について、以下のように留意することがいくつかあります。

高速コンピューティング: Karpenter はあらゆる種類の Kubernetes アプリケーションと連携しますが、多数の多様なコンピューティングリソースの迅速なプロビジョニングとプロビジョニング解除を必要とするユースケースでは特に優れたパフォーマンスを発揮します。例えば、機械学習モデルのトレーニング、シミュレーションの実行、複雑な財務計算の実行を行うバッチジョブなどです。高速 EC2 インスタンスを必要とするユースケースには、nvidia.com/gpu、amd.com/gpu、aws.amazon.com/neuron のカスタムリソースを活用できます。

プロビジョナーの互換性: Karpenter プロビジョナーは、Amazon EKS マネージドノードグループや EC2 Auto Scaling グループなどの静的キャパシティー管理ソリューションと連携して動作するように設計されています。プロビジョナー、動的および静的に管理されたキャパシティーの混在モデル、または完全に静的なアプローチを使用して、キャパシティ全体を管理することができます。Kubernetes Cluster Autoscaler を Karpenter と同時に使用しないことをお勧めします。どちらのシステムも、スケジュール不能なポッドに対応してノードをスケールアップするためです。一緒に設定すると、両方のシステムがこのようなポッドのインスタンスを起動または終了するために競合します。

Karpenter コミュニティに参加
Karpenter のコミュニティは誰にでも開かれています。それを試して、ワーキンググループミーティングに参加するか、ロードマップに従って関心のある将来のリリースを受け取ってください。前述のとおり、バグレポート、新機能の提案、修正、追加ドキュメントなど、あらゆるご意見を歓迎します。

Karpenter の詳細については、AWS Container Day のドキュメントデモ動画をご覧ください。

Channy

原文はこちらです。