EKS Automodeのカスタムノードプールを作成するときはノードクラスの作成を忘れずに(組み込みノードプール無効化の場合)

EKS Automodeのカスタムノードプールを作成するときはノードクラスの作成を忘れずに(組み込みノードプール無効化の場合)

Clock Icon2025.04.07

結論

EKS Automode有効・組み込みノードプール無効で、クラスターを作成するとノードクラスやアクセスエントリは自動的に作成されません。

ノードクラスやアクセスエントリの設定を忘れずに行いましょう。

EKS Automodeのノードプール・ノードクラス

本ブログでは、ノードプール や ノードクラス といった概念が登場します。

聞き慣れない方は、以下をご確認ください。

https://dev.classmethod.jp/articles/eks-auto-mode-custom-node-pool/

前提

本ブログの環境では、Terraform経由でKubernetesとAWSリソースを管理しています。

EKS ClusterとKubernetesリソースで、Statefileを分割しています。

ディレクトリ構成は以下の形をとっています。

cluster/
  main.tf
  outputs.tf
  providers.tf
  variables.tf
  terraform.tfvars
kube/
  main.tf
  outputs.tf
  providers.tf
  variables.tf
  terraform.tfvars

カスタムノードプールのみ使うため、組み込みノードプールは無効にしていました。

cluster/main.tf
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.34.0"

# 省略
  cluster_compute_config = {
    enabled    = true
    node_pools = []
  }
# 省略

事象

ノードが起動せず、Podが作成できない事象が発生しました。

詳細

ノードプールを作成しました。

kube/main.tf
resource "kubernetes_manifest" "node_pool_general" {
  manifest = yamldecode(file("${path.module}/files/manifest/nodepool_general.yaml"))
}
files/manifest/nodepool_general.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: general
spec:
  template:
    spec:
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
      requirements:
        - key: "karpenter.sh/capacity-type"
          operator: In
          values: ["spot", "on-demand"]
        - key: "eks.amazonaws.com/instance-category"
          operator: In
          values: ["c", "m", "r"]
        - key: "eks.amazonaws.com/instance-cpu"
          operator: In
          values: ["2", "4", "8"]
        - key: "kubernetes.io/arch"
          operator: In
          values: ["amd64"]
    metadata:
      labels:
        workload: general

動作確認用にPodの起動を試しました。

kubectl run test-pod --image=nginx --restart=Never

しかし、Podが起動しません。

kubectl get pods
出力例
NAME       READY   STATUS    RESTARTS   AGE
test-pod   0/1     Pending   0          6s
kubectl  describe pods test-pod
出力例
Name:             test-pod
Namespace:        default
Priority:         0
Service Account:  default
Node:             <none>
Labels:           run=test-pod
Annotations:      <none>
Status:           Pending
IP:
IPs:              <none>
Containers:
  test-pod:
    Image:        nginx
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-9dl7m (ro)
Conditions:
  Type           Status
  PodScheduled   False
Volumes:
  kube-api-access-9dl7m:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason            Age               From               Message
  ----     ------            ----              ----               -------
  Warning  FailedScheduling  3s (x6 over 28s)  default-scheduler  no nodes available to schedule pods

kubectl describeコマンドで以下のメッセージが出ていました。

PodをスケジュールできるNodeが無いみたいです。

Warning FailedScheduling 3s (x6 over 28s) default-scheduler no nodes available to schedule pods

原因

ノードプールのステータスを確認したところ、ノードクラスが存在しない旨のメッセージがありました。

NodeClass not found on cluster

ノードクラスが存在せずノードプールが使えない状態になっており、結果ノードを作成できなかったようです。

組み込みノードプールを有効化して作成したときはノードクラスが自動的に作成されていたため、ノードクラスの作成を行っていませんでした。

どうやら組み込みノードプール無効化で作成すると、デフォルトのノードクラスは自動的に作成されないようです。

