Karpenterをインストールしてみた

## きっかけ
先日、AWS re:Invent 2024に参加しました。普段からEKSを利用していることもあり、re:Inventのセッションで紹介されたKarpenterが気になったため社内環境へKarpenterをインストールしてみました。
その時の結果を共有してみたいと思います。

## 前提
今回構築で利用する環境について記載します。

- RHEL 8.6
- aws-cli v2.9.19
- kubectl v1.29.0
- eksctl v0.199.0
- helm v3.14.3

多少バージョン古いものもありますが、手元にあった上記の環境を利用します。また、今回の導入時にeksctlは古いと怒られた(EKSクラスタのバージョンと互換性のないeksctlを利用していました)ので最新のもの(v0.199.0)にアップデートしています。

## 参考にしたもの
karpenter.shサイトに導入手順が掲載されていたため、今回は以下(以後、「参考サイト」
と記述します）に沿って導入してみました。
https://karpenter.sh/docs/getting-started/getting-started-with-karpenter/

## インストールしてみた

### 環境変数の設定
環境変数の設定は参考サイトとほとんど同じです。リージョンとnamespaceの変数のみ変更しています。
```shell
export KARPENTER_NAMESPACE="karpenter"
export KARPENTER_VERSION="1.1.1"
export K8S_VERSION="1.31"
export AWS_PARTITION="aws" 
export CLUSTER_NAME="${USER}-karpenter-demo"
export AWS_DEFAULT_REGION="ap-noatheast-1"
export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export TEMPOUT="$(mktemp)"
export ARM_AMI_ID="$(aws ssm get-parameter --name /aws/service/eks/optimized-ami/${K8S_VERSION}/amazon-linux-2-arm64/recommended/image_id --query Parameter.Value --output text)"
export AMD_AMI_ID="$(aws ssm get-parameter --name /aws/service/eks/optimized-ami/${K8S_VERSION}/amazon-linux-2/recommended/image_id --query Parameter.Value --output text)"
export GPU_AMI_ID="$(aws ssm get-parameter --name /aws/service/eks/optimized-ami/${K8S_VERSION}/amazon-linux-2-gpu/recommended/image_id --query Parameter.Value --output text)"
```

### CloudFormationの実行
CloudFormationを実行します。
```bash
$ curl -fsSL https://raw.githubusercontent.com/aws/karpenter-provider-aws/v"${KARPENTER_VERSION}"/website/content/en/preview/getting-started/getting-started-with-karpenter/cloudformation.yaml  > "${TEMPOUT}" \
&& aws cloudformation deploy \
  --stack-name "Karpenter-${CLUSTER_NAME}" \
  --template-file "${TEMPOUT}" \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameter-overrides "ClusterName=${CLUSTER_NAME}"
```

cloudformationで作成されたリソースは以下のとおりです。
AWSアカウントIDをマスキングしています。
![cf_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939499/3ad5935e-7710-cad5-95fc-95f501c74b84.png)

### clusterの作成
EKSクラスタを作成します。

用意したyamlファイルは以下のとおりです。

:::note warn
`amiFamily: AmazonLinux2` としていますが、もうすぐEOLなのでご注意ください。
:::


```yaml
cat <<EOF > kerpenter-cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: ${CLUSTER_NAME}
  region: ${AWS_DEFAULT_REGION}
  version: "${K8S_VERSION}"
  tags:
    karpenter.sh/discovery: ${CLUSTER_NAME}

iam:
  withOIDC: true
  podIdentityAssociations:
  - namespace: "${KARPENTER_NAMESPACE}"
    serviceAccountName: karpenter
    roleName: ${CLUSTER_NAME}-karpenter
    permissionPolicyARNs:
    - arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:policy/KarpenterControllerPolicy-${CLUSTER_NAME}

iamIdentityMappings:
- arn: "arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME}"
  username: system:node:{{EC2PrivateDNSName}}
  groups:
  - system:bootstrappers
  - system:nodes


managedNodeGroups:
- instanceType: m5.large
  amiFamily: AmazonLinux2
  name: ${CLUSTER_NAME}-ng
  desiredCapacity: 2
  minSize: 1
  maxSize: 5

addons:
- name: eks-pod-identity-agent
EOF
```

作成したyamlファイルを用いてEKSクラスタを作成します。

```shell
$ eksctl create cluster -f kerpenter-cluster.yaml
```

kerpenter-cluster.yamlに従い、二つのNodeが作成されていることやEKSアドオンとしてvpc cni, CoreDNS, EKS Pod Identity Agent,kube-proxyが導入されていることなどを確認しています。（画像は時間の都合上、割愛いたします）


### Karpenterのインストール(失敗)
以下、何度かKarpenterのインストールに失敗したのでその時の記録を以下に記述します。

```shell
$ helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter --version "${KARPENTER_VERSION}" --namespace "${KARPENTER_NAMESPACE}" --create-namespace \
  --set "settings.clusterName=${CLUSTER_NAME}" \
  --set "settings.interruptionQueue=${CLUSTER_NAME}" \
  --set controller.resources.requests.cpu=1 \
  --set controller.resources.requests.memory=1Gi \
  --set controller.resources.limits.cpu=1 \
  --set controller.resources.limits.memory=1Gi \
  --wait 
```

上記を実行した結果、以下のエラーが出力されます。
```shell
Error: UPGRADE FAILED: client rate limiter Wait returned an error: context deadline exceeded
```

`--timeout` を追加してみましたが問題は解消されず、導入したkarpenterのPodのログには以下が出力されていました。
```shell
panic: operation error SQS: GetQueueUrl, https response error StatusCode: 400, RequestID: XXX, AWS.SimpleQueueService.NonExistentQueue: The specified queue does not exist or you do not have access to it.

```
この後、いろいろと試行錯誤した結果、Githubで以下のissuesが投稿されていることを確認しました。
https://github.com/aws/karpenter-provider-aws/issues/6623

Spot instances を利用せず、Interruption機能を利用しない場合は以下のラインを削除して問題ないとのことです。
```shell
--set "settings.interruptionQueue=${CLUSTER_NAME}" \
```

### Karpenterのインストール(成功)
issues:6623に従い、以下のコマンドでKarpenterをインストールしました。
```shell
$  helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter --version "${KARPENTER_VERSION}" --namespace "${KARPENTER_NAMESPACE}" --create-namespace \
>   --set "settings.clusterName=${CLUSTER_NAME}" \
>   --set controller.resources.requests.cpu=1 \
>   --set controller.resources.requests.memory=1Gi \
>   --set controller.resources.limits.cpu=1 \
>   --set controller.resources.limits.memory=1Gi \
>   --wait \
>   --timeout 20m
 Pulled: public.ecr.aws/karpenter/karpenter:1.1.1
Digest: sha256:b42c6d224e7b19eafb65e2d440734027a8282145569d4d142baf10ba495e90d0
Release "karpenter" has been upgraded. Happy Helming!
NAME: karpenter
LAST DEPLOYED: Sun Dec 22 08:04:56 2024
NAMESPACE: karpenter
STATUS: deployed
REVISION: 5
TEST SUITE: None
```
### 導入したリソースを確認
helmにて導入されたリソースを確認してみます。
karpenterのnamespaceを指定しているのでnamespace:karpenterのリソースを確認してみます。

```shell
$ kubectl get all -n karpenter
NAME                             READY   STATUS    RESTARTS   AGE
pod/karpenter-6954f9548b-6p8m9   1/1     Running   0          7m27s
pod/karpenter-6954f9548b-qthd6   1/1     Running   0          7m27s

NAME                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/karpenter   ClusterIP   10.100.109.151   <none>        8080/TCP   3h39m

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/karpenter   2/2     2            2           3h39m

NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/karpenter-59d469c97c   0         0         0       3h39m
replicaset.apps/karpenter-6954f9548b   2         2         2       7m27s
```
2つのkarpenter podや ClusterIPのサービスが作成されていることが確認できました。

今回はKarpenterのインストール記録を記事にまとめました。
実際に動作を確認するにはnode poolなどのリソース作成が必要です。進展があればここでご報告したいと思います。
最後までお読みいただき、ありがとうございました！