投稿日:
更新日:

EKS Auto Mode を覗いてみる

Authors

目次

banner.png

はじめに

昨年 12 月 2 日 - 6 日までの 5 日間に渡り、米 Las Vegas にて AWS re:Invent が開催されました。 今回は、次世代 SageMaker の発表や Bedrock・Knowledge Bases の機能強化、Nova のマルチモーダル画像・動画生成モデルの提供開始等、生成 AI に関する話題が盛りだくさんでした。

中でも個人的に興味深かったのが EKS Auto Mode の発表です。 これまでの EKS は、Control-Plane に関してある程度の機能がマネージドに提供されているものの、Google Kubernetes Engine(GKE) と比較してネイティブな Kubernetes を運用しなければならない印象でした。

また、手動でのクラスタアップグレードが必要な上、Data-Plane(ワーカーノード)の運用自動化も提供されておらず、ある程度インフラの知識を持ったエンジニアによる戦略的なメンテナンス作業が必要でした。

EKS Auto Mode では Kubernetes に必要なコンピュートリソース、ストレージシステム、ネットワーキング機能のプロビジョニング自動化等、従来の EKS と比較してクラスタの管理コストを大幅に下げることが期待できます。

今回は、そんな EKS Auto Mode の特徴や仕組みについて、個人的な所感を交えつつ紹介したいと思います。

EKS と運用上の課題

eks.png

Amazon Elastic Kubernetes Service(EKS) は AWS 上で Kubernetes をフルマネージドで実行するサービスとして多くの企業で採用されています。

しかし、導入や運用に際していくつかの課題が存在します。 従来の EKS は Control-Plane の管理やアップグレードを AWS が管理するのに対して、ワークロードを実行するノードは、プロビジョニングやスケーリングを基本的に利用者側で管理する必要がありました。

また、ノードのアップグレード作業は自前で実施する必要があり、付随する Addon のバージョン管理や Blue/Green 戦略等によるノードの入れ替えも全て利用者側で行わなければなりません。

Google Cloud には GKE Autopilot に代表される、ノードコンポーネントをクラウドプロバイダ側で管理してくれるソリューションがあります。 また、Standard edition でもノードのアップグレードを自動化する機能があり、EKS と比較して Kubernetes のメンテナンスに必要とされる大部分の作業コストを削減することが可能です。

以上のような背景を踏まえ、今回発表された EKS Auto Mode は、主にノードコンポーネントの運用負荷を下げる機能 が追加されています。

EKS Auto Mode

eks-auto-mode.png

Today at re:Invent, AWS announced Amazon Elastic Kubernetes Service (Amazon EKS) Auto Mode, a new feature that fully automates compute, storage, and networking management for Kubernetes clusters. Amazon EKS Auto Mode simplifies running Kubernetes by offloading cluster operations to AWS, improves the performance and security of your applications, and helps optimize compute costs.

本日 re:Invent において、AWS は Amazon Elastic Kubernetes Service(Amazon EKS)の Auto Mode を発表しました。 これは、Kubernetes クラスタのコンピューティング、ストレージ、およびネットワーキングの管理を完全に自動化する新機能です。 Amazon EKS Auto Mode は、クラスターの運用を AWS にオフロードすることで Kubernetes の実行を簡素化し、アプリケーションのパフォーマンスとセキュリティを向上させ、コンピューティングコストを最適化するのに役立ちます。

EKS Auto Mode の概要

EKS Auto Mode は、Control-Plane に加え、クラスタプロビジョニングやスケーリングの自動化、ワーカーノードのコンピュートリソース最適化、定期的なパッチ適用によるセキュリティの確保、他の AWS ソリューションとのシームレスな統合といった Kubernetes の運用負担を低減するための機能が追加されています。

特に、Addon やノードコンポーネントの管理が AWS 側の責務となったことで、メンテナンスに要する専門知識や作業コストの削減が期待されます。

責務の範囲

  • 従来の EKS
eks-responsibility-scope.png

従来の EKS では、主に Kubernetes における Control-Plane のみを AWS がマネージドに提供しており、ノードや、その他 Addon は利用者側で運用・メンテナンスする必要がありました。

  • EKS Auto Mode
eks-auto-mode-responsibility-scope.png

EKS Auto Mode では、Control-Plane に加えて Addon で提供されていた機能の一部は、マネージドコンポーネントとしてクラスタ作成時点で予めデプロイされます。

具体的に、AWS によって管理されるクラスタには以下のような機能が備わっています。

機能(マネージドコンポーネント)概要
CoreDNSクラスタ DNS
kube-proxyPod と Service のネットワーキング
AWS Load Balancer Controllerアプリケーションロードバランサのプロビジョニング
AWS EBS CSI Driverブロックストレージ制御ドライバ
Karpenterコンピュートノードの選択とオートスケーリング

クラスタに登録されたノード(ノードグループ)は EKS Auto Mode によって管理されます。 ここで、EKS Auto Mode が管理するノードは EKS Managed Node Groups とは別で、マネージドに提供される Karpenter が管理するノードプールとなります。

以前のように Cluster Autoscaler を追加してノードのスケールを設定する必要はなく、Karpenter 自体がリソースのリクエスト状況に応じて最適なノードを選択、スケーリングを管理します。 EKS Auto Mode では、Pod が縮退すると不要なノードは最低 0 台にスケールインされる ゼロスケールモデル となります。