kubectl get nodepools.karpenter.sh
出力例
NAME      NODECLASS   NODES   READY   AGE
general   default     0       False   8m2s
kubectl describe nodepools.karpenter.sh
出力例
Name:         general
Namespace:
Labels:       <none>
Annotations:  karpenter.sh/nodepool-hash: 6272226517684250404
              karpenter.sh/nodepool-hash-version: v3
API Version:  karpenter.sh/v1
Kind:         NodePool
Metadata:
  Creation Timestamp:  2025-04-04T01:38:58Z
  Generation:          1
  Resource Version:    2313
  UID:                 86138198-83a8-44ee-8034-5733f17a7df6
Spec:
  Disruption:
    Budgets:
      Nodes:               10%
    Consolidate After:     0s
    Consolidation Policy:  WhenEmptyOrUnderutilized
  Template:
    Metadata:
      Labels:
        Workload:  general
    Spec:
      Expire After:  336h
      Node Class Ref:
        Group:  eks.amazonaws.com
        Kind:   NodeClass
        Name:   default
      Requirements:
        Key:       karpenter.sh/capacity-type
        Operator:  In
        Values:
          spot
          on-demand
        Key:       eks.amazonaws.com/instance-category
        Operator:  In
        Values:
          c
          m
          r
        Key:       eks.amazonaws.com/instance-cpu
        Operator:  In
        Values:
          2
          4
          8
        Key:       kubernetes.io/arch
        Operator:  In
        Values:
          amd64
      Termination Grace Period:  24h
Status:
  Conditions:
    Last Transition Time:  2025-04-04T01:38:58Z
    Message:               NodeClass not found on cluster
    Observed Generation:   1
    Reason:                NodeClassNotFound
    Status:                False
    Type:                  NodeClassReady
    Last Transition Time:  2025-04-04T01:38:59Z
    Message:
    Observed Generation:   1
    Reason:                ValidationSucceeded
    Status:                True
    Type:                  ValidationSucceeded
    Last Transition Time:  2025-04-04T01:38:58Z
    Message:               NodeClassReady=False
    Observed Generation:   1
    Reason:                UnhealthyDependents
    Status:                False
    Type:                  Ready
  Resources:
    Cpu:                  0
    Ephemeral - Storage:  0
    Memory:               0
    Nodes:                0
    Pods:                 0
Events:
  Type     Reason               Age                  From       Message
  ----     ------               ----                 ----       -------
  Normal   NodeClassReady       5m22s                karpenter  Status condition transitioned, Type: NodeClassReady, Status: Unknown -> False, Reason: NodeClassNotFound, Message: NodeClass not found on cluster
  Normal   Ready                5m22s                karpenter  Status condition transitioned, Type: Ready, Status: Unknown -> False, Reason: UnhealthyDependents, Message: NodeClassReady=False, ValidationSucceeded=Unknown
  Normal   ValidationSucceeded  5m22s                karpenter  Status condition transitioned, Type: ValidationSucceeded, Status: Unknown -> True, Reason: ValidationSucceeded
  Warning                       5m16s                karpenter  Failed resolving NodeClass
  Warning                       78s (x2 over 3m18s)  karpenter  Failed resolving NodeClass

対応

ノードクラスを作成して、ノードを作成できるようにします。

以下を参考にTerraformを修正します。

Amazon EKS のノードクラスを作成する - アマゾン EKS

ノードクラス作成

組み込みノードクラスを有効にすると、defaultという名前のノードクラスが作成されます。

前述の公式ドキュメント上に以下の記述があるため、独自に作成するノードクラス名をgeneralとしました。

独自に作成するノードクラスに default という名前を付けないでください。

kube/main.tf
# 追加
resource "kubernetes_manifest" "node_class" {
  manifest = yamldecode(templatefile("${path.module}/templates/manifest/nodeclass.yaml", {
    node_security_group_id   = data.tfe_outputs.cluster.values.eks.node_security_group_id
    node_role_name           = data.tfe_outputs.cluster.values.eks.node_iam_role_name
  }))
}

