KubernetesクラスターでNodeの自動スケーリングをするKarpenterがGA#reinvent

KarpenterがGAになったので触ってみました。実行できないPodが存在するとすぐにスケーリングしてくれますよ!

枡川です。
KubernetesクラスターでNodeの自動スケーリングをするKarpenterがGAになりました。

Today, AWS announced that Karpenter, a new open-source Kubernetes cluster autoscaling project, is now Generally Availble with version 0.5 and ready for use in production environments. Karpenter is a flexible, high-performance Kubernetes cluster autoscaler that helps improve application availability and resource utilization. Karpenter launches right-sized EC2 instances in response to changing application load in under a minute. These EC2 instances are based on the specific needs of a cluster’s workloads, such as compute, storage, acceleration, and scheduling requirements. Today, Amazon Elastic Kubernetes Service (EKS) supports clusters using Karpenter on AWS, although Karpenter is designed to work with any conformant Kubernetes cluster.
AWS Karpenter v0.5 Now Generally Available

KarpenterはAWS管理のプロジェクトですが、OSSとして公開されています。(リポジトリ)
先程引用した文ではEKSでKarpenterを使用することをサポートした旨が記載されておりますが、Karpenterは環境に関わらずKubernetes上で動作するように作られています。

何をスケーリングさせてくれるのか

Kubernetesには元々自動スケーリングのためにHPA(Horizontal Pod AutoScaler)やVPA(Vertical Pod AutoScaler)などが存在しています。
これらはKubernetesアプリケーションの実行単位であるPodをスケーリングさせる機能となります。
これらのPodをスケーリングさせる機能については下記ブログを参考にして下さい。

Podをスケーリングさせる機能があっても、土台となるNodeをスケーリングさせてくれないと真にスケーリングを実施できているとは言えません。
コンピューティングリソースが枯渇すればPodは追加できなくなるからです。(Pending状態で立ち上がらなくなったりします)
Podに合わせてNodeの自動スケーリングを実現するのがKarpenterとなります。

やってみた

現在はGAとなったタイミングですが、既に公式のドキュメント等は揃っており、チュートリアルも整備されています。

チュートリアルではeksctlで作成したクラスターに対してHelmでKarpenterをインストールします。
その後、Deploymentで指定するReplica数を変化させることでPod数を増減させ、その際の挙動を確認できます。
eksctlで簡単にKubernetesクラスターが立ち上がりますし、IAMロールもCloudFormationで作成することができます。
さっそくKarpenterの挙動を見ていきます。
まず、レプリカ数を0にしてDeproymentを作成します。

$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 0
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      terminationGracePeriodSeconds: 0
      containers:
        - name: inflate
          image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
          resources:
            requests:
              cpu: 1
EOF

この時点ではPodは存在しません。

$ kubectl get pods
No resources found in default namespace.

Nodeはeksctlで1つ作成されています。

$ kubectl get nodes
NAME                                          STATUS   ROLES    AGE   VERSION
ip-192-168-21-17.us-west-2.compute.internal   Ready    <none>   17m   v1.21.5-eks-bc4871b

レプリカ数を増やすコマンドを実行します。(スケーリングの速度が気になるのでここから実行時間を付けます)

$ kubectl scale deployment inflate --replicas 5  (2021-11-30 15:39:09)
deployment.apps/inflate scaled

ログを確認すると5秒後にはインスタンスを作成し始めています。

2021-11-30T15:39:14.899Z        INFO    controller.provisioning Launched instance: i-085e70fb5fce12d33, hostname: ip-192-168-96-10.us-west-2.compute.internal, type: t3a.2xlarge, zone: us-west-2d, capacityType: spot {"commit": "84b683b", "provisioner": "default"}

ログには現れませんでしたが、1分後にはインスタンスがReadyになっていました。

$ kubectl get nodes  (2021-11-30 15:40:15)
NAME                                          STATUS   ROLES    AGE   VERSION
ip-192-168-21-17.us-west-2.compute.internal   Ready    <none>   19m   v1.21.5-eks-bc4871b
ip-192-168-96-10.us-west-2.compute.internal   Ready    <none>   63s   v1.21.5-eks-bc4871b

80秒後過ぎにはPodもRunning状態になっていました。

$ kubectl get pods  (2021-11-30 15:40:33)
NAME                       READY   STATUS    RESTARTS   AGE
inflate-6b88c9fb68-2mb84   1/1     Running   0          84s
inflate-6b88c9fb68-2rj4f   1/1     Running   0          84s
inflate-6b88c9fb68-7zf4w   1/1     Running   0          84s
inflate-6b88c9fb68-98lfh   1/1     Running   0          84s
inflate-6b88c9fb68-srrlj   1/1     Running   0          84s

あくまでチュートリアルのケースであり状況によって変化するものと思われますが、スケーリングする速度は素晴らしいです。
次に、下記コマンドでdeploymentを削除します。

$ kubectl delete deployment inflate  ( 2021-11-30 15:40:47)
deleted

Podが無くなったことが2秒後には検知されています。

2021-11-30T15:40:49.755Z        INFO    controller.node Added TTL to empty node {"commit": "84b683b", "node": "ip-192-168-96-10.us-west-2.compute.internal"}

スケールインの際は30秒待ってインスタンスが削除されます。

2021-11-30T15:41:19.798Z        INFO    controller.termination  Cordoned node   {"commit": "84b683b", "node": "ip-192-168-96-10.us-west-2.compute.internal"}
2021-11-30T15:41:19.961Z        INFO    controller.termination  Deleted node    {"commit": "84b683b", "node": "ip-192-168-96-10.us-west-2.compute.internal"}

所感

GAになったばかりでありまだまだこれから機能やドキュメントが追加されていくであろう状況ですが、Podの追加に合わせてNodeがあっという間に立ち上がる様は圧巻です。
Cluster Autoscalerとの比較も含めていろいろ試してみたい気持ちでいっぱいです。
皆さんも是非試して見て下さい!