機能

Automate cluster infrastructure with EKS Auto Mode を参考に、EKS Auto Mode の機能をまとめてみます。

クラスタ管理の簡素化

運用上のオーバヘッドを最小限に抑え、EKS に関する専門的な知識がなくてもリクエストに応じた動的なワークロードを実行できます。

アプリケーションの可用性

ワークロードのリソースリクエストに応じて、クラスタ内のノードを動的に追加・削除します。 これにより、手動によるキャパシティプランニングの必要性が最小限に抑えられ、アプリケーションの可用性が確保されます。

コストの効率性

NodePool およびワークロードの要件で定義された柔軟性を維持しながら計算コストを最適化します。 また、未使用のインスタンスをスケールインさせ、ワークロードを他のノードに統合してコスト効率を向上させます。

ノードプロビジョニングの自動化

ノードのインスタンスには、イミュータブルな AMI が使用されます。 開発者がワークロードの実行に必要な環境を自分で設定する必要はなく、EKS Auto Mode によって適切な AMI が自動的に選択・プロビジョニングされます。

オートスケーリング

EKS Auto Mode は、マネージドに組み込まれた Karpenter によって ゼロスケールモデルでノードをオートスケール させます。

クラスタのキャパシティが不足した場合、Karpenter はノードをスケールアウトさせて Pod をスケジュールします。 また、Pod が縮退し、リソースに空きができた場合は、不要なノードをスケールインします。

セキュリティ

EKS Auto Mode で使用される AMI にはロックダウンされた Security-Enhanced Linux(SELinux) が使用されるため、強制アクセス制御により読み取り専用のルートファイルシステムが提供されます。

EKS Auto Mode では、SSH や SSM によるノードへのリモート接続は許可されません。

また、EKS Auto Mode によって起動されたノードの最大寿命は 21 日間に限定 されており、その後は強制的に新しいノードに置き換えられます。

定期的なノードの入れ替えにより、セキュリティパッチや OS、コンポーネントのアップグレードが小まめに実施されるため、ワークロードへの影響を最小限に抑えつつ最新のソフトウェアや API を維持することが可能になります。

ノードの入れ替えは、PDB(Pod Disruption Budget)/ NDB(NodePool Disruption Budget)に従って自動的に実行されます。

PDB は Kubernetes の機能で、NDB は Karpenter の機能です。

クラスタアップグレード

Control-Plane をアップグレードすると、自動的に Data-Plane もアップグレード されます。

これまでは、Upgrade Insight 等を活用してアプリケーション側の準備をした上でアップグレード作業に移る必要がありましたが、これらの機能は EKS Auto Mode が実行してくれます。

ただし、自前でインストールした Addon がある場合は、別途アップグレードの対応が必要になります。

You are still responsible for updating:

  • Apps and workloads deployed to your cluster
  • Self-managed add-ons and controllers
  • Amazon EKS Add-ons

また、ノードのローリングアップグレード時にアプリケーションへの影響を避けるため、PDB の設定を必須化しておいた方が良いでしょう。

Auto Mode simplifies the version update process by handling the coordination of control plane updates with node replacements, while maintaining workload availability through pod disruption budgets.

マネージドコンポーネント

Kubernetes の機能や AWS の他のソリューションを統合するために必要となる Addon は、マネージドコンポーネントとしてクラスタを作成した時点で追加されます。 これにより、Addon のバージョン管理を利用者側で行う必要がなくなります。

マネージドコンポーネントでは主に次のような機能が提供されます。参考

  • Pod IP アドレスの割り当て
  • Pod ネットワークポリシの管理
  • ローカル DNS サービス
  • GPU プラグイン
  • ロードバランサコントローラとヘルスチェック
  • EBS CSI ストレージ

これらで提供されない機能(Metrics Server 等)を別途 Addon として追加することも可能です。

ただし、自前で追加したものに関しては EKS Auto Mode では管理されないため、これまでと同様の運用・メンテナンスが必要になります。

  • GPU のサポート

マネージドコンポーネントには GPU プラグインが含まれており、NVIDIA GPU や Neuron GPU 用のカーネルドライバと分離して管理されます。

GPU プラグインは、従来の EKS では Addon として追加する必要がありました。 また、Fargate ではサポートされていませんでした。

カーネルドライバとプラグインを分離することで、Kubernetes は GPU リソースを、より効率的に管理できるため高性能なワークロード実行が可能となります。

カスタマイズ可能な NodePool と NodeClass

ワークロードでストレージシステム、コンピュートエンジン、ネットワーク構成の変更が必要となる場合は、Custom NodePool / Custom NodeClass を作成して EKS Auto Mode に登録することで、自動的に最適なノードが払い出されます。

デフォルトの NodePool / NodeClass は変更できませんが、特定の要件を満たす Custom NodePool / Custom NodeClass を利用者側で追加できます。

NodePool / NodeClass はいずれも Karpenter のカスタムリソースとなります。

他の AWS ソリューションとの統合

EKS Auto Mode は、ロードバランサ、ストレージシステム、ネットワーキング、IAM に関して、他の AWS ソリューションとシームレスに統合されています。

ロードバランサ

