血と汗となみだを流す

血と汗となみだを流す

個人の思ったこと、やったことの吐き出し口です。

EKS Auto Mode で NodeClaim が Error getting launch template configs になる

現象

$ kubectl describe nodeclaim (nodeclaim name) すると以下のような感じで「Error getting launch template configs」が発生して NodeClaim リソースが Unknown になる。

Status:
  Conditions:
    Last Transition Time:  2024-12-18T04:37:19Z
    Message:               object is awaiting reconciliation
    Observed Generation:   1
    Reason:                AwaitingReconciliation
    Status:                Unknown
    Type:                  Initialized
    Last Transition Time:  2024-12-18T04:37:19Z
    Message:               Error getting launch template configs
    Observed Generation:   1
    Reason:                LaunchFailed
    Status:                Unknown
    Type:                  Launched
    Last Transition Time:  2024-12-18T04:37:19Z
    Message:               Node not registered with cluster
    Observed Generation:   1
    Reason:                NodeNotFound
    Status:                Unknown
    Type:                  Registered
    Last Transition Time:  2024-12-18T04:37:19Z
    Message:               Initialized=Unknown, Launched=Unknown, Registered=Unknown
    Observed Generation:   1
    Reason:                ReconcilingDependents
    Status:                Unknown
    Type:                  Ready

原因

以下のページの NodeClass の定義にある「Optional: Additional EC2 tags」でタグを付与する場合、クラスター IAM ロールに追加の IAM ポリシーが必要になる。

docs.aws.amazon.com

apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: default
spec:
〜略〜
  # Optional: Additional EC2 tags
  tags:
    Environment: "production"
    Team: "platform"

ユーザーがタグを付与したい場合、クラスター IAM ロールに以下の IAM ポリシーを追加する。

docs.aws.amazon.com

EKS Auto Mode で NodeClass が InstanceProfileCreationFailed になる

原因

クラスターIAMロールを確認しましょう。
sts:TagSession が追加されています。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "eks.amazonaws.com"
      },
      "Action": [
        "sts:AssumeRole",
        "sts:TagSession"
      ]
    }
  ]
}

以下のドキュメントの「Update Cluster IAM Role」を参照してください。
docs.aws.amazon.com

Karpenter Controller を Fargate で動かしているけど NodeClaim が Unknown になる InvalidParameterValue: 'karpenter.k8s.aws/ec2nodeclass' is not a valid tag key

事象

Karpenter Controller Pod を Fargate で起動し、Pod Schedule を Karpenter にやってもらおうとしても Node が起動しない。
NodeClaim を調べたら以下のエラーが出ていた。

$ kubectl describe nodeclaim default-xxxx
~~~
creating instance, with fleet error(s), InvalidParameterValue: 'karpenter.k8s.aws/ec2nodeclass' is not a valid tag key. 
Tag keys must match pattern ([0-9a-zA-Z\\-_+=,.@:]{1,255}), and must not be a reserved name ('.', '..', '_index'); RequestLimitExceeded: Request limit exceeded.; UnfulfillableCapac...
~~~

原因(と思われるところ)

インスタンスメタデータのタグへのアクセスを許可すると、以下の制約が発生する。 docs.aws.amazon.com

インスタンスメタデータのタグへのアクセスを許可する場合、インスタンスタグキーが具体的な制限の対象になります。
コンプライアンスに違反すると、新しいインスタンスの起動が失敗したり、既存のインスタンスのエラーが発生します。制限は次のとおりです。

- 英字 (a-z、A-Z)、数字 (0-9)、および + - = . , _ : @ の各文字のみを含めることができます。
- スペースと / を含めることはできません。
- . (1 つのピリオド)、.. (2 つのピリオド)、または _index だけで構成することはできません。

詳細については、「タグの制限」を参照してください。

NodeClaim は karpenter.k8s.aws/ec2nodeclass などの / (スラッシュ) 付のタグを使用するため、上記のエラーが発生していた。

対処方法

AWS コンソールの [EC2]-[ダッシュボード]-[アカウントの属性]-[データ保護とセキュリティ]-[IMDS デフォルト]-[管理]から「メタデータ内のタグへのアクセス」を無効化した。

Karpenter Controller を Fargate で動かしているけど Pod が起動しない EC2MetadataRequestError

事象

Karpenter Controller Pod を Fargate で起動しようとしたら失敗。以下のエラーが出力された。

$ kubectl logs -n karpenter karpenter-db9c68466-8jzjj
panic: failed to get region from metadata server: EC2MetadataRequestError: failed to get EC2 instance identity document
caused by: RequestError: send request failed
caused by: Get "http://169.254.169.254/latest/dynamic/instance-identity/document": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

