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 ポリシーが必要になる。
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
name: default
spec:
〜略〜
# Optional: Additional EC2 tags
tags:
Environment: "production"
Team: "platform"
ユーザーがタグを付与したい場合、クラスター IAM ロールに以下の IAM ポリシーを追加する。
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 にたどり着くまでに時間がかかってしまった。アクセスエントリに早く移行しよう。
Karpenter で作成される Node を削除するときの finalizer 処理
コードを追いながら「おそらくこういう処理だろう」という感じがわかったのでメモを残す。
正しいかどうかわからないので是非コメントいただければと思います。
ざっくりとした流れ
Node が削除されるときの流れは以下ドキュメントに記載があります。
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 がそのリクエストを受け取ってオブジェクトの削除処理を始めます。
API Server は、Delete 処理内の BeforeDelete 処理で、オブジェクトのメタデータに deletionTimestamp フィールドを追加します。
Karpenter 側
Node リソースの Reconcile で deletionTimestamp フィールドが追加されたことを検知し、finalize 処理が始まります。
NodeClaim 側の finalize 処理はこちら
finalize 処理の中で、冒頭記載した処理を実行していきます。
リソースが削除可能になったら finalizer が削除され、API Server がリソースを削除します。
ちなみに、finalizer で指定される "karpenter.sh/termination" はここに定義され、
指定の finalizer が設定されているかの判定で使われている。