EKS Auto Mode は Ingress クラスから ALB や NLB をプロビジョニングするための AWS Load Balancer Controller をネイティブにサポートしています。

これまでのように Addon や Helm 等で別途クラスタにデプロイする必要がないため、AWS Load Balancer Controller の運用を EKS Auto Mode にオフロードすることができます。

ストレージシステム

EKS Auto Mode では、クラスタ作成時点で EBS CSI Driver が利用可能となります。 利用者はストレージクラスを作成するだけで、リクエストに応じた EBS を自動的にプロビジョニングすることができます。参考

従来の EKS では、EBS / EFS CSI Driver もクラスタ作成後に利用者側で追加する必要がありましたが、EKS Auto Mode では管理をオフロードすることができます。

ただし、2025 年 1 月時点では EFS CSI Driver は未対応のようです。

ネットワーキング

従来の EKS ではクラスタのネットワーク設定や管理を手動で行う必要がありましたが、Auto Mode を使用すると、これらのネットワーク関連のタスクが自動化されます。

具体的には以下のタスクが EKS Auto Mode によって自動化されます。

  • Pod や Cluster Service の接続を自動で構成
  • IPv4 / IPv6 のデュアルスタックをサポート
  • セカンダリ CIDR ブロックの自動追加

ネットワーク周りの複雑な設定を AWS 側が自動的に調整してくれるため、手動によるネットワーク管理の負担を低減できます。

通常、Pod の台数が増加して VPC の CIDR ブロックが足りなくなると、新規に Pod やサービスを追加するのが難しくなりますが、EKS Auto Mode では セカンダリ CIDR ブロックを自動的に追加してくれるため、スケーラビリティを維持できます。

IAM

EKS Auto Mode は Kubernetes Service Account(KSA)と IAM ロールを紐付ける方法として Pod Identity をネイティブにサポートしています。 従来の EKS では、Pod Identity を使用するために Addon で Pod Idenitity Agent を追加する必要がありましたが、EKS Auto Mode ではクラスタを作成した時点でインストールされています。

これまで Pod に IAM ロールを付与する際は IAM Roles for Service Accounts(IRSA) が広く用いられてきましたが、今後は Pod Identity を基本的に使用し、EKS Pod Identity が使用できない場面では IRSA を使うことが推奨されています。参考

Pod Identity を使用すると、クロスアカウントやマルチクラスタ等においてリソースポリシの利用や、セッションタグによる属性ベースのアクセス制御が可能となります。

なお、Pod Identity が有効になっているクラスタで、従来の IRSA を引き続き利用することも可能です。

Pod Identity の全体像は以下のようになります。参考

eks-pod-identity.png

IRSA の場合は、Pod がデプロイされた際に Mutating Webhook を介して EKS OIDC Provider が発行した認証情報を受け取りますが、Pod Identity では EKS Pod Identity Agent から取得します。

eks-irsa-pod-identity-blog.png

EKS on Fargate との違い

EKS には、Auto Mode の他にも Fargate でノードを管理する EKS on Fargate というクラスタの運用方法があります。

サポート機能の比較

EKS Auto Mode と EKS on Fargate の違いをまとめると以下のようになります。

項目EKS Auto ModeEKS on Fargate
Control-Plane のアップグレード手動手動
Data-Plane(ノード)のアップグレード自動(Control-Plane アップグレード後に自動で実行)自動(Pod の再起動によるノード入れ替え)
ノードへの SSH / SSM××
イメージのキャッシュ〇(ノードにあれば)×
GPU ノードの利用×
Security Group for Pods×
Public IP を持つ Pod×
DaemonSet の作成×
特権コンテナの実行×
HostPort / HostNetwork×
課金(クラスタ以外)インスタンス単位Pod 単位
Spot インスタンスの利用×
Reserved Instances(RI)/ Savings Plan(SP)の利用RI / SP サポートSP のみサポート
GuardDuty Runtime Monitoring 対応×

アップグレード方法の違い

Control-Plane は、EKS Auto Mode と Fargate のいずれも手動でのアップグレードが必要となります。 Data-Plane のアップグレードは EKS Auto Mode の場合は Control-Plane アップグレード後に自動アップグレードされます。

また、自前で追加した Addon を除く、関連コンポーネントも自動的に更新されます。

一方の、Fargate は既存の Pod を削除、再作成することでバージョンアップされたノードが作成されます。

従来の EKS では Managed Node Groups が使用されていましたが、EKS Auto Mode では EKS Auto Mode Managed Instance と呼ばれる専用インスタンスが使用されるため、ノードのバージョン管理負担が低減されます。

リモート接続

EKS Auto Mode と Fargate は、ともに SSH / SSM でのリモート接続はできません。

EKS Auto Mode の AMI には SELinux が使用されており、読み取り専用のルートファイルシステムとなります。

また、Fargate には、そもそも接続できる EC2 インスタンスが存在しません。

ノードのログを確認する場合は、S3 バケット等、HTTP PUT 操作が可能なオブジェクトストレージにログを出力して確認します。

セキュリティと利便性のトレード・オフなので仕方ないですが、ログ調査はやや複雑になります。

イメージのキャッシュ

EKS Auto Mode は新規に Pod を立ち上げる際に、イメージキャッシュが効く可能性がありますが、Fargate はサーバレス実行となるためキャッシュは全く効きません。