resource "kubernetes_manifest" "node_pool_general" {
  manifest = yamldecode(file("${path.module}/files/manifest/nodepool_general.yaml"))
}

セキュリティグループやIAM RoleはTerraform EKS Moduleで自動作成されるリソースを指定します。

subnetSelectorTerms:部分も置き換えが必要な場合があります。

今回はサブネット用のタグ(※1)で指定していますが、タグを設定していない場合はsubnet idを指定する形で設定します。

templates/manifest/nodeclass_general.yaml
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: general
spec:

  # Required: Subnet selection for node placement
  subnetSelectorTerms:
    - tags:
        kubernetes.io/role/internal-elb: "1"
    # Alternative using direct subnet ID
    # - id: "subnet-0123456789abcdef0"

  # Required: Security group selection for nodes
  securityGroupSelectorTerms:
  - id: ${node_security_group_id}
    # Alternative approaches:
    # - id: "sg-0123456789abcdef0"
    # - name: "eks-cluster-node-security-group"

  # Optional: Configure SNAT policy (defaults to Random)
  snatPolicy: Random  # or Disabled

  # Optional: Network policy configuration (defaults to DefaultAllow)
  networkPolicy: DefaultAllow  # or DefaultDeny

  # Optional: Network policy event logging (defaults to Disabled)
  networkPolicyEventLogs: Disabled  # or Enabled

  # Optional: Configure ephemeral storage (shown with default values)
  ephemeralStorage:
    size: "80Gi"    # Range: 1-59000Gi or 1-64000G or 1-58Ti or 1-64T
    iops: 3000      # Range: 3000-16000
    throughput: 125 # Range: 125-1000

  # Optional: Name of IAM role to use for EC2 instance role
  # If unspecified, EKS creates a role
  # If specified, you must create an access entry for this role as described above
  role: ${node_role_name}

ノードプールの設定で、指定しているノードクラスを今回作成したノードクラスに変更します。(default -> general)

files/manifest/nodepool_general.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: general
spec:
  template:
    spec:
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        # 作成したノードクラスを指定
        name: general
      requirements:
        - key: "karpenter.sh/capacity-type"
          operator: In
          values: ["spot", "on-demand"]
        - key: "eks.amazonaws.com/instance-category"
          operator: In
          values: ["c", "m", "r"]
        - key: "eks.amazonaws.com/instance-cpu"
          operator: In
          values: ["2", "4", "8"]
        - key: "kubernetes.io/arch"
          operator: In
          values: ["amd64"]
    metadata:
      labels:
        workload: general

Terraformで設定を適用します。

terraform -chdir=kube apply

※1 EKS Auto Mode のサブネットにタグを付ける - アマゾン EKS

アクセスエントリ作成

組み込みノードプール無効化時は、アクセスエントリは自動で作成されません。

こちらも作成します。

cluster/main.tf
resource "aws_eks_access_entry" "auto_mode" {
  cluster_name  = module.eks.cluster_name
  principal_arn = module.eks.node_iam_role_arn
  type          = "EC2"
}

resource "aws_eks_access_policy_association" "auto_mode" {
  cluster_name  = module.eks.cluster_name
  policy_arn    = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSAutoNodePolicy"
  principal_arn = module.eks.node_iam_role_arn

  access_scope {
    type = "cluster"
  }
}
terraform -chdir=cluster apply

動作確認

動作確認として、Podを起動してみます。

「出力例」のようにStatusRunningになればOKです。

kubectl run test-pod --image=nginx --restart=Never
出力例
$ kubectl get pods
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          3m2s

おわりに

初歩的なところですが、忘れそうと思ったのでブログにしました。

組み込みノードグループを無効化する場合は、ノードクラスの設定を忘れずに設定しましょう。

以上、AWS事業本部の佐藤(@chari7311でした。)

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.