goroutine 1 [running]:
github.com/samber/lo.must({0x296ac40, 0xc000942dc0}, {0xc000a1fbf8, 0x1, 0x1})
        github.com/samber/lo@v1.46.0/errors.go:51 +0x1bb
github.com/samber/lo.Must[...](...)
        github.com/samber/lo@v1.46.0/errors.go:65
github.com/aws/karpenter-provider-aws/pkg/operator.NewOperator({0x347c438, 0xc000706f00}, 0xc000653980)
        github.com/aws/karpenter-provider-aws/pkg/operator/operator.go:110 +0x213
main.main()
        github.com/aws/karpenter-provider-aws/cmd/controller/main.go:32 +0x2a

原因(と思われるところ)

アカウントレベルでIMDS(インスタンスメタデータサービス)を有効化していなかった。

対処方法

AWS コンソールの [EC2]-[ダッシュボード]-[アカウントの属性]-[データ保護とセキュリティ]-[IMDS デフォルト]-[管理]からインスタンスメタデータサービスを有効化した。
メタデータのバージョンは「V2のみ(トークンは必須)」

Pod を削除して再起動したところ、無事 Fargate 上で Pod が起動した。

$ kubectl get pod -n karpenter -o wide
NAME                        READY   STATUS    RESTARTS   AGE     IP                NODE                                      NOMINATED NODE   READINESS GATES
karpenter-db9c68466-h844g   1/1     Running   0          4m21s   192.168.106.138   fargate-ip-192-168-106-138.ec2.internal   <none>           <none>
karpenter-db9c68466-jr8kt   1/1     Running   0          4m22s   192.168.76.92     fargate-ip-192-168-76-92.ec2.internal     <none>           <none>

補足

インスタンスメタデータサービスの有効化はリージョン単位で実行する必要がある。

Karpenter Controller の Pod が起動しない

現象

  • Karpenter Controller Pod が CrashLoopBackOff のまま起動しない。

エラーログ

$ kubectl logs -n kube-system karpenter-c66f6f595-xqq8x
panic: AWS.SimpleQueueService.NonExistentQueue: The specified queue does not exist or you do not have access to it.

goroutine 1 [running]:
github.com/samber/lo.must({0x2a44ee0, 0xc0007044e0}, {0x0, 0x0, 0x0})
        github.com/samber/lo@v1.46.0/errors.go:53 +0x1df
github.com/samber/lo.Must[...](...)
        github.com/samber/lo@v1.46.0/errors.go:65
github.com/aws/karpenter-provider-aws/pkg/controllers.NewControllers({0x3476bd8, 0xc0005eb590}, {0x348c408, 0xc000220b60}, 0xc000845188, {0x347bf30, 0x4d41c80}, {0x3487fa0, 0xc000b6f440}, {0x3447100, ...}, ...)
        github.com/aws/karpenter-provider-aws/pkg/controllers/controllers.go:73 +0x82f
main.main()
        github.com/aws/karpenter-provider-aws/cmd/controller/main.go:54 +0x5bb

原因

  • helm でインストールする際に serviceAccount の紐づけが出来ていなかった。
echo Your Karpenter version is: $KARPENTER_VERSION
helm registry logout public.ecr.aws
helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter --version "${KARPENTER_VERSION}" --namespace "${KARPENTER_NAMESPACE}" --create-namespace \
  --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${KARPENTER_IAM_ROLE_ARN} \
  --set settings.clusterName=${CLUSTER_NAME} \
  --set settings.clusterEndpoint=${CLUSTER_ENDPOINT} \
  --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

上記コマンドの環境変数部分 ${KARPENTER_IAM_ROLE_ARN} に値がセットされていなかった。

失敗/成功の比較

  • 起動失敗した Pod
$ kubectl describe pod -n kube-system karpenter-c66f6f595-xqq8x
〜略〜
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-v4f8t (ro)
〜略〜
  • 起動成功した Pod
$ kubectl describe pod -n kube-system karpenter-57b88c6f8f-cnslt
〜略〜
    Mounts:
      /var/run/secrets/eks.amazonaws.com/serviceaccount from aws-iam-token (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-fcr7h (ro)
〜略〜

helm インストール時にコマンドミスったせいで /var/run/secrets/eks.amazonaws.com/serviceaccount from aws-iam-token がマウントされていなかった。

Karpenter で起動した node がクラスターに登録されずに落ちる

現象

  • Karpenter で起動したクラスターが node として起動される前に落ちる。
  • AWS コンソールからは EC2 インスタンスは正常に起動しているが、kubectl get node しても表示されない。

エラーメッセージなど

  • NodeClaim 調査
$ kubectl describe nodeclaim default-cfxh5
〜略〜
    Last Transition Time:  2024-09-24T13:33:19Z
    Message:               Node not registered with cluster
    Reason:                NodeNotFound
    Status:                Unknown
    Type:                  Registered
〜略〜
  • kubelet のログ
$ sudo journalctl -u kubelet
〜略〜
Sep 24 11:59:54 ip-192-168-66-178.ec2.internal kubelet[2105]: E0924 11:59:54.270285    2105 kubelet_node_status.go:96] "Unable to register nodewith API server" err="Unauthorized" node="ip-192-168-66-178.ec2.internal"
〜略〜