ノードの種類

EKS Auto Mode は起動するノードのインスタンスタイプを指定することはできませんが、NodePool / NodeClass でインスタンスタイプを制限できます。 サポートされているインスタンスタイプには GPU 搭載のものも含まれています。

一方、Fargate は GPU ノードをサポートしていません。

Security Group for Pods

EKS Auto Mode では Pod 単位のセキュリティグループはサポートされていません。 ノード単位のセキュリティグループを利用します。

一方の Fargate は Pod 単位のセキュリティグループを利用できるため、EKS Auto Mode も今後サポートされるかもしれません。

ネットワークアクセス

EKS Auto Mode では HostPort / HostNetwork をサポートしていますが、Fargate は Pod がノードのホストネットワークに直接アタッチされる形態となるためサポートされていません。

また、EKS Auto Mode では Public IP を付与して Pod を直接公開できますが、Fargate はできません。

DaemonSet の作成

EKS Auto Mode では作成できますが、Fargate は作成できません。

課金体系

EKS Auto Mode はインスタンスタイプに応じて課金されます。

一方の Fargate は、タスクまたは Pod のリソースリクエスト、OS、CPU アーキテクチャ、ストレージリソースに基づいて課金されます。

また、EKS Auto Mode は Spot インスタンスの利用や、RI / SP がサポートされていますが、Fargate は Spot インスタンスを利用することはできず、SP のみのサポートとなります。

GuardDuty Runtime Monitoring

GuardDuty Runtime Monitoring はコンテナランタイムの脅威を検出する機能を提供しており、コンテナの権限昇格や不正なプロセスの実行を把握することができます。

GuardDuty Runtime Monitoring も、EKS Auto Mode ではサポートされていますが Fargate には対応していません。

所感

EKS Auto Mode と EKS on Fargate の違いは、サーバの実体を持つか否かに依存 します。 EKS Auto Mode は利用者側から確認できる EC2 インスタンスが存在しますが、Fargate はサーバレスソリューションです。

小規模なプロダクトにおいて最小限の労力で Kubernetes を利用したい場合は Fargate で十分要件を満たせると思います。

一方で、ノードに対してある程度の要件が定められている状況下では、Kubernetes における Data-Plane コンポーネントそのものの運用負担を低減できる EKS Auto Mode の方が有用だと思います。 双方では、似通った機能もあるため、要件を洗い出して適切なソリューションを判断する必要がありそうです。

EKS Auto Mode を使ってみる

EKS Auto Mode を軽く触ってみます。

プライベートサブネット内にノードプールを配置して、プライベートクラスタとして構築していきます。

sample-architecture.png

構築

今回は Terraform を使用しますが、コンソールから 「Quick configuration (with EKS Auto Mode) - new」 を選択して構築することもできます。

eks-configuration-01.png

Terraform ファイルの構成は以下のようにしています。

.
├── eks.tf       // EKS クラスタ定義
├── iam.tf       // IAM 定義
├── locals.tf    // 定数定義
├── provider.tf  // AWS Provider 定義
├── terraform.tf // Terraform バージョン定義
└── vpc.tf       // VPC 定義

terraform.tf

terraform {
  required_version = "1.11.2"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.94.1"
    }
  }
}

provider.tf

provider "aws" {
  region = "ap-northeast-1"
  assume_role {
    role_arn = "arn:aws:iam::123456789123:role/terraform" # Terraform 用の Admin IAM ロール
  }
}

locals.tf

locals {
  name                       = "eks-auto-mode-playground"
  cluster_version            = "1.31"
  access_entry_principal_arn = "arn:aws:iam::123456789123:role/ren510dev-playground" # クラスタを利用するユーザの IAM ロール
}

vpc.tf

resource "aws_eip" "eks_auto_mode_playground_eip" {
  count = 1

  tags = {
    Name = "${local.name}-eip"
  }
}

module "eks_auto_mode_playground_vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.19.0"

  name = "eks-auto-mode-playground"
  cidr = "10.0.0.0/16"

  azs = [
    "ap-northeast-1a",
    "ap-northeast-1c",
    "ap-northeast-1d",
  ]

  public_subnets = [
    "10.0.0.0/20",  # ap-northeast-1a public subnet
    "10.0.16.0/20", # ap-northeast-1c public subnet
    "10.0.32.0/20", # ap-northeast-1d public subnet
  ]
  public_subnet_tags = {
    "kubernetes.io/role/elb" = "1",
  }

  private_subnets = [
    "10.0.128.0/20", # ap-northeast-1a private subnet
    "10.0.144.0/20", # ap-northeast-1c private subnet
    "10.0.160.0/20", # ap-northeast-1d private subnet
  ]
  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = "1"
  }

  ### NAT Gateway: 単一の NAT Gateway を使用
  enable_nat_gateway     = true
  single_nat_gateway     = true
  one_nat_gateway_per_az = false
  reuse_nat_ips          = true
  external_nat_ip_ids    = aws_eip.eks_auto_mode_playground_eip.*.id

  ### VPN Gateway
  enable_vpn_gateway = false

  depends_on = [
    aws_eip.eks_auto_mode_playground_eip
  ]

  tags = {
    Name = local.name
  }
}

iam.tf

IAM ロールは、Control-Plane と Deta-Plane に付与します。

