2024/12/1にre:InventでEKS Auto Modeが発表されました。AWSとしては、EKS Auto Modeを今後EKSを構築する時のスタンダードにしていきたいんだろうなと感じます。ただ、Auto ModeはEKSアドオンやKarpenterをはじめ、組み込みコンポーネントが隠蔽されており違いを知っておかないと戸惑う感じがあります。
今回はEKS Auto Modeを構築しつつ、どのような挙動なのか見ていきます。
EKS Auto Modeのコンセプト
EKS Auto Modeのコンセプトを見ると、クラスター管理をAWSにオフロードしてアプリケーション開発へフォーカスできることを狙っているようです。その例として、次の図が示されています。
これまでのEKSではアドオンやEC2インスタンスをユーザー管理していたのに対して、Auto Modeはストレージ/コンピュート/ロードバランサー管理をAWSが担保しEC2にも関与するようになっています。
Before Auto Mode
After Auto Mode
コンセプトから受ける印象と実際
コンセプト図から、EKS Auto Modeに次のような印象を抱きます。実際使ってみると期待に近いものの、一部は従来のEKS管理から楽になったかは悩ましい側面もあります。
- EKSアドオンはAWSが管理するためユーザーは導入不要になった
- EC2のオートスケールはAWSに完全お任せできる
- IngressからLB作成や管理、TargetGroup紐づけも任せられる
また、以下はコンセプトから読み解けないので気になります。
- Auto Mode管理のALBやEBS、EC2は引き続きユーザーが関与できるのか
- Helmはどうなるのか
- Podの水平スケールはどうなるのか
それぞれ見ていきましょう。
EKSアドオンはAWSが管理するためユーザーは導入不要になった
これは受けた印象に割と近いです。CoreDNSなど必須EKSアドオンを追加不要、Podも見えなくなったのでマネージドだなという印象と実感が揃っています。 一方で、ユーザーは必要なEKSアドオンを追加でき、そのPodはkubectlで確認、操作できます。
- ✔️: これまでEKSクラスターで必須といってもよかったCoreDNS、kube-proxy、VPC CNIはAuto Modeでは導入不要
- ✔️: Node LocalDNSも組み込みになった
- ✔️: AWS EBS CSI Driverも組み込みになった
- ✔️: EKSPod Identityt Agentも組み込みになった
- ✔️: 組み込まれたコンポーネントのPod等はkubectlで見えずNodeも利用しない
- ✔️: 組み込みにならなかったEKSアドオンはユーザーが任意で導入できる
- ⚠️: サードパーティEKSアドオンの新Kubernetesバージョン対応は引き続き待つ必要がある
- ⚠️: Mertics Serverは組み込まれておらず、組み込みじゃないEKSアドオンを追加するとPodが起動、Nodeも起動する
組み込みになったCoreDNS、kube-proxy、VPC CNIは事実上必須でしたが、これまでは全然手当なくてつらかったのが正直な感想です。Auto Modeで組み込まれたことは非常にうれしいです。 組み込みになったEKSアドオンのリソースはPodが見えないだけじゃなく、Nodeが存在しなくても動作するのが不思議な感覚ですが各Node上でsystemdサービスとして実行される1ので納得です。
とはいえ、ユーザーが追加したEKSアドオンはPodなどリソースが見えますし、Nodeも必要です。贅沢をいうなら、Metrics ServerはHPAでもKEDAでも必須なので組み込みEKSアドオンとして管理してほしかったです。
ユーザーが追加できるEKSアドオンの注意点として、3rdパーティのEKSアドオンが利用できるかはEKSのKubernetesに依存します。例えば、現在EKS 1.32が最新ですが3rdパーティEKSアドオンの多くは対応していません。各アドオン提供者の意欲に依存しているので、EKSアップグレードの可否がEKSアドオンに左右されうるのは嫌だなと感じます。
EC2のオートスケールはAWSに完全お任せできる
オートスケールがKarpenterに変わり、Karpenterコントローラーが完全お任せになりました。代わりにコストが上がってどっちかというと厳しい。
- ✔️: EKS Auto ModeでKarpenterコントローラーが組み込みになった
- ✔️: 組み込みノードグループ
general-purpose
は、SPOTを使わない・amd64でしかアプリケーションを動作しない・ストレージサイズは80GB固定・インスタンスタイプもある程度限定される - ✔️: 上を1つでも変えたい場合、自分でKarpenterのNodeClass2、NodePool定義を書く必要がある
- ⚠️: AMIは常に最新が利用される(自動パッチ)
- ❌: Auto Mode管理のノードは最大21日寿命でPDBを使った制御が必須
- ❌: EKS Auto Mode管理のKarpenterで作られたEC2は追加料金がかかる(+11-12%程度)
EKS Auto Modeのノード水平スケールはKarpenterなので、Karpenter 1.2以上を使っている人なら戸惑うことなく自分のNodeClassやNodePool定義を書くことができます。Cluster AutoScalerを使っている人には大きな体験の変更になります。
Auto ModeのKarpenterはOSS版Karpenterからカスタマイズが入っており、EC2NodeClassの代わりにNodeClassへ変更・NodePoolのフィールドキーが一部さし変わっています。特にNodeClassからamiSelector
がなくなったことでAMIを指定せずとも最新AMIが使われます。AMIを固定できないため、Linux系のセキュリティインシデント時の対応時に注意が必要そうです。
ノードの寿命はOSSでは無期限にできましたが、Auto Modeでは最大21日で入れ替わるのがユースケースによって厳しいです。また、寿命によるEC2の入替えタイミングはユーザーが制御できないため、PDBを使ってPodがどのように入れ替わるか制御する必要があります。PDBを指定しない場合、Podがいつの間にか0台という最悪のタイミングが起こりえます。
気になる点はコストです。EKS Auto Modeの組み込みKarpenterで起動したEC2インスタンスは追加料金が11-12%程度かかります。オンデマンド・スポットにかかわらず固定金額かかるので、単純にEKS Auto Modeにするとコストが12%程度上がると考えても差支えないでしょう3。また、組み込みノードプールはSpotが利用されないので、どのみち自分で書くことになります。
EC2の21日寿命の個人的所感
ゲームサーバーでよくある「インメモリにデータを持つサーバー」は、時にワールドサーバーと呼ばれる大量常時接続をさばき、長時間起動しっぱなしなサーバーを使うことがあります。ワールドサーバーの停止はゲームの停止を意味するため、サーバーの入れ替えタイミングを選ぶことになります。そう、寿命日数がハードリミットされると、ゲーム中入れ替えができないサーバーと致命的に相性が悪いんですね。
EKS Auto Modeでも従来のマネージドノードグループは使え、従来のマネージドノードグループ管理のEC2に21日制限はありません。このため、21日寿命が困るPodは従来のマネージドノードグループを使って回避になります。そんなー。
EC2コスト増加分の個人的所感
Karpenterコントローラー・従来EKSアドオンのPodが見えないことから、EC2コスト追加料金はこれらの稼働分としてかかっているのかなと感じます。しかし、自前で動かしてもKarpenterコントローラーで2Pod動作、EKSアドオン各種で6-10pod程度増える程度です。これに対して、EC2ノードごとにコストが上乗せされるのは納得感ありません。SPやRI、スポットでも1台当たり追加料金は変わらないので、費用低減策をしているほど負担が重くなって受け入れ難い感情を感じます。
IngressからLB作成や管理、TargetGroup紐づけも任せられる
LB管理をお任せできます。従来のAWS LoadBalancer Controller(ALBC)で作ったALBを、AutoModeにマイグレーションできないので高負荷環境なユーザーは注意が必要です。
- ✔️: EKS Auto ModeはElastic Load Balancingを管理するコントローラーを組み込みで持っている
- ✔️: ALBをIngressで管理できる
- ✔️: NLBをServiceで管理できる
- ✔️: TargetGroupだけ管理もできる
- ⚠️: ALBの挙動はAnnotationsからIngressClassParamsやIngressClassで設定に変わりnamespaceごとの違いを管理する方法が変わった
- ⚠️: 既存のALBをEKS Auto Modeに直接マイグレートできない
- ⚠️: 既存のTargetGroupBindingを利用するにはTargetGroupのタグを調整する
EKS Auto ModeではOSS版AWS LoadBalancer Controller(ALBC)がIngress Annotationsで設定したALB設定を、IngressClassParams・IngressClassで調整するように変わっています。もしもALBCを使っている既存EKSクラスターをAuto Modeに変更する場合、違いに気を付けましょう。
また、従来のEKSクラスターからAuto Modeに変更する場合、同一ALBにマイグレーションできません。ドキュメントに、DNSベースのトラフィックシフト(Route53の加重ルーティング)を使ってALBを切り替えるといいでしょう。4
ALBCでTargetGroupBindingを使っていてAuto Modeでも引き続き同じTargetGroupを用いるには、TargetGroupのタグにクラスター名を入れる必要があります。
eks:eks-cluster-name: EKSクラスター名
Auto Mode管理のALBやEBS、EC2は引き続きユーザーが関与できるのか
組み込みKarpenterで作られたEC2(Auto Mode管理ノード)へ、ユーザーはほぼ関与できなくなりました。EC2を直接消せなくなったのは安全ですが、一方で夜間停止時のアプローチ方法が1つ減りました。5
- ✔️: EKS Auto Modeで作成されたEC2、ALB、NLB、EBS等はAWSコンソールなど従来通り確認できる
- ✔️: Auto Mode管理のALBはユーザーが消せる
- ⚠️: Auto Mode管理のノード(EC2)はユーザーが消せない、ソフトウェア追加できない、SSH・SSM SesisonManagerでアクセスできない
AWSコンソールでEC2の状態を確認できるので、負荷状況などの確認は従来通りです。
マネージドインスタンスのドキュメントにある通り、EKS Auto Modeで起動したEC2はEKS管理下になりユーザー操作ができなくなりました。SSM SessionManagerでアクセスできないの悲しいですね。
Helmはどうなるのか
Auto Modeになっても、Helmは引き続きユーザー管理です。それはそう。そして、EKSで一番つらいのはHelmによるコントローラー更新だと考えているので難しさは解消していないなと感じます。Helmアップグレードをもっと安全に楽にしたい。
- ⚠️: EKS Auto Modeでもユーザーが自分で導入したHelmは自分で管理が必要
利用するHelmをすべて3rdパーティEKSアドオンにすれば楽になる、と考えてしまいそうですが、EKSアドオンごとにKubernetesバージョン対応を待つ必要があります。Kubernetes 1.32への対応が3/15時点でもあまり進んでない現状からすると、引き続き自前Helmで導入を選ばざるを得ないケースが多いでしょう。がんばりましょう。
とはいえ、Karpenter、AWS LoadBalancer Controller、EBS CSI Driver、Pod Identity Agent、Node LocalDNSの導入が省けるので多少は楽になりますね。コスト増加と見合ってるとは言い難いですが。
Podの水平スケールはどうなるのか
Auto ModeはNodeの水平スケールは管理しますが、Podの水平スケールは管理しません。
- ✔️: EKS Auto ModeはKubernetes標準のHPAが利用できる
- ⚠️: HPAで必要なMetrics ServerはEKS Addonや自前Helmで追加が必要
- ⚠️: KEDAを使うなら自前Helm導入が必要
Metrics ServerはAuto Mode管理じゃありません。幸いEKSアドオンで導入できるのでインストールしましょう。
HPAはKubernetes標準提供のPod水平スケールリソースで、その単純さから負荷が低かったりスパイクしないなら悪くない選択肢です。しかし、実際のワークロードはCPU/Memoryではなくキュー残数やリクエスト処理時間などアプリケーションメトリクスをベースにスケール判定することが多く、加えて時間制御、一時的な0台制御を考えるとHPAは力不足と言わざるを得ません。KEDAは実運用に足る能力を持っていることから、結局のところKEDAを導入することになるでしょう。
管理する対象リソースの違いから、AWS統合が必要なノードレベルの水平スケールまではAuto Modeが管理するものの、Podはアプリケーションがやってねという切り分けなのかなぁと感じます。
EKS Auto Modeは使えるのか
実際のところEKS Auto Modeは使えるのか考えてみましょう。
あまり手をかけることがない小規模な環境(開発や検証環境含む)でEKS Auto Modeは使いやすいと感じます。一方で、大規模な環境(本番環境など)でEKS Auto Modeはコスト面から説得力は持ちにくそうです。仮に開発でEKS Auto Mode、本番でEKS Auto Modeとしても、コントローラーや定義の管理が共通化できないのは開発でドッグフーディングできず不満があります。
- ✔️: 小規模な環境 (追加Helmがない、EC2台数が少ない)
- ⚠️: 中~大規模な環境 (追加Helmが多い、EC2台数が多い)
EKS Auto ModeはEC2コストに説得力を持たせられればいいのですが、現時点の料金体系では大規模環境でEKS Auto Modeを採用する動機付けは難しいと感じます。また、小規模な環境ならECS FargateやLambdaで組んでしまえばよいケースは多く、Kubernetesを使う環境で小規模とはというのも難しいです。
個人的には、AWSコンテナ系アプリケーションで見たときに、クラスターバージョン含めた管理の楽さで見るとECS Fargate > ECS EC2 >> EKS Auto Mode > EKS
、コスト面でECS EC2 > EKS >> EKS Auto Mode > ECS Fargate
6という感触です。
EKS Auto Modeが実現していること
EKS Auto ModeはよりAWS統合が強くなっています。これまで必須だったEKSアドオンは考慮不要になりました。Node水平スケールアウトも組み込みKarpenterに任せることができEC2も自動更新してくれます。ALB/NLBとの統合も任せることができます。EBSマウントもサクッとできますし、Pod Identityもさくっと利用できます。お任せ度が高まっているのは事実です。
EKSはマネージドKubernetesと言いつつ、コントロールプレーン・AWS-Kubernetesアクセス管理・ログ回り程度しかマネージドではないのでは?という感触からすると、やっとマネージドな実感がわいてきます。
EKS Auto Modeのペインポイント
コストとこれまでの運用との差異が見受けられるので、そこに合致するとつらさがあります。EKS Auto Mode管理のEC2は一台あたりコストが+11-12%上がります。EC2は最大21日寿命で入れ替えタイミングは制御困難です。Pod Security Identityは利用できません。
また、ユーザー自身がExternalDNSやExternalSecretsのような各種コントローラーをHelmで導入している場合、Helm更新時の手間は軽減していません。Podスケールアウトは面倒みないためHPAで力不足ならKEDAを入れざるを得ません。EKS Auto ModeといってもKubernetes運用が完全に任せられるわけじゃないです。
EKS Auto Modeの採用基準
大量のEC2が必要なワークロードではコスト増加が受け入れられるかはカギになるでしょう。また、従来KarpenterやAWS LoadBalancer Controller(ALBC)をはじめとして複数Helmコントローラーを利用していたチームにとっては、Karpenter/ALBCの管理が不要になっても他のHelm管理は残るため楽になったとは感じられない7のが正直なところです。
導入を検討するフローはこういうかんじでしょうか。
フローチャート
graph TD a([EC2の稼働台数]) b([Helmコントローラー]) A[EKS Auto Modeの利用を検討する] B[EKS Auto Modeは利用しない] a --少ない---> b --少ない---> A a -.多い..-> B b -.多い..-> B
Amazon EKS Auto Mode のノード自動更新を Deep Dive するというAWSブログでも懸念に触れられているので参考になります。
EKS Auto Modeを使いつつ違いを見る
実際に触ってEKS Auto Modeの挙動を確認しましょう。EKS Auto Modeを追加EKSアドオンがない状態で構築して、次の点を順番に見ていきましょう。
- 組み込みコンポーネントがある
- 組み込みノードグループがある
- 組み込みKarpenterで動作させるEC2は追加料金がかかる
- 求められるIAMポリシーが異なる
- ネットワーク周りで制約がある
- 組み込みでALBを作成できる
なお、Auto Modeでも接続やロギングは共通です。
- EKSの認証方法は変わらない
- EKSロギングは変わらない
組み込みコンポーネントがある
何もEKSアドオンを追加していない状態でも、EKS Auto Modeには組み込みコンポーネントがあります。
組み込まれているのは従来EKSアドオンで入れていたものや、Karpenterを含めたAWS連携部分に関わるコントローラーです。EKS Auto Modeの組み込みコンポーネントは次の通りです。
- これまで必須EKSアドオンだったkube-proxy/CoreDNS/Amazon VPC CNIが組み込みインストールされ、Podは隠蔽されている
- Karpenterが組み込みインストールされいる
- AWS LoadBalancer Controller(ALBC)が組み込みインストールされている
- AWS EBS CSI Driverが組み込みインストールされている
- EKS Pod Identity Agentが各ノードでインストールされている
一方で、自分でインストールしたHelmやアプリケーションはこれまで通り自分で管理します。自分でEKSアドオンから追加したコントローラーも自分で管理します。
組み込みコンポーネントの面白いところは、EKS Auto Modeで起動してEKSアドオンやアプリケーションを何もデプロイしていない状態でPodを見ても何も見えないことです。セルフサービスEKSアドオンや自分のPodを起動していない状況だと、NodeClassやNodePoolも見えないのが興味深いです。8
$ kubectl get po -A
No resources found
$ kubectl get nodeclass
No resources found
$ kubectl get nodepool
組み込みノードグループがある
EKS Auto Modeはsystem
とgeneral-purpose
という組み込みノードグループがあります。従来のManaged NodeGroupとは異なり名前が決められており、使うかどうかは任意です。
組み込みノードグループはKarpenterで動作しており、組み込みノードグループのKarpenter定義は変更できません。
組み込みノードグループは、NodeClassdefault
を共通利用してしています。NodeClassは、KarpenterでいうところのEC2NodeClassに相当し、NodePoolで起動するEC2のスペックを定義します。EC2のスペックはEKS Auto Modeで建てたクラスターと同じセキュリティグループ、サブネットグループになっているのが特徴的です。Karpenterではセキュリティグループ、サブネットグループともにタグで検索させるのが主流だったので、これは組み込みの性質を強く感じます。また、KarpenterのEC2NodeClassではamiSelector
でAMIバージョンを都度指定する必要がありましたが、NodeClassで指定はできず最新AMIが使われます。
組み込みノードグループのNodePool
はKaprneterのNodePoolと同じスペックですが、requirements
の一部フィールドがEKS Auto Mode独自になっています。
組み込みノードグループのKubernetes定義を見てみましょう。
NodeClass
default
$ kubetl get nodeclass default -o yaml | kubetl neat apiVersion: eks.amazonaws.com/v1 kind: NodeClass metadata: annotations: eks.amazonaws.com/nodeclass-hash: "3399735243323253970" eks.amazonaws.com/nodeclass-hash-version: v1 labels: app.kubernetes.io/managed-by: eks name: default spec: ephemeralStorage: iops: 3000 size: 80Gi throughput: 125 networkPolicy: DefaultAllow networkPolicyEventLogs: Disabled role: automode-eks-AmazonEKSAutoNodeRole securityGroupSelectorTerms: - id: sg-1234567890 snatPolicy: Random subnetSelectorTerms: - id: subnet-1234567890123 - id: subnet-1234567890234
NodePool
system
general-purpose
と違い、traintsにCriticalAddonsOnly
があり、arm64アーキテクチャにも対応しています。CoreDNSなど多くのEKSアドオンがこのtaintsをもっているので、EKSアドオン専用のNodePoolを指向していることがわかります。
$ kubectl get nodepool system -o yaml | kubectl neat apiVersion: karpenter.sh/v1 kind: NodePool metadata: annotations: karpenter.sh/nodepool-hash: "4982684901400657622" karpenter.sh/nodepool-hash-version: v3 labels: app.kubernetes.io/managed-by: eks name: system spec: disruption: budgets: - nodes: 10% consolidateAfter: 30s consolidationPolicy: WhenEmptyOrUnderutilized template: spec: expireAfter: 336h nodeClassRef: group: eks.amazonaws.com kind: NodeClass name: default requirements: - key: karpenter.sh/capacity-type operator: In values: - on-demand - key: eks.amazonaws.com/instance-category operator: In values: - c - m - r - key: eks.amazonaws.com/instance-generation operator: Gt values: - "4" - key: kubernetes.io/arch operator: In values: - amd64 - arm64 - key: kubernetes.io/os operator: In values: - linux taints: - effect: NoSchedule key: CriticalAddonsOnly terminationGracePeriod: 24h0m0s
NodePool
general-purpose
systemと異なりtaintsはなく、amd64アーキテクチャのみ対応しています。オンデマンドでしか起動しません。
特に制約がないため、Auto Modeで適当にPodを起動すると、general-purpose
NodePoolでノードが作成されます。
$ kubectl get nodepool general-purpose -o yaml | kubectl neat apiVersion: karpenter.sh/v1 kind: NodePool metadata: annotations: karpenter.sh/nodepool-hash: "4012513481623584108" karpenter.sh/nodepool-hash-version: v3 labels: app.kubernetes.io/managed-by: eks name: general-purpose spec: disruption: budgets: - nodes: 10% consolidateAfter: 30s consolidationPolicy: WhenEmptyOrUnderutilized template: spec: expireAfter: 336h nodeClassRef: group: eks.amazonaws.com kind: NodeClass name: default requirements: - key: karpenter.sh/capacity-type operator: In values: - on-demand - key: eks.amazonaws.com/instance-category operator: In values: - c - m - r - key: eks.amazonaws.com/instance-generation operator: Gt values: - "4" - key: kubernetes.io/arch operator: In values: - amd64 - key: kubernetes.io/os operator: In values: - linux terminationGracePeriod: 24h0m0s
組み込みKarpenterで動作させるEC2は追加料金がかかる
EKS Auto Modeは、管理するNode(=EC2)に対して追加料金がかかります。
Amazon EKS Auto Mode の料金は、EKS Auto Mode によって起動および管理される Amazon EC2 インスタンスの期間とタイプに基づいてお支払いいただきます。以下の Amazon EKS Auto Mode の料金は、EC2 インスタンス自体を対象とする Amazon EC2 インスタンス料金に加えて請求されます。EC2 インスタンス料金と同様に、EKS Auto Mode の料金は 1 秒単位で課金され、1 分間分の最低料金がかかります。オンデマンド、1 年および 3 年のリザーブドインスタンス、Compute Savings Plans、スポットインスタンスなど、EKS Auto Mode では Amazon EC2 インスタンス購入オプションをすべて利用できますが、EKS Auto Mode の料金は EC2 インスタンス購入オプションとは無関係です。
まとめると次のようになります。
起動タイプ | 追加コストが必要 |
---|---|
EKS Auto ModeのBuilt-in node poolsで起動したEC2 | 必要 |
EKS Auto Modeで自前Node ClassとNodePoolで起動したEC2 | 必要 |
EKS Auto ModeにOSS Karpenterを入れてEC2NodeClassとNodePoolで起動したEC2 | 不要 |
EKS Auto Mode管理のNodeClassdefault
を避けて独自NodeClassを作ってもAuto Mode管理のノードとカウントされるので抜け穴はなさそうです。なお、追加分のコストはCost Explorer > API operationでEKSAutoUsageとして表示されます。(Service分類はElastic Container Service for Kubernetes
)
Auto Mode管理のノードか判別する
EKS Auto Modeが管理しているNodeどうかを識別するには、EC2インスタンスならManaged
にTrueがついているか、Nodeならeks.amazonaws.com/compute-type: auto
ラベルがあるかで判別できます。
Nodeにラベルがあるので、nodeSelectorで制御もできますね。
nodeSelectcor: eks.amazonaws.com/compute-type: auto
追加料金の試算
例えばEKS Auto ModeのBuilt-in node poolssystem
が有効な状態で、EKSアドオンのMetrics Server
をインストールするとc6g.large
が2台9起動します。東京リージョンで起動した場合、EKS Auto Modeで起動したc6g.large
のコストは元の価格から見て119.9%です。
$0.0856 (EC2オンデマンド料金) + $0.01027 (EKS Auto Mode追加分) = $0.09587/h $0.09587 / $0.0856 * 100 = 111.99%
AWSの例示する料金例を見ても、おおむね+11-12%程度の追加EC2料金になると見込むことになりそうです。
求められるIAMポリシーが異なる
通常のEKSクラスターとAuto Mode EKSクラスターで「EKSクラスター用IAMロール」「ノード用IAMロール」の必要ポリシーが異なります。詳細はドキュメントを見るといいのですが、組み込みコンポーネントで必要なIAMポリシーが追加された感じです。
IAM Role | 通常のEKSクラスター | Auto Mode EKSクラスター |
---|---|---|
EKSクラスター用IAMロール | arn:aws:iam::aws:policy/AmazonEKSClusterPolicy arn:aws:iam::aws:policy/AmazonEKSVPCResourceController |
arn:aws:iam::aws:policy/AmazonEKSClusterPolicy arn:aws:iam::aws:policy/AmazonEKSComputePolicy arn:aws:iam::aws:policy/AmazonEKSBlockStoragePolicy arn:aws:iam::aws:policy/AmazonEKSLoadBalancingPolicy arn:aws:iam::aws:policy/AmazonEKSNetworkingPolicy arn:aws:iam::aws:policy/AmazonEKSVPCResourceController + 下記のタグ用追加カスタムポリシー |
ノード用IAMロール | arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly |
arn:aws:iam::aws:policy/AmazonEKSWorkerNodeMinimalPolicy arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly |
EKS Auto ModeのNodeClassで追加タグを設定する場合、Auto ModeのEKSクラスター用IAM Roleに以下のカスタムポリシーを追加する必要があります。このポリシーは、KarpenterであればKarpenterコントローラー用のポリシーに相当しています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Compute", "Effect": "Allow", "Action": [ "ec2:CreateFleet", "ec2:RunInstances", "ec2:CreateLaunchTemplate" ], "Resource": "*", "Condition": { "StringEquals": { "aws:RequestTag/eks:eks-cluster-name": "{{ClusterName}}" }, "StringLike": { "aws:RequestTag/eks:kubernetes-node-class-name": "*", "aws:RequestTag/eks:kubernetes-node-pool-name": "*" } } }, { "Sid": "Storage", "Effect": "Allow", "Action": [ "ec2:CreateVolume", "ec2:CreateSnapshot" ], "Resource": [ "arn:aws:ec2:*:*:volume/*", "arn:aws:ec2:*:*:snapshot/*" ], "Condition": { "StringEquals": { "aws:RequestTag/eks:eks-cluster-name": "{{ClusterName}}" } } }, { "Sid": "Networking", "Effect": "Allow", "Action": "ec2:CreateNetworkInterface", "Resource": "*", "Condition": { "StringEquals": { "aws:RequestTag/eks:eks-cluster-name": "{{ClusterName}}" }, "StringLike": { "aws:RequestTag/eks:kubernetes-cni-node-name": "*" } } }, { "Sid": "LoadBalancer", "Effect": "Allow", "Action": [ "elasticloadbalancing:CreateLoadBalancer", "elasticloadbalancing:CreateTargetGroup", "elasticloadbalancing:CreateListener", "elasticloadbalancing:CreateRule", "ec2:CreateSecurityGroup" ], "Resource": "*", "Condition": { "StringEquals": { "aws:RequestTag/eks:eks-cluster-name": "{{ClusterName}}" } } }, { "Sid": "ShieldProtection", "Effect": "Allow", "Action": [ "shield:CreateProtection" ], "Resource": "*", "Condition": { "StringEquals": { "aws:RequestTag/eks:eks-cluster-name": "{{ClusterName}}" } } }, { "Sid": "ShieldTagResource", "Effect": "Allow", "Action": [ "shield:TagResource" ], "Resource": "arn:aws:shield::*:protection/*", "Condition": { "StringEquals": { "aws:RequestTag/eks:eks-cluster-name": "{{ClusterName}}" } } } ] }
ネットワーク周りで制約がある
EKS Auto Modeは以下をサポートしています。
- EKSネットワークポリシー
- KubernetesポッドのHostPortおよびHostNetworkオプション
- パブリックサブネットまたはプライベートサブネットのポッド
一方で、以下をサポートしていないためネットワーク周りの制約があります。
- ポッドあたりのセキュリティグループ (SGPP)
- カスタムネットワーキング。ポッドとノードのIPアドレスは同じCIDRブロックからのものである必要がある
- ウォームIP、ウォームプレフィックス、ウォームENI設定
- 最小IPターゲット設定
- プレフィックス委任の有効化または無効化
- オープンソースAWS CNIでサポートされているその他の設定
- conntrackタイマーのカスタマイズなどのネットワークポリシー設定 (デフォルトは300秒)
- クラウドWatchへのネットワークイベントログのエクスポート
運用中にサブネットのIPが足りなくなった時の追加VPC CIDR対応
EKS Auto ModeのポッドとノードのIPアドレスは「同じCIDRブロックからのもの」である必要があります。カスタムネットワーキングをサポートしていないので、「運用中にVPCへ追加CIDRを設定、サブネットを切ってPodを起動させる」ときに注意が必要です。
NodeClassdefault
はEKSクラスターと同じサブネットをIdで参照しており追加サブネットに対応できません。これに対応するには、独自C2NodeClassを作成してタグでサブネットを探索
させましょう。
EKS Nodeの最大Pod数が110に制限されている
Auto ModeはEKSの最大Pod数が「ハードリミットの110」か「ノードの最大ポッド数」の低い方に制限されています。
従来、VPC CNIを用いたEKSにおいてNodeごとに起動できるPodの数はENIに依存していました。この時、インスタンスファミリーごとの起動可能なPod数一覧はGitHubで公開されています。このため、インスタンスタイプによっては110を超えて起動できたのですが、Auto Modeでは110というハードリミットが設けられていることに注意が必要です。
組み込みでALBを作成できる
EKS Auto Modeは組み込みでALBを作成して構成できるため、AWS LoadBalancer Controller(ALBC)を別途インストールする必要がありません。ALBの作成はIngressリソースを使って行い、NLBの作成はServiceリソースを使って行います。
ALBを作成する手順はドキュメントに沿って、IngressClassParams、IngressClass、Ingressの3リソースを作成します。次の例はNginx
をALBで公開するリソースを作成します。
# IngressClassParamsとIngressClassは非Namespaceリソース apiVersion: eks.amazonaws.com/v1 kind: IngressClassParams metadata: name: alb spec: scheme: internet-facing --- apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: name: alb annotations: # Use this annotation to set an IngressClass as Default ingressclass.kubernetes.io/is-default-class: "true" spec: # Configures the IngressClass to use EKS Auto Mode controller: eks.amazonaws.com/alb parameters: apiGroup: eks.amazonaws.com kind: IngressClassParams name: alb # IngressClassParams name --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: test-ingress namespace: default spec: ingressClassName: alb # match IngressClass rules: - http: paths: - path: / pathType: ImplementationSpecific backend: service: name: nginx-svc port: number: 8080 --- apiVersion: v1 kind: Service metadata: name: nginx-svc namespace: default spec: selector: app: nginx ports: - port: 8080 targetPort: http --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: default spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: public.ecr.aws/nginx/nginx:1.27 resources: limits: memory: "128Mi" cpu: "256m" ports: - name: http containerPort: 80
ALBCではingressのmetadata.annotations
にALB向けのパラメーターを設定できましたが、EKS Auto ModeではIngressClassParamsやIngressClassで設定します。ALBCとはフィールドキーが変わっているものもあるので注意しましょう。
気になる挙動を試す
触っててどうなるのか気になることを色々触ってみます。
EKS作成直後のPod状態
EKSアドオンを何も導入していない状態だとPodが存在しません。ユーザー側のアプリケーションや追加EKSアドオンがなければ常時必要なノードがないのはコスト的に嬉しいことです。納得いってなかったですよね?
$ kubectl get po -A
No resources found
$ kubectl get node
No resources found
$ kubectl get nodeclass
No resources found
$ kubectl get nodepool
追加EKSアドオンをインストールする
追加EKSアドオンをインストールすると、組み込みノードグループのsystem
が利用されます。例えばMetrics Serverを追加すると、NodePoolsystem
でPodが起動します。
$ kubectl get po -A -o wide NAMESPACE NAME READY STATUS RESTARTS AGE kube-system metrics-server-746f5dc94-rdlzd 1/1 Running 0 64s kube-system metrics-server-746f5dc94-vl4wr 1/1 Running 0 3m15s $ kubectl get node NAME STATUS ROLES AGE VERSION i-095d98cf6f997a6a6 Ready <none> 52s v1.32.0-eks-2e66e76 i-09eabe62ba3931e7d Ready <none> 50s v1.32.0-eks-2e66e76 $ kubectl get nodeclaim NAME TYPE CAPACITY ZONE NODE READY AGE system-bcsln c6g.large on-demand ap-northeast-1a i-095d98cf6f997a6a6 True 77s system-z7ppv c6g.large on-demand ap-northeast-1c i-09eabe62ba3931e7d True 77s
カスタムNodePoolはweightやtaintsをつけると組み込みノードグループと混じらない
組み込みNodePoolsystem
やgeneral-purpose
には優先度spec.weight
が設定されていません。このため、カスタムNodePoolに優先度を指定しないと組み込みNodePoolとカスタムNodePoolでPodの起動ノードが混在します。
これを避けるためには、カスタムNodePoolに「適切な優先度をつける」「taintsをつける」のどちらかを検討するといいでしょう。そのNodePoolに他のPodを起動させたくないなら「taints」がいいでしょうし、そのPodをそのNodePoolで起動できればいいなら「NodePoolの優先度」か「nodeSelectorでNodePool名を指定」などでもいいでしょう。
# 優先度をつける例 apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: custom-pool spec: # ... 省略 weight: 10
# taintsをつける例 apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: custom-pool spec: template: spec: # ... 省略 taints: - effect: NoSchedule key: AppOnly --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: # taintsに合わせる tolerations: - key: AppOnly operator: Exists containers: - name: nginx image: public.ecr.aws/nginx/nginx:1.27 resources: limits: memory: "128Mi" cpu: "256m" ports: - name: http containerPort: 80
Auto Modeが管理するEC2はコンソールから消せない
従来のEKSでは、NodeGroupやKarpenterで起動したEC2はAWSコンソールから消せました。しかしEKS Auto Modeで起動したNode(EC2)をAWSコンソールからTerminate Instanceしようとしても実行失敗します。
Failed to terminate (delete) an instance: You are not authorized to perform this operation. User: arn:aws:sts::1234567801234:assumed-role/foo-role/bar is not authorized to perform: ec2:TerminateInstances on resource: arn:aws:ec2:ap-northeast-1:1234567801234:instance/i-04df53f6f7a5bc3d0 with an explicit deny in a resource-based policy. Encoded authorization failure message: ppuIku-省略...
kubectlからnodeを消すとEC2も連動して消えます。
$ kubectl delete node i-04df53f6f7a5bc3d0 node "i-04df53f6f7a5bc3d0" deleted
Auto Modeが管理するALBはコンソールから消せる
EKS Auto Modeが管理するALBはAWSコンソールから消せます。ここはEC2と挙動が違いますね。
Successfully deleted load balancer: arn:aws:elasticloadbalancing:ap-northeast-1:1234567801234:loadbalancer/app/k8s-default-testingr-1234567801/abcdefghijklmnop.
従来通り、kubectlからingressを消すとALBも連動して消えます。
$ kubectl delete ingress test-ingress ingress.networking.k8s.io "test-ingress" deleted
Auto ModeのEKSクラスター削除時にEC2とALBはどうなるのか
通常のEKSでは、Karpenterで管理しているNodeを残したままEKSクラスターを消すとEC2が残り、ALBCで管理しているingressリソースを残したままEKSクラスターを削除するとALBが残りました。 一方、EKS Auto Modeで作ったEC2/ALBはEKSクラスター削除に連動して消えます。後始末まで見てくれるマネージド具合はうれしいですね。
表にまとめると次の通りです。
EKSの動作モード | EKSクラスター削除時のEC2挙動 | EKSクラスター削除時のALB挙動 |
---|---|---|
通常のEKS+Karpenter+ALBC | EC2が残る | ALBが残る |
EKS Auto Mode | EC2が消える | ALBが消える |
KarpenterとEKS Auto Modeで起動したEC2の違い
次の違いがあります。
項目 | Karpenter | EKS Auto Mode |
---|---|---|
EC2のManaged状態 | false | true |
Nameタグ | Nameタグがつく | Nameタグがつかない |
EC2のボリューム | /dev/xvda のサイズ変更 |
/dev/xvdb のサイズ変更 |
先に紹介した通り、EKS Auto Modeで起動したEC2をAWSコンソールから見るとManaged: true
になっています。Karpenterで起動したEC2はManaged: false
です。
EKS Auto Modeで起動したEC2にNameタグがつきません。不便。KarpenterはName
タグにインスタンスのIP name
(この例ならip-10-100-21-142.ap-northeast-1.compute.internal
)を設定します。(1段目の図)しかしEKS Auto ModeはName
タグ自体が設定されません。(2段目の図)
設定次第ではありますが、EC2のボリュームも違います。KarpenterではEC2NodeClassでボリュームサイズを指定すると/dev/xvda
のサイズが変わりました。しかしEKS Auto Modeでは、EC2へストレージ/dev/xvda
と/dev/xvdb
の2つアタッチされ、NodeClassでボリュームサイズを指定すると/dev/xvdb
のサイズが変わります。例えばカスタムNodeClassで20GiBを指定すると、/dev/xvdb
EBSのサイズが20GiBになっていますね。
apiVersion: eks.amazonaws.com/v1 kind: NodeClass metadata: name: custom-class spec: # 省略 ephemeralStorage: size: "20Gi" # <-- ここでサイズ指定
EKS AccessEntryの注意
組み込みノードグループを作っていると、IAM access entriesにノードグループで指定したNode用のIAM RoleArn(通常はAmazonEKSAutoNodeRole)が追加されます。
しかし組み込みノードグループを作らない場合、カスタムNodeClassを展開するまではIAM access entriesにAmazonEKSAutoNodeRoleが追加されません。 一見自分で追加しないといけないのか!? となりますが、カスタムNodePoolを展開すると10-15分程度で自動追加されます。 早まってIaCで追加しないようにしましょう。
NodeClassの注意
spec.roleにはIAM Role名を指定する
spec.roleのIAM Role名は64文字未満である必要があります。ドキュメントがIAM Role ARNになっているので64文字に収まらずびっくりしますが、実際はIAM Role Name指定です。
# ×: ドキュメントはIAM Role ARN表記になっているがダメ spec: role: arn:aws:iam::123456789012:role/MyNodeRole
$ kubectl apply -f ./k8s/test/automode_nodepool.yaml The NodeClass "custom-class" is invalid: * spec.role: Too long: may not be more than 64 bytes * <nil>: Invalid value: "null": some validation rules were not checked because the object was invalid; correct the existing errors to complete validation
# 〇: 実際はIAM Role NameでOK。OSS Karpenterと同じ spec: role: MyNodeRole
Auto Mode管理のEC2に追加タグを設定するにはEKS Cluster Roleに追加権限が必要
EKSクラスターIAM Roleに追加ポリシーを設定しないと、Auto Modeで起動するノードに追加タグを設定した際に、NodeClaimが展開出来ず、kubectl describe
するとError getting launch template configs: User is not authorized to perform this operation because no identity-based policy allows it
と表示されます。この場合、IAM Roleに追加権限を設定すれば、無事にNodeClaimが展開されEC2起動・Podスケジュールされます。
apiVersion: eks.amazonaws.com/v1 kind: NodeClass metadata: name: custom-class spec: # 省略 tags: environment: custom
$ kubectl describe nodeclaim xxxxx Status: Conditions: Last Transition Time: 2025-03-12T09:48:38Z Message: object is awaiting reconciliation Observed Generation: 1 Reason: AwaitingReconciliation Status: Unknown Type: Initialized Last Transition Time: 2025-03-12T09:48:38Z Message: Error getting launch template configs: User is not authorized to perform this operation because no identity-based policy allows it Observed Generation: 1 Reason: Unauthorized Status: Unknown Type: Launched Last Transition Time: 2025-03-12T09:48:38Z Message: Node not registered with cluster Observed Generation: 1 Reason: NodeNotFound Status: Unknown Type: Registered Last Transition Time: 2025-03-12T09:48:38Z Message: Initialized=Unknown, Launched=Unknown, Registered=Unknown Observed Generation: 1 Reason: ReconcilingDependents Status: Unknown Type: Ready Events: <none>
NodePoolの注意
Karpenterでは、expireAfterにNeverを設定して寿命で入れ替わらないように出来ました。EKS Auto Modeでspec.template.spec.expireAfter
をNever
に設定するとエラーになります。これは先に説明した最大21日という制限に引っかかるためです。
$ kubectl apply -f ./k8s/test/automode_nodepool.yaml Error from server (Invalid): error when creating "./k8s/test/automode_nodepool.yaml": NodePool.karpenter.sh "custom-pool" is invalid: [spec.template.spec: Invalid value: "object": type conversion error from 'string' to 'google.protobuf.Duration' evaluating rule: the sum of expireAfter and terminationGracePeriod may not exceed 21 days, spec.template.spec: Invalid value: "object": expireAfter may not be set to Never]
まとめ
EKS Auto Mode完全に理解した気分になれたでしょうか。実際使ってみると色々そこ違うんだという点があるので、引き続き更新していきたいです。
繰り返しになりますが、EKS Auto Modeはコスト面、Node(EC2)寿命が最大21日、という2点がネックに感じます。ステートレスなワークロードなら寿命が短いのはどうでもいいのですが、ステートフルワークフロードでは採用できないレベルでつらいでしょう。EKS Auto Modeを使うぐらいなら、ECSでいいケースもあるので悩ましさが増した感じもしますがどうでしょうか。
参考
AWSドキュメント
- Amazon EKS Auto Mode の発表 | AWS
- Getting started with Amazon EKS Auto Mode | Containers
- Create a Node Pool for EKS Auto Mode - Amazon EKS
- Create an EKS Auto Mode Cluster with the AWS Management Console - Amazon EKS
- Learn about Amazon EKS Auto Mode Managed instances - Amazon EKS
- Learn about identity and access in EKS Auto Mode - Amazon EKS
- Learn about VPC Networking and Load Balancing in EKS Auto Mode - Amazon EKS
- Deploy a sample inflate workload to an Amazon EKS Auto Mode cluster - Amazon EKS
- Choose an optimal Amazon EC2 node instance type - Amazon EKS
- Community add-ons - Amazon EKS
- Amazon EKS Auto Mode のノード自動更新を Deep Dive する ~ 長期実行ワークロードを正しく取り扱う - builders.flash☆ - 変化を求めるデベロッパーを応援するウェブマガジン | AWS
AWSスライド
- Amazon EKS Auto ModeでKubernetesの運用をシンプルにする - Speaker Deck
- EKS Auto Mode | Spearker Deck
- AWS Blackbelt Online Seminarre:Invent 2024 アップデート速報
その他
- Karpenter NodeClaim has error "Error getting launch template configs" in Amazon EKS Auto Mode | by Hiroaki Kaji | Medium
- Terraform で Auto Mode の EKS クラスターを作成して、Pod Identity で AWS 権限を与えたアプリケーションをデプロイしてみた | DevelopersIO
- EKS Auto Mode で独自の NodePool を作成して利用してみた | DevelopersIO
- EKS Auto Modeで既存のTarget GroupをTargetGroupBindingで使う方法 | DevelopersIO
- [メモ]Amazon EKS Auto Modeの所感
- NodeClasses | Karpenter
- NodePools | Karpenter
- [EKS] [request]: Support custom TargetGroupBinding resources in auto-mode - Issue #2508 | aws/containers-roadmap
- Do you know that EKS Auto Mode enforces a 21-day maximum node lifetime? - DEV Community
- ドキュメントに記載がないですがAWS スライドに記載あります↩
- KarpenterのEC2NodeClassに相当しますが、EKS Auto Modeでは設定できるフィールドに制限があります↩
- ECSもFargateだとお高くなりがちなのと似ていますが、ECS EC2では追加コストないので非対称な価格設定です↩
- 自分でLCUを設定できるようになってよかったよかった。↩
- Managed NodeGroupを0台にして、Karpenterで起動したEC2を強制的にTerminateすることで簡単に夜間停止を用意できたのが不可能になった↩
- EKS with Fargateはコスト面で最も悪いですが同軸には適さないので除外↩
- そもそもHelmコントローラーの更新がつらいので0にしたい↩
- Karpenterコントローラーを自分で使う場合、先にEC2NodeClass、NodePoolリソースを展開しておくのでPodがいなくても見えるはず。ないということは、Pod作成をトリガーにNodeClassやNodePoolを作っていると推察される。↩
-
2台起動するのは、Metrics ServerのpodAntiAffinityで
affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution
にて"topologyKey": "kubernetes.io/hostname"
が設定されているため同一Nodeでスケジュールされないため↩