原因

  • Karpenter で起動した node に付与する IAM ロールを aws-auth ConfigMap に追加するのを忘れてた

追加手順

eksctl create iamidentitymapping \
  --username system:node:{{EC2PrivateDNSName}} \
  --cluster "${CLUSTER_NAME}" \
  --arn "arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME}" \
  --group system:bootstrappers \
  --group system:nodes

確認

$ kubectl describe cm -n kube-system aws-authName:         aws-auth
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>

Data
====
mapRoles:
----
- groups:
  - system:bootstrappers
  - system:nodes
  rolearn: arn:aws:iam::[AWS_ACCOUNT_ID]:role/[karpenter controllerが使うIAMロール]
  username: system:node:{{EC2PrivateDNSName}}
- groups:
  - system:bootstrappers
  - system:nodes
  rolearn: arn:aws:iam::020243262758:role/KarpenterNodeRole-[CLUSTER_NAME]
  username: system:node:{{EC2PrivateDNSName}}

mapUsers:
----
[]


BinaryData
====

Events:  <none>

まとめ

kubelet が Unauthorized を出していた時点で認証周りだとは思っていたが、aws-auth にたどり着くまでに時間がかかってしまった。アクセスエントリに早く移行しよう。

docs.aws.amazon.com

Karpenter で作成される Node を削除するときの finalizer 処理

コードを追いながら「おそらくこういう処理だろう」という感じがわかったのでメモを残す。
正しいかどうかわからないので是非コメントいただければと思います。

ざっくりとした流れ

Node が削除されるときの流れは以下ドキュメントに記載があります。

karpenter.sh

1. Add the karpenter.sh/disruption=disrupting:NoSchedule taint to the node to prevent pods from scheduling to it.
2. Begin evicting the pods on the node with the Kubernetes Eviction API to respect PDBs, while ignoring all static pods, pods tolerating the karpenter.sh/disruption=disrupting:NoSchedule taint, and succeeded/failed pods. Wait for the node to be fully drained before proceeding to Step (3).
  - While waiting, if the underlying NodeClaim for the node no longer exists, remove the finalizer to allow the APIServer to delete the node, completing termination.
3. Terminate the NodeClaim in the Cloud Provider.
4. Remove the finalizer from the node to allow the APIServer to delete the node, completing termination.

翻訳

1. Pod がスケジューリングされないようにするため、ノードに karpenter.sh/disruption=disrupting:NoSchedule の taint を追加します。
2. Kubernetes Eviction API を使用してノード上の Pod の退避を開始し、PDB を尊重します。この際、すべての静的 Pod、karpenter.sh/disruption=disrupting:NoSchedule の taint を許容する Pod、および成功/失敗した Pod は無視します。ステップ(3)に進む前に、ノードが完全に drain されるのを待ちます。
3. 待機中に、ノードの基となる NodeClaim が存在しなくなった場合、API Server がノードを削除できるように finalizer を削除し、終了を完了します。
4. クラウドプロバイダーで NodeClaim を終了します。
5. AP IServer がノードを削除できるようにノードから finalizer を削除し、終了を完了します。

API Server 側

ユーザーまたはコントローラーがオブジェクトの削除をリクエストすると、API Server がそのリクエストを受け取ってオブジェクトの削除処理を始めます。

github.com

API Server は、Delete 処理内の BeforeDelete 処理で、オブジェクトのメタデータdeletionTimestamp フィールドを追加します。

github.com

Karpenter 側

Node リソースの Reconcile で deletionTimestamp フィールドが追加されたことを検知し、finalize 処理が始まります。

github.com

NodeClaim 側の finalize 処理はこちら

github.com

finalize 処理の中で、冒頭記載した処理を実行していきます。
リソースが削除可能になったら finalizer が削除され、API Server がリソースを削除します。

ちなみに、finalizer で指定される "karpenter.sh/termination" はここに定義され、

github.com

指定の finalizer が設定されているかの判定で使われている。

github.com

プライバシーポリシー