### AmazonEKSAutoClusterRole
resource "aws_iam_role" "eks_auto_mode_cluster_role" {
  name        = "eks-auto-mode-master-role"
  description = "Allows access to other AWS service resources that are required to operate Auto Mode clusters managed by EKS."

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

  tags = {
    Name = local.name
  }
}

resource "aws_iam_role_policy_attachment" "eks_auto_mode_cluster_role_cluster_policy" {
  role       = aws_iam_role.eks_auto_mode_cluster_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
}

resource "aws_iam_role_policy_attachment" "eks_auto_mode_cluster_role_block_storage_policy" {
  role       = aws_iam_role.eks_auto_mode_cluster_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSBlockStoragePolicy"
}

resource "aws_iam_role_policy_attachment" "eks_auto_mode_cluster_role_compute_policy" {
  role       = aws_iam_role.eks_auto_mode_cluster_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSComputePolicy"
}

resource "aws_iam_role_policy_attachment" "eks_auto_mode_cluster_role_load_balancing_policy" {
  role       = aws_iam_role.eks_auto_mode_cluster_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSLoadBalancingPolicy"
}

resource "aws_iam_role_policy_attachment" "eks_auto_mode_cluster_role_networking_policy" {
  role       = aws_iam_role.eks_auto_mode_cluster_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSNetworkingPolicy"
}

### AmazonEKSAutoNodeRole
resource "aws_iam_role" "eks_auto_mode_node_role" {
  name        = "eks-auto-mode-node-role"
  description = "Allows EKS nodes to connect to EKS Auto Mode clusters and to pull container images from ECR."

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Action = "sts:AssumeRole",
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })

  tags = {
    Name = local.name
  }
}

resource "aws_iam_role_policy_attachment" "eks_auto_mode_node_role_container_registry_pull_policy" {
  role       = aws_iam_role.eks_auto_mode_node_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly"
}

resource "aws_iam_role_policy_attachment" "eks_auto_mode_node_role_worker_node_minimal_policy" {
  role       = aws_iam_role.eks_auto_mode_node_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodeMinimalPolicy"
}

コンソールから手動で作成する場合は、IAM ロールの Use case ページから、それぞれ「EKS - Auto Cluster」と「EKS - Auto Node」を選択することで、自動的に AWS managed policy を追加することができます。

eks-configuration-02.png

Control-Plane

eks-configuration-03.png

Data-Plane

eks-configuration-04.png

eks.tf

module "eks_auto_mode_playground" {
  source  = "terraform-aws-modules/eks/aws"
  version = "20.35.0"

  cluster_name    = local.name
  cluster_version = local.cluster_version

  ### VPC
  vpc_id = module.eks_auto_mode_playground_vpc.vpc_id
  subnet_ids = [
    module.eks_auto_mode_playground_vpc.private_subnets[0], # ap-northeast-1a private subnet
    module.eks_auto_mode_playground_vpc.private_subnets[1], # ap-northeast-1c private subnet
    module.eks_auto_mode_playground_vpc.private_subnets[2], # ap-northeast-1d private subnet
  ]

  cluster_endpoint_private_access      = true
  cluster_endpoint_public_access       = true
  cluster_endpoint_public_access_cidrs = ["0.0.0.0/0"]

  authentication_mode                      = "API"
  enable_cluster_creator_admin_permissions = true

  ### Control-Plane
  create_iam_role = false
  iam_role_arn    = aws_iam_role.eks_auto_mode_cluster_role.arn

  ### Data-Plane
  cluster_compute_config = {
    enabled       = true # EKS Auto Mode 有効化
    node_pools    = ["general-purpose", "system"]
    node_role_arn = aws_iam_role.eks_auto_mode_node_role.arn
  }

  ### Cluster network
  cluster_service_ipv4_cidr = "172.20.0.0/16"
  cluster_ip_family         = "ipv4"

  ### IRSA
  enable_irsa = true

  ### Cluster zonal shift
  cluster_zonal_shift_config = {
    enabled = true
  }

  ### Cluster upgrade policy
  cluster_upgrade_policy = {
    support_type = "STANDARD"
  }

  ### Addons
  bootstrap_self_managed_addons = false
  cluster_addons                = {}

  ### Logging
  cluster_enabled_log_types = [
    "api",
    "audit",
    "authenticator",
    "controllerManager",
    "scheduler",
  ]

  depends_on = [
    module.eks_auto_mode_playground_vpc,
    aws_iam_role.eks_auto_mode_cluster_role,
    aws_iam_role.eks_auto_mode_node_role,
  ]

  tags = {
    Name = local.name
  }
}

resource "aws_eks_access_entry" "admin_entry" {
  cluster_name  = module.eks_auto_mode_playground.cluster_name
  principal_arn = local.access_entry_principal_arn
  type          = "STANDARD"

  tags = {
    Name = local.name
  }
}

resource "aws_eks_access_policy_association" "admin_policy" {
  cluster_name  = module.eks_auto_mode_playground.cluster_name
  principal_arn = aws_eks_access_entry.admin_entry.principal_arn
  policy_arn    = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"

  access_scope {
    type = "cluster"
  }

  depends_on = [
    module.eks_auto_mode_playground,
    resource.aws_eks_access_entry.admin_entry,
  ]
}

確認

前述の Terraform 一式を適用してクラスタを構築します。 10 分程度掛かりました。

クラスタ情報

eks-configuration-05.png

EKS Auto Mode が有効になっていることを確認します。

ノード

eks-configuration-06.png

初期状態では、NodePool のみ存在していて、実際のノード(EC2)は 1 台も起動していません。

ネットワーク

eks-configuration-07.png

Private Subnet 内のワークロードは NAT Gateway(EIP)を介して、外部ネットワークと通信します。

アクセスエントリ

eks-configuration-08.png

以下 4 つのアクセスエントリを付与しています。

  • クラスタ作成に使用した Terraform の IAM ロール
  • クラスタに接続するための IAM ロール
  • Data-Plane の IAM ロール
  • Control-Plane の IAM ロール

Addon

eks-configuration-09.png

クラスタ作成時点では何も追加されていません。

初期状態

  • クラスタへ接続
$ aws eks update-kubeconfig --name eks-auto-mode-playground --region ap-northeast-1
  • 初期構成の確認
### NodePool
$ kubectl get nodepools -o wide
NAME              NODECLASS   NODES   READY   AGE   WEIGHT   CPU   MEMORY
general-purpose   default     0       True    56m            0     0
system            default     0       True    56m            0     0

### Node
$ kubectl get nodes -o wide
No resources found

### Namespace
$ kubectl get namespace
NAME              STATUS   AGE
default           Active   60m
kube-node-lease   Active   60m
kube-public       Active   60m
kube-system       Active   60m

$ kubectl get pods -A -o wide
No resources found

クラスタ構築時点では、ノードやワークロードはデプロイされていません。

ワークロードの追加

ここで、ワークロード(Nginx)をデプロイします。

apiVersion: v1
kind: Namespace
metadata:
  name: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: nginx
spec:
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 80
          resources:
            limits:
              memory: '512Mi'
              cpu: '0.2'
            requests:
              memory: '256Mi'
              cpu: '0.1'
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: nginx
spec:
  type: ClusterIP
  selector:
    app: nginx-pod
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80

ワークロードを追加すると、ノードが一台起動し、Pod がスケジュールされることが分かります。

また、ノードの OS には Bottlerocket(amd64) という SELinux が使用されています。

bottlerocket.png
### ノード 確認
$ kubectl get nodes -o wide
NAME                  STATUS   ROLES    AGE   VERSION               INTERNAL-IP    EXTERNAL-IP   OS-IMAGE                                          KERNEL-VERSION   CONTAINER-RUNTIME
i-0a6b078d4c199f378   Ready    <none>   11m   v1.31.6-eks-aad632c   10.0.128.172   <none>        Bottlerocket (EKS Auto) 2025.1.9 (aws-k8s-1.31)   6.1.131          containerd://1.7.27+bottlerocket

### Pod 確認
$ kubectl get pods -A -o wide
NAMESPACE   NAME                                READY   STATUS    RESTARTS   AGE   IP             NODE                  NOMINATED NODE   READINESS GATES
nginx       nginx-deployment-7987c95c7f-qrsgv   1/1     Running   0          11m   10.0.128.192   i-0a6b078d4c199f378   <none>           <none>

Ingress の追加

EKS Auto Mode は Load Balancer Controller をネイティブにサポートしているため、別途 CRD 等を追加する必要はありません。

そのまま、IngressClass を追加します。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: alb
  labels:
    app.kubernetes.io/name: LoadBalancerController
spec:
  controller: eks.amazonaws.com/alb
$ kubectl apply -f ingress-class.yaml
ingressclass.networking.k8s.io/alb created

$ kubectl get ingressclass -o wide
NAME   CONTROLLER              PARAMETERS   AGE
alb    eks.amazonaws.com/alb   <none>       2m34s

Ingress を追加します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: nginx
  annotations:
    alb.ingress.kubernetes.io/load-balancer-name: nginx-ingress
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-svc
                port:
                  number: 80
$ kubectl get ingress -n nginx -o wide
NAME            CLASS   HOSTS   ADDRESS                                                    PORTS   AGE
nginx-ingress   alb     *       nginx-ingress-746646965.ap-northeast-1.elb.amazonaws.com   80      4m4s
eks-configuration-10.pngeks-configuration-11.png

以前と比べて、非常に手軽に ALB をプロビジョニングすることができました。

Karpenter

karpenter.png

EKS Auto Mode はノードのプロビジョニングやスケーリングの自動化に Karpenter を使用しています。

Karpenter の概要

Karpenter は、元々 AWS が開発したクラスタスケーリングを実現するためのツールです。

karpenter-provider-eks-github.png

現在は Kubernetes SIGs にて OSS として管理されています。

karpenter-github.png

Karpenter は 2020 年に最初のバージョンがリリースされ、当初は EKS のみをサポートしていましたが、現在では GKE や AKS でも利用することができます。

これまで EKS で Karpenter を使用するためには、利用者側で Addon もしくは Helm 等で追加して管理・運用する必要がありました。

一方で、EKS Auto Mode ではクラスタ作成時点で有効化されておりマネージドに提供されているため、NodePool / NodeClass を作成することで利用できます。

Cluster Autoscaler との違い

クラスタのオートスケールを実現する仕組みとして、もう一つ Cluster Autoscaler があります。

cluster-autoscaler-github.png

Cluster Autoscaler と Karpenter の違いについて紹介します。

コスト最適化

Karpenter は複雑な設定を必要とせずワークロードの要求を満たす最もコストの低い Instance Type の組み合わせでクラスタノード(EC2)を起動します。 Cluster Autoscaler を使用した場合でも複数の Instance Type の組み合わせでクラスタノードを起動させることはできますが、利用者自身でどの Instance Type を使用するかのかを全て指定する必要がありました。

また、Cluster Autoscaler の制約として使用する Instance Type は同じ数の CPU コア、同じキャパシティを持った RAM でなくてはなりません。参考

そのため、Karpenter は Cluster Autoscaler と比較して、不要なキャパシティを削減してコストを最適化することが可能です。

ノードの起動速度

端的に述べると、Karpenter は Cluster Autoscaler と比較してノードの起動速度が速くなります。

これは、Cluster Autoscaler が Managed Node GroupsAuto Scaling Groups(ASG) 経由でクラスタのインスンスサイズを調整するのに対して、Karpenter は、それ自体が直接クラスタのインスタンスサイズを調整します。 つまり、ASG に依存せず、直接 EKS Auto Mode Managed Instance を制御できるため、その分ノードの起動が速くなるというわけです。

cluster-scale-model.png

NodePool と NodeClass

Karpenter は NodePool と NodeClass の 2 種類のカスタムリソースで所望する Instance Type を定義します。

NodeClass は Karpenter が利用する AMI や、起動するサブネット、ノードに紐付けるセキュリティグループ等を(タグで)指定します。

apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: default
spec:
  ### AMI ファミリ
  amiFamily: AL2

  ### インスタンスに接続するサブネット(subnetSelectorTerms の配列内は OR で結合され、一つの Term は AND で結合される)
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: '${CLUSTER_NAME}'

  ### インスタンスにアタッチするセキュリティグループ
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: '${CLUSTER_NAME}'

  ### NodeID に使用する IAM インスタンスプロファイル(Role または instanceProfile のいずれかを指定する)
  instanceProfile: 'KarpenterNodeInstanceProfile-${CLUSTER_NAME}'

NodePool は Karpenter がどのタイプの EC2 をクラスタノードとして起動するかや、Karpenter のスケール挙動を指定します。

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    metadata:
      ### 全てのノードに付与されるラベル属性
      labels:
        role: app

      ### 全てのノードに付与されるアノテーション属性
      annotations:
        example.com/owner: 'my-team'

    spec:
      ### 参照するクラウドプロバイダのノードクラス
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default

      ### 必要に応じて Taints ラベルを付与することで Pod 配置を制御
      taints:
        - key: example.com/special-taint
          effect: NoSchedule

      ### ノードの初期化開始時に追加される Pod は Taints ラベルを許容し、完了後に Taints を削除する
      startupTaints:
        - key: example.com/another-taint
          effect: NoSchedule

      ### ノードが削除されるまでの生存期間(Never を設定すると有効期限を無効にできるがセキュリティ上の懸念が生じる)
      expireAfter: 720h | Never

      ### ノードが強制削除されるまでのドレイン期間(削除命令が実行されるとノードのドレインを開始する)
      terminationGracePeriod: 48h

      ### プロビジョニングされたノードのパラメータを制限(see: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#operators)
      requirements:
        - key: 'karpenter.k8s.aws/instance-category'
          operator: In
          values: ['c', 'm', 'r']
        - key: 'karpenter.k8s.aws/instance-cpu'
          operator: In
          values: ['4', '8', '16', '32']
        - key: 'karpenter.k8s.aws/instance-hypervisor'
          operator: In
          values: ['nitro']
        - key: 'karpenter.k8s.aws/instance-generation'
          operator: Gt
          values: ['2']
        - key: 'topology.kubernetes.io/zone'
          operator: In
          values: ['us-west-2a', 'us-west-2b']
        - key: 'kubernetes.io/arch'
          operator: In
          values: ['arm64', 'amd64']
        - key: 'karpenter.sh/capacity-type'
          operator: In
          values: ['spot', 'on-demand']

  ### Karpenter が統合対象とするノードの種類(不要なキャパシティを削減してコストを最適化します)
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized

    ### Pod がノードに追加・削除された後 Karpenter がノードを統合するまでの待機時間
    consolidateAfter: 1m

    ### Karpenter がノードをスケールダウンできる速度を制御
    budgets:
      - nodes: 10%
      - schedule: '0 9 * * mon-fri' ### 例:平日の AM 9:00 から 8 時間はデプロビジョニングさせない
        duration: 8h
        nodes: '0'

  ### クラスタの合計リソース数を定義(limits を超えて Karpenter はノードを追加できません)
  limits:
    cpu: '1000'
    memory: 1000Gi

  ### 選択される NodePool の優先順位(指定しない場合は weight=0 となり、値が大きいほど優先順位が高くなる)
  weight: 10

一点気をつけなければならないのが、Karpenter は EC2 instance rebalance recommendations に対応していないため、Spot インスタンスを利用する場合は 2 分以内に Pod が終了するように設定する必要があります。

一般に 2 分を超える Graceful Shutdown が必要な場面はそうそう無いと思いますが、PDB を設定している場合は競合しないように注意が必要です。参考

Node Affinity との棲み分け

現時点で、EKS Auto Mode において Node Affinity を使用することはできない と思われます。

Node Affinity は Data-Plane やワークロードに対して、どのゾーンやノードに配置するかを指示するための機能となっていますが、EKS Auto Mode では Karpenter がノードの割り当てルールを取り仕切っています。

そのため、予め決められたルールセット(NodePool と EC2NodeClass カスタムリソース等)に宣言的に定義されたマニフェストに基づいて、Karpenter が Pod のスケジュール先、ノードの配置先を決定します。

スケール戦略

EKS Auto Mode は Pod が要求するリソース量に応じてノードを自動的に追加します。 そのため、常設ノードに比べて、ワークロードの起動時間が通常よりも長くなることが懸念されます。

この点に関しては、PriorityClass を活用して、スケジュール優先度の低い Pod を常時稼働させておくことで、必要なノードを一定数確保しておくことができます。 いわゆる、Balloon と言われるテクニックです。

こちら で既に紹介されていましたが、Balloon Pod を利用することで、ノードの起動速度の改善に効果があるようです。

スケジュールベースでゼロスケール可能な KEDA と組み合わせれば、必要な時間帯のみノードをオーバープロビジョニングするようなことも可能になるみたいです。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: balloon
spec:
  cooldownPeriod: 300
  minReplicaCount: 0
  scaleTargetRef:
    name: balloon
  triggers:
    - metadata:
        desiredReplicas: '3'
        start: 30 8 * * *
        end: 00 18 * * *
        timezone: Asia/Tokyo
      type: cron

クラスタアップグレード

Control-Plane をマニュアルでアップグレードすることで、マネージドコンポーネントとノードもワンライナーで更新されます。

eks-upgrade-01.pngeks-upgrade-02.png
$ kubectl get node -o wide -w
NAME                  STATUS   ROLES    AGE    VERSION               INTERNAL-IP    EXTERNAL-IP   OS-IMAGE                                           KERNEL-VERSION   CONTAINER-RUNTIME
i-0e3fe4ed33df707d6   Ready    <none>   2d9h   v1.31.6-eks-aad632c   10.0.128.112   <none>        Bottlerocket (EKS Auto) 2025.1.11 (aws-k8s-1.31)   6.1.131          containerd://1.7.27+bottlerocket
i-0e3fe4ed33df707d6   Ready    <none>   2d9h   v1.31.6-eks-aad632c   10.0.128.112   <none>        Bottlerocket (EKS Auto) 2025.1.11 (aws-k8s-1.31)   6.1.131          containerd://1.7.27+bottlerocket
i-0c776b6e149074eb8   Ready    <none>   87s    v1.32.2-eks-677bac1   10.0.155.140   <none>        Bottlerocket (EKS Auto) 2025.1.11 (aws-k8s-1.32)   6.1.131          containerd://1.7.27+bottlerocket
eks-upgrade-03.png

従来の EKS で、(主にノードの)クラスタアップグレードを行う際は、事前に Addon バージョンの確認や、Blue/Green 等による戦略的な作業が要されました。

EKS Auto Mode では、Control-Plane のアップグレードに際して、関連するマネージドコンポーネント(CoreDNS / kube-proxy / Load Balancer Controller 等)やノードが、一律で整合性が取れるように自動的に更新されます。 この点、従来のアップグレード作業と比較して、かなり簡易化されている印象です。

ただし、単一クラスタでは、以前のバージョンにロールバックすることができない(クラスタを 2 台用意しての切り替え作業が必要となる)ため、シンプルさ故の懸念もいくつか残ります。

EKS Auto Mode への移行

EKS Auto Mode は 2024 年 12 月 1 日時点で Public Preview となっています。

EKS Auto Mode は、既存の EKS クラスタで有効にすることもできます。 ただし Kubernetes v1.29 以上であることが必須要件となります。

AWS は以下の移行をサポートしています。

  • Karpenter から EKS Auto Mode ノードへの移行
  • EKS Managed Node Groups から EKS Auto Mode ノードへの移行
  • EKS Fargate から EKS Auto Mode ノードへの移行

AWS は以下の移行をサポートしていません。

  • EBS CSI Controller から EKS Auto Mode Block Storage へのボリュームの移行
  • AWS Load Balancer Controller から EKS Auto Mode へのロードバランサの移行
  • 代替 CNI、またはその他のサポートされていないネットワーク構成を使用した EKS クラスタの移行

まとめ

今回のブログでは、先日 AWS re:Invent で発表された EKS Auto Mode について紹介してみました。

EKS Auto Mode は従来の EKS と比較してノードの運用負担を大幅に軽減することができ、クラスタの運用に要される知識も少なくて済む印象でした。 特に、アップグレード作業で負担となっていた、Addon のバージョン管理や、Blue/Green による戦略的な切り替えについて考えなくて済むのは非常に助かります。

一方で、従来の EKS で成熟された運用が確立されている場合や、サービス規模が非常に大きい場合、ノードスケジューリングの小回りのしずらさや、切り戻し作業のコスト等、いくつか懸念もあるなと率直に思いました。 このため、「EKS on Fargate < EKS Auto Mode < Native EKS」という並びで、どのクラスタモードを使用するかを慎重に検討していく必要がありそうです。

参考・引用