BLUF(結論から先に)
EKSとECSのどちらが自社のプロジェクトに合っているか――この判断は意外に難しいものです。
個別の特性だけを切り出して比べれば、勝者を選ぶのは簡単です。難しさは、両者を正しく比較するためには「特性の集合体」として捉える必要がある点にあります。つまり、それぞれの製品はメリットとデメリットが表裏一体になった存在として見るのが正確です。
ここを押さえると、自然に次の2点が見えてきます。
1. どちらが優れているかは、デフォルトでは決まらない。最適解はプロジェクトと組織レベルの要件・制約に応じて判断すべきである。
2. どちらが最適かを客観的に見極めるには、批判的思考と少し込み入った推論が欠かせない。
本記事では、ほとんど文書化されていない違いやその意味合い、よく直面するプロジェクト・組織レベルの制約に関わる知見、そして判断の際に考慮すべきその他の要素をご紹介します。
本記事の内容は「条件付きアドバイスによる思考のガイド」として捉えてください。具体的なプロジェクトと突き合わせれば、根拠ある意思決定に直結する実践的なアドバイスへと変わります。
目次
BLUF(結論から先に)
目次
対象読者
はじめに
セクション1:EKSとECSの細かな違い
1. ECSのほうがFargateの料金が大幅に安い(EKS Fargateは高い)。
2. EKSのEC2コンテナ密度はECSより大幅に高い。
3. ECSのほうがサービスディスカバリの選択肢が豊富。
4. EKSはKubernetesベースであるため、マルチクラウドやローカル開発でECSよりわずかに有利。
5. ECSはコントロールプレーンに費用がかからないが、EKSはかかる。
セクション2:判断を左右しうる重要な違いに関する知見
1. EKSはデフォルトでコンテナのスケーリングが速く、keda.shアドオンを導入すれば高度なオートスケーリングにも対応する。
2. EKSのIaC(Infrastructure as Code)はECSより根本的に優れている。標準化されており、読みやすく、疎結合で、宣言的で、ステートフルなメタデータをサポートしているからだ。
3. ECSにはボリュームの組み込みサポートがない。
4. EKSの難易度は変動的かつ逆説的である。
「EKSは簡単すぎるがゆえに難しい」
5. ECSのアップデートは極めてまれで、安定性とクラスタ運用の手間回避という点で大きな利点となる。
6. EKSには避けられないメンテナンスの負担があり、メンテナンス不要なECSに比べて構成要素が桁違いに多い。
セクション3:ECS、EKS、あるいはどちらでもないかを選ぶための経験則
1. 次のような場合はECSのほうが適している可能性がある。
2. EKSが優れた選択肢だと客観的に裏付けるには、状況要因をもう一歩踏み込んで検討する必要がある(本セクションではEKS Auto Modeに関する有益な助言も扱います)。
3. ステートフルアプリケーションは、経験則ベースの議論に値するほど頻出するシナリオである。
結論
対象読者
本記事は、EKSとECSの選択にあたって根拠ある判断を下したいすべての方を対象としています。
該当する方であれば、やや長めのこの記事を読む価値は十分にあります。読み終えた頃には、根拠ある意思決定という主目的に加えて、次の3つの副次的な成果も得られているはずです。
1. 思いがけない違い、メリット、デメリットを発見できる。
(検索しても見つかりにくく、文書化されていないことが多いものを中心に取り上げます)
2. 意思決定のためのメタ知識が身につく。
(選択がもたらす意味のある影響、選択肢を検討する際に重く考慮すべき重要要因や制約に関する洞察など。これらは経験則ベースの推奨事項を組み立てる土台にもなります)
3. 主張の根拠となる推論を理解できる。
主張・含意・洞察の妥当性を裏付ける推論を理解し、納得し、自分の言葉で言い換えられるようになれば、その知識を活かして「この決定は妥当な根拠に基づいている」という確信を、個人・チーム・組織の各レベルで高められます。
はじめに
本記事は上記の目次に沿ったセクション構成になっています。各セクションでは主張のリストとともに、その妥当性を裏付ける説明、事実に基づく根拠、経験則的な根拠を交えて提示します。
セクション1では、知っておくと役立つもののたいていは大きな問題にならない、EKSまたはECS固有の違いを番号付きリストで紹介します。
セクション2では、意思決定の場面で決め手になりうるため注目に値する違いについて、踏み込んだ知見を扱います。
セクション3では、よくあるプロジェクト・チーム・組織レベルの懸念に基づく条件付きの経験則を示します。これらをご自身の状況に当てはめれば、実践的な指針が得られます。
セクション1:EKSとECSの細かな違い
ECSもEKSも、FargateとEC2のどちらでも動かせます。とはいえ実際には、ECSはFargate、EKSはEC2インスタンスを使う傾向が強くあります。
本セクションの最初の2つの違いは、それぞれの利点を取り上げ、なぜこの傾向が生じるのかを説明するものです。続く3つは小さな利点と、それが比較的軽微にとどまる理由を扱います。
1. ECSのほうがFargateの料金が大幅に安い(EKS Fargateは高い)。
これは大きな問題ではありません。価格にかかわらず、機能面の優位性からEKSユーザーがEC2を選ぶケースもあるためです(EC2はコンテナイメージのキャッシュとデーモンセットに対応しますが、Fargateはどちらにも対応していません)。
- 理論上、AWSのFargateドキュメントによれば、Fargateインスタンスは利便性とセキュリティ面のメリットと引き換えにEC2よりやや高くなる想定で、このトレードオフを通じて総所有コストの低減を図るとされています。
ところが現実には、この説明はECSにしか当てはまりません。ECSはAMD(Intel/x86_64)、ARM、オンデマンド、SpotベースのFargateインスタンスに対応していますが、
- EKSはオンデマンドのAMDベースFargateインスタンスにしか対応していないからです。
EKSは「Fargate Spotインスタンス」にも「ARMベースFargate」にも対応していません。
- つまりEKSの価格を比較する際は、最も高い選択肢と最も安い選択肢を突き合わせざるを得ず、加えてFargateの追加コストとインスタンスサイズの切り上げロジックにも対処する必要があります。
- 具体例として、あるコンテナをライトサイジング分析した結果、CPU 1.8、RAM 1.2GBが最適と判明したとしましょう。
CPU 2が必要な場合、FargateはRAMを自動的に4GBへ切り上げ、AMDベースのオンデマンドFargate料金が適用されます。us-east-1のFargate料金は$2.37/日。一方、このコンテナはt4g.smallのARMベースEC2 EKS Spotノードに収まり、$0.1512/日で済みます。
- つまりEKS+Fargate構成は、EKS+EC2構成の最大15倍にもなり得るのです(さらに付け加えると、これは最も安いリージョンでの試算であり、料金が高いリージョンでは差はもっと開きます)。
2. EKSのEC2コンテナ密度はECSより大幅に高い。
注:大半のコンテナがCPU 1個・RAM 1GB以上を使う構成なら、価格差は最小限になります。t3/t4g.smallはそのサイズのECSタスクを2つホストできるためです。
CPUとRAMの使用量が小さいマイクロサービスを大量にデプロイするケースでは、EKSのコンテナ密度の高さのおかげで、コンテナをEKSで動かすほうが大幅に安くなり得ます。(注:複数マイクロサービスを大規模に展開する組織にとっては大きなコスト差別化要因になり得ますが、多くの組織にとってコスト差はそれほど大きくならないと考えられるため、本記事ではこれを軽微な違いとして扱います)
- 多くのECSユーザーはFargateインスタンスを使う傾向があり、いずれにせよインスタンスごとに1タスク/Podしか配置できません。あまり知られていないのは、ECS+EC2の構成がEKS+EC2に比べて大きく見劣りすることです。
- t4g.smallはEKS Podを11個、ECSタスクを2つ動かせます。
t4g.largeはEKS Podを35個、ECSタスクを2つ動かせます。
- これは以下のコマンドで算出しました。
aws ec2 describe-instance-types \
--filters "Name=instance-type,Values=t4g.*" \
--query "InstanceTypes[].{Type: InstanceType, MaxENI: NetworkInfo.MaximumNetworkInterfaces, IPv4addr: NetworkInfo.Ipv4AddressesPerInterface}" \
--output table
- このコマンドの出力から、t4g.smallは3つのENIをサポートすることが分かります。ECSはホストVM用に1つを使い、その後タスクごとに1つを割り当てます。便利な略式公式は$MAX_ENI -1 = $MAX_TASKS_PER_EC2_INSTANCE です(3-1=2)。
- 注:ECSにはENIトランキング(別名AWS VPC Trunking)という、名前負けした機能があります。理論上はECSのコンテナ密度を高めるはずですが、実際にはFinOpsのコスト最適化の観点からは使う意味がまったくないインスタンスタイプでしか対応していないため、個人的には存在しないものと思って差し支えないと考えています。
- 関連する小ネタとして:
通常、AMDインスタンスはコストが安く性能も高いため、デフォルトで最良の選択肢になりがちです。t3aの「a」はAMDを意味するので、一般則ではt3aのほうがt3より優れています。ところがECSのコンテナ密度では珍しくt3がt3aに勝ります。t3a.smallは奇妙にもENIが2つしかなく、ECSタスクは1つしかサポートできないのに対し、t3.smallはENIが3つあり、ECSタスクを2つ動かせるからです。
- ECSユーザーがFargateインスタンスを好む大きな理由は、私見では次の2つだと考えています。
1. ECS+Fargateはほぼターンキーでセットアップできるが、ECS+EC2は追加の作業が必要。
2. EC2インスタンスでも大幅にコンテナ密度が高くなるわけではないため、ECS+FargateからECS+EC2へ切り替える動機が乏しい。
3. ECSのほうがサービスディスカバリの選択肢が豊富。
これはECSの軽微な利点と捉えています。役立つのは限られたユースケースに限定され、そうした場面でもEKSはオプションのツールを追加することでベースライン機能を拡張し、同等の結果を得られるためです。
- EKSのサービスディスカバリは、クラスタ内のPodからのみ解決可能なクラスタ内DNS名で、$SERVICE.$NAMESPACE.svc.cluster.local という規則的なパターンに従います。
- ECSは2つのサービスディスカバリ方式を提供します。1つはAPIベースでECSクラスタ内通信に対応し、もう1つはDNSベースでVPC内通信に対応します(詳細はこちらを参照ください)。
4. EKSはKubernetesベースであるため、マルチクラウドやローカル開発でECSよりわずかに有利。
この差が比較的小さい理由は次のとおりです。
- マルチクラウドはほぼ常に避けるべき選択です。正しく実現する唯一の方法はクラウド非依存の設計を採ることですが、それも好ましいケースはまれです。マルチクラウドの根本的な課題は、理論上のメリット1つに対して現実の問題が10個簡単に見つかってしまうことです。
- MinikubeやRancher Desktopを使えばKubernetesをローカルで動かせますが、私が見てきた範囲では、これでメリットを得ているのは個々のノートPC上で手作業で構築した一部の高スキルなエンジニアに限られます。
有用な統合を備えた一貫したローカル開発体験をチーム全体に展開するには、統合固有の細かな事情があまりに多く、相応の投資なしには困難です。そのため実態としては、このメリットの実用的価値はかなり限定的にとどまります。
- ECSもDockerベースなので、高スキルなエンジニアであれば個人ノートPCでDockerベースのローカル開発が可能です。ローカルKubernetesがEKSに部分的にしか当てはまらないのと同じく、ローカルDocker開発もECSには部分的にしか当てはまりません。
同様に、統合固有の細かな事情をさばけるのは高スキルなエンジニアに限られ、得られるメリットも個人開発者としての自分にしか及ばないため、DockerベースであることはECSにとっても実用上の価値が限定的になりがちです。
5. ECSはコントロールプレーンに費用がかからないが、EKSはかかる。
これは比較的軽微な利点と捉えています。EKSの料金は十分に手頃で正当化しやすいからです。とはいえ、できる限り低コストで運用したいスタートアップにとっては効いてくるかもしれません。
- EKSクラスタを最新に保てば、クラスタあたり年間$864です。とはいえdev、stage、prodに加えて一時的なサンドボックスクラスタを抱えるのが一般的なので、年間$3kあたりが現実的な目安です。
- EKSのコントロールプレーン費用が正当化しやすい理由は次の3点です。
- 1. ECSと比べる以前に、料金そのものが妥当である。
TalosやRancherのようなクラウド非依存のKubernetesディストリビューションを動かすなら、HA/FTのコントロールプレーンノードとして3つのVMの料金を負担する必要があります。EKSのコントロールプレーン費用はDIYより安いうえに、マネージドサービスのメリットも享受できます。
- 2. EKSにはわずかなプレミアムを払う価値のある機能、特にデバッグのしやすさとフィードバックループの速さがあります(次のセクションで詳述します)。
- 3. EKSには独自のコスト削減要素もあります。EKS+EC2はECS+Fargateより安く、コンテナ密度の高さからECS+EC2より安くなり得ます。Kubernetes Ingressによって複数サービスでロードバランサーを共有しやすくなり、AWS LBの台数を減らせます。karpenter.shは適正サイズのオートスケーリングを自動化し、keda.shは高度なコンテナオートスケーリングを提供します。
- これらが効いて、EKSのほうがECSよりホスティングコストが安くなることもあります。条件変数が多すぎて「どちらが安くなりやすい」と断ずるのは難しいものの、EKSのほうが総額で安くなる、あるいは差が実質的にほぼゼロになるケースは決して珍しくありません。そのため、EKSのコントロールプレーン費用の存在は、論点として実質的に無関係になることもあるのです。
セクション2:判断を左右しうる重要な違いに関する知見
本セクションではEKSの利点を3つ、続いて欠点になりがちだが利点にもなり得るEKSのパラドックス、最後にECSの利点を2つ取り上げます。
1. EKSはデフォルトでコンテナのスケーリングが速く、keda.shアドオンを導入すれば高度なオートスケーリングにも対応する。
- EKSは一般にECSよりスケールアップが速い傾向があります。EKS+EC2とECS+Fargateを比較した場合、Fargateがコンテナイメージのキャッシュに対応していないことから直感的に納得できます。
直感に反するのは、EKSとECSの双方をEC2インスタンスで動かしてもなお、EKSのほうが高速な起動を実現する頻度が高いという事実です。
これは、EKSのコンテナ密度が高いことで、コンテナイメージキャッシュをより頻繁に活用できるためです。イメージキャッシュのおかげで、EKS Podが数秒以内に起動するのも珍しくありません。
- ECSもオートスケーリングは十分にサポートされており、カスタムCloudWatchメトリクスに基づくスケーリングにも対応していますが、スケーリング全般ではEKSに及びません。EKSは、ECSの実装上の制約・メトリクスの解像度・ゼロへのスケーリング対応といった違いから、コンテナのオートスケーリングが目に見えて速く、優れています。
- ECSの実装上の問題点を掘り下げます。ターゲットベースのオートスケーリングは設定された容量単位の刻みでしかスケールアップできず、ステップベースのオートスケーリングを併用すれば多少の可変スケーリングが可能になりますが、メトリクスのデータポイントが1分に1回しか収集されないため、スケーリング判断の間に1分のラグが生じてしまいます。
- (メトリクスを収集する頻度はメトリクスの解像度と呼ばれます)
- EKSはKubernetesのHPA(Horizontal Pod Autoscaler)を使い、デフォルトのメトリクス解像度は15秒なので、4倍速くスケーリングできます。
- ECSのスケーリングはCloudWatchメトリクス、CloudWatchアラーム、そして最適でないデフォルトと編集不可のデフォルトの組み合わせで動作するため、EKSのHPAほど優れているとは言えません。
ECSにもベストケースのシナリオはあり、悪いトレードオフと引き換えに一面ではEKSを上回れますが、総合的にはECSの選択肢のほうが見劣りします。
- ECSのベストケースのメトリクスオートスケーリングのシナリオは次のとおりです。
高解像度カスタムCloudWatchメトリクスは最大1秒の解像度を持てます。
ただし実際には10秒単位しか意味を持ちません。スケーリングをトリガーするのはCloudWatchアラームで、その最小評価期間が10秒だからです。
これは技術的にはEKSの編集不可なHPAデフォルト評価期間15秒を上回りますが、利点と引き換えに大きな代償が伴います。10秒のメトリクス解像度(実際には1分未満なら何でも)を採用すると、メトリクスの保持期間がわずか3時間になってしまいます。
- 一般的なシナリオにおけるECSのメトリクスオートスケーリングは、次のような姿になりがちです。
- ECSのCPU・RAMメトリクスは1分のメトリクス解像度を持ち、これは編集不可のデフォルトです。そのため、最も一般的なシナリオではCloudWatchアラームの最小評価期間が1分単位に強制されます。
- カスタムメトリクスを実装する場合でも、15日間の保持期間と低料金のために1分間隔を選ぶことが多いでしょう。
- また、ECSのメトリクス解像度は暗黙のデフォルト値が1分であり、10秒粒度を有効にするには明示的な設定が必要である点も触れておく価値があります。
Kubernetesのメトリクスサーバーは、暗黙のデフォルト値として15秒というより優れたメトリクス解像度を持っています。
- ECSはSQSキューのメトリクスを使う場合に限ってゼロへスケーリングできます。通常はゼロまでスケールダウンできません。
- EKSはkeda.shという無料アドオンを入れれば、カスタムメトリクス、HTTPトラフィックのゼロへのスケーリング、cronベースのスケーリングなど、より堅牢なオートスケーリング機能を追加できます。
cronオプションは、オートスケーリングに加えてベースライン容量の上積みが必要なよくあるシナリオで特に役立ちます。ピーク時間帯のトラフィック急増を滑らかにさばきつつ、活動量が低くなる予測可能な時間帯にはベースライン容量を絞り込めるからです。
2. EKSのIaC(Infrastructure as Code)はECSより根本的に優れている。標準化されており、読みやすく、疎結合で、宣言的で、ステートフルなメタデータをサポートしているからだ。
これらの特性は、デバッグのしやすさ、フィードバックループ、DevOps全体のユーザー体験において、桁違いの優位性を生み出します。
- EKSはkubectl + yamlというKubernetesの標準に従っています。
人間にとって読みやすく、学びやすく、編集しやすい形式です(YAMLはJSONのスーパーセットなので、JSONを内包的に扱える点も嬉しいおまけです)。
- ECSにはIaCもツーリングも、明確な公式標準が事実上存在しません。そのためECSのIaCは学習しづらく、AWS Copilot、AWS CDK、Terraform、Pulumiといった一般的なツール群を比較・選定する作業がいきなり必要になります。
- IaCとツーリングの選択肢自体はEKSのほうが多いものの、標準は1つに集約されています。EKSのあらゆる選択肢がその標準を土台にしているため、学習のしやすさという点でも、共通標準を重視する企業間で通用するスキルを身につけられる可能性という点でも、EKSは大きく有利です。
- ECSの概念的な疎結合の欠如とIaCの弱さは、いくつもの本質的な不利益につながります。
ECS Serviceは、概念的にはEKSのDeployment、Service、ConfigMap、Secret、AWS IAMロールが密結合のバンドルとして一体化したものに相当します。これが複数の問題を引き起こします。
- 1. まず、ECSのデプロイメントの密結合は、デプロイ済みオブジェクトに対するインプレース編集に制約を課します。
変更には完全な再デプロイや、削除と再作成を伴う面倒な2段階プロセスが必要になることが珍しくありません。
反復的な変更を加えたい場面では、これがすぐに苦痛になります。
ECSではロードバランサーの種類を追加・削除・切り替えるのも非常に厄介です。同じサービス名のままでは更新できず、ゼロから削除・再作成する必要があり、その間ダウンタイムが発生します。ブルーグリーンの切り替えで回避できますが、当然オーバーヘッドが伴います。
一方EKSを扱うエンジニアは、宣言的かつ冪等な更新のおかげで快適なユーザー体験を得られます。
- 2. ECSのデプロイは、本質的にEKSより遅い。
- 3. ECSのデプロイがうまくいかないと、実際の状態が望ましい状態へ収束したかどうかの明確なフィードバックがないまま、ブラックボックスをデバッグする状況に陥りがちです。
そのためECSエンジニアは、タイムアウトを待ちながら「コンピューターからNG」を食らう反復作業に1回あたり4分ほど費やすことも珍しくありません。
さらに失敗が起きたとき、ECSのブラックボックス的な性質は原因に関するフィードバックやヒントを返してくれないことが多い、という点も忘れてはいけません。
- 4. ECSデプロイの問題のデバッグは、シンプルで疎結合なEKSのYAMLオブジェクトのデバッグよりも反復回数が多くなる傾向があります。
これは、ECSタスクが複数のコンポーネントを密結合に束ねたものだからです。トラブルシュートの範囲が広く、どのコンポーネントに焦点を絞るべきかを切り分ける手段が乏しいのです。
- EKSをデバッグする段になると、各コンポーネントを独立して体系的にデプロイ・編集・デバッグできます。kubectl describeやyaml出力でステートフルなeventsとstatusを確認すれば明確なフィードバックが得られるため、フィードバックループを秒単位に縮めるのも容易です。EKSのフィードバックループは、思考とタイピングの速度がボトルネックになる程度です。
- kubectl port-forwardのおかげで、EKS上のプライベートIPサービスのデバッグも極めて簡単に行えます。ECSにはこれに相当するものがありません。
- フィードバック面でKubernetesの優れたユーザー体験を支える本質的な要素は、コンポーネントオブジェクトのYAMLマニフェストにコントローラーがステートフルなメタデータを追記し、それがkubectl applyによってクラスタのetcdデータベースに反映されることにあります。
そのおかげでエンジニアはkubectl describeやyaml出力でオブジェクトのeventやstatusメタデータを参照でき、各コンポーネントオブジェクトのフェーズごとの成否について、迅速かつ多くの場合具体的なフィードバックを得られます。
そのため何かが失敗しても、どのコンポーネントが、どこで失敗したのかをすぐに高い確度で特定できます。
- これに対するECSの壊れたワークフローを見てみましょう。AWSのWeb GUIではロードバランサー型のECSサービスを作成でき、デプロイのフォームでどのサブネットにデプロイするかを尋ねられます。
パブリックとプライベートの両方は選べず1つに絞れと案内されますが、その質問の肝心な部分は教えてくれません。
つまり、これはロードバランサー用のサブネットなのか、それともバックエンドインスタンス用のサブネットなのか、です。
本来は「ロードバランサーはパブリック、バックエンドはプライベート」というベストプラクティスに沿うために2回尋ねるべきところ、サブネット選択は1度しか問われません。
その結果、ECSのワークフローではプライベートサブネットへのパブリックIPロードバランサーのデプロイのような、本来プログラム側で防ぐべき操作も実行できてしまいます。
当然うまくいきませんが、入力検証で弾くべきところが、回避可能なエラーと不十分な原因情報だけが返されることになります。
- EKSの強みが光るもう1つのよくあるデバッグシナリオを挙げます。
あるエンジニアがテスト用に新規VPCを作り、誤ってNATゲートウェイのないVPCにEKSまたはECSクラスタをデプロイしたとしましょう。
- ECSの場合、インターネットアクセスがないためコンテナイメージのプルが失敗し、ログもメトリクスも一切得られません。問題は、原因に関するフィードバックがゼロのまま手探りで進めるしかないことです。ECS Execはプラットフォームに既定でターンキー組み込みされておらず、有効化も容易ではありません。
VPCの問題だと気づかなければ、ECSタスクやECSサービスの設定を当てもなくデバッグして無駄な反復を重ねがちです。ECSはフィードバックの乏しいブラックボックスのような存在だからです。
そもそも「イメージのプルに失敗した」とすら教えてくれず、それが原因だと自分で推察するしかありません。
- 同じ状況にEKSで遭遇した場合は格段に解決しやすくなります。ワーカーノードがインターネットに出られなくても、コントロールプレーンはデフォルトでパブリックに到達可能なので、kubectlでイメージプル失敗のようなフィードバックを取得でき、インターネット接続不足という良いヒントが得られます。
3. ECSにはボリュームの組み込みサポートがない。
- ECSについて知って驚いたのは、設定やシークレットを注入したい場合(ecs-task-definition.jsonにインラインで書く、AWS Secrets Managerから参照するなど)、ECSの公式の組み込み手段は環境変数だけだという点です。設定やシークレットをファイルとしてマウントするECSプラットフォーム標準の手段は用意されていません。
- 動的な設定ファイルを簡単に注入できないことは、ECSにKubernetesのIngress Controllerに相当する仕組みがない大きな理由でもあります。
- ECSはステートフルストレージとしてEFSを使え、ファイルをマウントするための回避策も存在しますが、要するにそれらはいずれも力技であり、ECSプラットフォームレベルの組み込みサポートがないために容易には実装できません。
この点には補足が必要です。
ECSはAWSプラットフォームレベルでEFSをサポートしていますが、ECSプラットフォームレベルでセットアップを楽にする統合は提供されていません。
(楽でないどころか、ECSでEFSを構成するのは単独のEC2やEKSで構成するより難しいケースが多いと言えます。ECSはフィードバックループが遅く、デバッグしづらいブラックボックスのように振る舞いがちだからです)
- 一方EKSにはKubernetes Storage Classを構成するためのEFS CSIドライバーがあり、その統合とEKSプラットフォーム標準の組み込みサポートのおかげでEFSのセットアップがしやすくなっています。
- EKSでは設定とシークレットを環境変数としても、ファイルとしてもマウントできます。Statefulsets、Storage Class、PersistentVolumeなどの高度な機能のおかげで、ステートフルなworkloadsの実装も比較的容易です。
4. EKSの難易度は変動的かつ逆説的である。 「EKSは簡単すぎるがゆえに難しい」
ECSの難易度は比較的安定しています。ECSのほうが本質的な制約が多いためです。重要なのは、実装チームが経験に裏打ちされた助言を得られ、適切な実装戦略を取るならば、EKSのほうがECSよりむしろ簡単になり得るというニュアンスです。
(ご存じない方のために言えば、これは「ECSは常にEKSより簡単」というAWSドキュメントによくある主張に対し、批判的思考に基づいて反論する立場です)
- この洞察を伝えるには時間がかかります。ニュアンス、実証的なパラドックス、そして洞察を直感的に理解するために欠かせない複数の論理の流れを共有する必要があるので、しばしお付き合いください。
- EKSはECSより簡単になり得ます。ECSには避けがたい本質的な不利が複数あり、主要なものはすでに先ほど挙げました。EKSの不利はそれとは根本的に異なり、自然な思考の偏りから生じるパラドックスに由来する、創発的な性質を持ちます。
EKSのこのパラドックス的な不利の全体像、その原因、そして戦略的に避ける方法を理解できれば、EKSはぐっと扱いやすくなります。
- EKSは古い格言の格好の例です。「良いものでも過ぎれば毒。極端に走れば、しばしば問題を生む」
- Kubernetesは優秀すぎ、機能豊富すぎ、爆発的に成功しすぎたがゆえに、巨大なエコシステムを抱えています。その巨大なエコシステムは複雑で、明確なメリットと隠れたコストを併せ持つKubernetesツールを採用したくなる自然な偏りと相まって、EKSが難しいと見なされる大きな理由になっています。
- 大事な気づきは、Kubernetesの巨大で複雑なエコシステムはすべてオプションだということです。戦略的に使用範囲を絞り込めば、EKSは扱いやすいまま保てます。
- 背景を補足したうえで、もう1つの関連するパラドックスに進みます。
- 私が持つプリンシパルレベルのエンジニアリングスキルの1つに、「問題解決者」と「問題変換者」を見分ける能力があります。問題変換者とは、1つの問題を解決する代わりにN個の新しい問題を生み出すツールや手法のことで、自分が何をしているかを本当に理解し、二次的影響まで考え抜いている場合を除いては、避けるべき悪手であることが多いものです。
- このロジックに照らすと、私は次のものは悪手になりがちだと考えています。
Kubernetes Operator、Statefulsets、v1でないAPIの使用(特にアルファAPIでStatefulsetをデプロイするオペレーターは大物の悪手)、サービスメッシュ、nginx-ingressコントローラー。Hashicorp Vaultも忘れてはいけません。「友達にhashi-vaultを使わせるな」です。
- そこから生まれる問題の例としては、深刻なCVE、メンテナンス負担、EKSへの強制アップデートが最終的にアプリの強制更新につながる連鎖などがあります。
更新が破壊的変更を持ち込むことは珍しくなく、サービスが落ちる新しい経路と、何かあったときの影響範囲の拡大が生まれるため、追加のテストも必要になります。
- 十分に複雑な構成は、IaC、自動化、ドキュメント、スキルセットのボトルネック、人員配置などに関わる問題を生み得ます。
- この前提を踏まえると、もう1つのパラドックスはこうです。
悪いアイデアが持ち込まれた場合、ECSは制約が強く、柔軟性に欠け、ほどよく扱いにくいので、悪いアイデアを実装しようとすればすぐに「これは厳しいな」と気づきます。最低限のことすら大変なため、結局は最低限の実装にとどまり、結果としてECSは「簡単」だと見なされやすくなります。
- EKSは繰り返しになりますが、自分にとって不利になるほど柔軟で機能豊富です。
誰かが悪いアイデアを思いついても、EKSは自由度と実装のしやすさを十分に提供してしまうため、悪いアイデアまで含めてどんなものでも実装できてしまいます。
悪いアイデアが共有されると厄介です。Kubernetesは扱いやすいぶん、他のメンバーも悪気なく安易にそれを採用・実装してしまえるからです。
そして問題が起きると、Kubernetesが「難しすぎる」と槍玉に挙げられることになります。
裏に潜む真実は、悪いアイデアを避けるだけで多くの問題は回避できる、というものです。
言い方を変えれば、「EKSは人が難しくしている」のです。
- これらの洞察を組み合わせると、優れたEKS実装戦略の土台になります。
要は、組み込み機能を優先するという経験則を採用し、定期的にYAGNIの原則を意識し、ECSにない機能はなるべく避けて、シンプルなEKS機能の範囲にとどめることです(ECSにはオペレーター、Ingress Controller、永続ボリューム、非安定API、巨大なサードパーティツール群はほぼ存在せず、AWS App Meshのサポートも廃止される予定です)。
この戦略を念頭に置いて両者を比較すると、より同条件に近い比較に近づきます。すると今度は、EKSが香り高いHoneycrispリンゴに見えてくるかもしれません。
5. ECSのアップデートは極めてまれで、安定性とクラスタ運用の手間回避という点で大きな利点となる。
- 理論上、オンデマンドFargateインスタンスは何年もアップデートなしで稼働し続けることが可能であり、更新による破壊的変更がもたらすダウンタイムを避けられます。
- EKSプラットフォームは利用者にいずれアップデートを強制します。クラスタ上のアプリが放置されたまま更新されていない場合、特定のKubernetesバージョン向けに作られた古いアプリが、強制プラットフォーム更新によって動かなくなるリスクがあります。
- nginx-ingressコントローラーは、特定バージョンのIngress Controllerと対応するKubernetesバージョンを一覧化したテーブルを持つ、有名なアプリの好例です。
- EKSでは、ある意味で自業自得ながら厄介な、よくあるシナリオがあります。EKSベースのソリューションをできるだけ速く・安くセットアップするために業者を雇い、契約終了後はEKSクラスタとそのworkloadsが何年も放置される、というものです。
そしていずれ、EKSプラットフォームが最終的に更新を強制してくることを誰かが知ります。何かが壊れた後に気づくか、強制自動更新の直前にその組織が誰かに更新を丸投げするかのどちらかです。
担当エンジニアは、作業量を見誤っていたことに気づくケースが多々あります。クラスタの更新だけでなく、その上にデプロイされた複数のworkloadsまで更新する必要があるためです。
- 普段なら大したことではないものの、土壇場の締め切りでこなすのはストレスが大きく、間に合わなければ本番障害を招きかねません。とりわけそうした組織は、Kubernetesに詳しくない人にこの仕事を割り当てがちで、放置されたEKSクラスタは計画性に欠けた急ごしらえの産物であることが多く、IaCも、2年以上前に去ったエンジニアによるセットアップ手順のドキュメントも残っていないのが常です。
- 強制更新だけでなく、EKSのEC2ノードはFargateベースのECSクラスタに比べてワーカーノードの再起動が必要になる場面も多くなります。
(EC2ノードはkarpenter.shのようなコスト削減型のクラスタオートスケーラーでスケールダウンでき、karpenter.shはデフォルトで30日ごとにオンデマンドノードを再起動し、EKSワーカーノードVMの最新パッチを適用します)
- EKSはまた、karpenter.sh、Kubernetes Gateway APIコントローラー、Ingress Controller、サービスメッシュなどの形で、任意の複雑さを取り込みやすい構造になっています。
- こうしたオプション要素を採用するほど、新たな失敗経路、トラブルの発生源、設定ミス、不具合のあるアップデート、サプライチェーン上の脆弱性、緊急対応を要する重大脆弱性、機能としての半定期的な再起動、更新に伴う破壊的変更といったリスクが増えていきます。
- 皮肉な話ですが、Istioのようなサービスメッシュは複数クラスタにまたがるマルチリージョンメッシュ構築、リトライロジックなど、稼働率向上のための機能を備えているのに、現実にはダウンタイムの主因になることも珍しくありません。
- アプリがいったんデプロイされて稼働してしまえば、ECSはほぼメンテナンスフリーになる傾向があります。
- EKSの構成は3クラスタ以上になることが多く、各クラスタに複数のコンポーネントがあり、それらがすべて更新を必要とするため、避けようのないメンテナンスの手間が積み上がります。
- 幸いなことに、メンテナンス負担を抑えるための進化は数多く生まれています。代表格はEKS Auto Modeですが、これを使わない場合でも、AWS Managed Add-onsや、Ingress・karpenter向けのv1安定APIによって、更新は格段に楽で速く、安心できるものになっています。
6. EKSには避けられないメンテナンスの負担があり、メンテナンス不要なECSに比べて構成要素が桁違いに多い。
EKSのこの2つの一見小さな欠点は、運用オーバーヘッドの面で大きな不利を生む二次的影響を引き起こします。「大きな」と言っても抽象的なので、目安としてEKSメンテナンスに費やすエンジニアリング時間を年間2〜14日と置いておきましょう。
- ECSの特性は、一般的なDevOpsベストプラクティスを知らなかったり、意図的に省いたりしても、許容してくれる寛容さを持っています。
ECSの管理者は、たとえば次のような本来好ましくないパターンでも、それなりの安定性を享受できます。
- 1. 手作業と部分的な自動化を組み合わせ、IaCを最低限にとどめたワークフローを採用する。あるいはworkloadsのデプロイは自動化しても、クラスタのプロビジョニングは自動化しない。
(ECSは一度動き出せばそのまま動き続ける傾向があるため、これでもうまくいくことがあります)
- 2. 複数クラスタによるセキュリティ上のメリットを無視し、すべてを1つのECSクラスタに詰め込む。
(devとprodを1つのECSクラスタに混在させても、ECSの一般的なアーキテクチャパターンのおかげで、ほとんどの問題の影響範囲が狭く保たれるため、信頼性を損ねることはまれです。
ECSサービスは、共有のKubernetes Ingressロードバランサーではなく、サービスごとにAWSマネージドLBを持つのが一般的です。Fargateコンテナはそれぞれ専用のVMを取得するため、分離性も高まります)
- 3. 適切なリソースのlimits/requestsを設定しない。
(Fargateインスタンスは1 ECSタスク=1 VMという比率なので、これはコスト最適化の問題にとどまり、信頼性まで損ねる事態にはなりにくくなります)
- EKSは構成要素も複雑性も大きく、長期的にクラスタの信頼性とメンテナンス性を保ちたい管理者にとって、ベストプラクティスの厳格な実装は事実上の必須要件になります。
- ベストプラクティスを厳格に実装しなければならない、という前提自体に大きな代償があります。
メンテナンスやベストプラクティス実装にまつわる雑務はエンジニアリング時間を奪い、その時間は決して安くありません。さらに厄介なことに、ベストプラクティスの追求はエンジニアをDevOpsヤクシェービングのウサギ穴に引きずり込みかねません。
DevOpsヤクシェービングは至極まっとうな活動になり得ますが、まっとうなのか、過剰なのか、まったく不要なのかの線引きが難しいため、潜在的に厄介な落とし穴でもあります。
ここで強調しておきたいのは、ECS管理者は雑務から解放されているだけでなく、DevOpsヤクシェービングに巻き込まれる場面そのものが少ないという点です。
- EKSを運用するチームは、信頼性のためにEKSクラスタは少なくとも2つ必要だ、という結論にすぐ行き着きます。
EKSコンポーネントの更新や設定ミスが破壊的変更を招き得ること、Ingress、DNS、CNI、karpenter.sh、サービスメッシュ、不健全なノードなど多くのコンポーネントの問題が広範囲に影響することは、運用していればすぐに分かります。
そのため、環境を分離し、低位環境で更新をテストすることがEKSの信頼性に欠かせないと、自然と腑に落ちます。
- 環境プロモーションのワークフローに慣れてくると、もう1つよくある気づきが訪れます。
低位環境でのテストが意味を持つのは、低位環境と上位環境がそれなりに似ている場合に限られる、という事実です。
- 多くのEKSチームは、低位環境と上位環境を同期させ続けるために、IaC、エンドツーエンドの自動化、CICDパイプラインを厳格に整備することに時間を投じます。
- もう1つよくある経験は、dev環境ほど変化が速く、頻度も高く、手作業の変更も多いということです。本番環境でも障害・インシデント対応のための緊急手作業が発生することは珍しくありません。
そのためEKSチームは、ライブ環境がgitやCICDパイプラインで定義されたIaC・自動化と一致しなくなる「設定ドリフト」に直面しがちです。
ライブ環境とIaCの一致を保つには、CICDパイプラインとGitOpsを組み合わせるなど、さらに踏み込んだベストプラクティスの厳格な実装が必要になります。
セクション3:ECS、EKS、あるいはどちらでもないかを選ぶための経験則
1. 次のような場合はECSのほうが適している可能性がある。
- 稼働率を最大化し、メンテナンスを最小化したまま2〜10年動かし続ける前提でアプリを設計したい場合。
たとえば、めったに更新しないアプリ――社内の独自監査アプリのような内製ツール、あるいはゼロデイの重大なRCE脆弱性を突かれても深刻な事態にはなりにくい外向けアプリ(シェルを持たないdistrolessイメージや最小権限の原則に沿ったIAM権限などのベストプラクティスを採用しているケース)を想定してください。
こうした場合、EKSの強みであるデバッグのしやすさと速いフィードバックループよりも、ECSの強みであるほぼゼロの運用オーバーヘッドを優先する判断が理にかなうことがあります。
- 比較的シンプルなアプリで、環境への更新デプロイが1日数回程度、アプリやアーキテクチャの要件が安定していてめったに変わらない、あるいは常にうまくいく単純なパターンだけをデプロイするカスタムECS用CICDパイプラインに投資する予定がある場合。
こうした条件下なら、トラブル時のデバッグの難しさやフィードバックループの遅さといったECSの弱点に振り回されるリスクを最小化できるはずです。
- 少人数のチームで、メンバーが開発者ばかり、しかも誰一人としてDevOpsベストプラクティスを厳格に実装する方法を学ぶことに興味も意欲もない場合。
ECSは(EKSと比べて)運用ベストプラクティスが乏しかったり最低限だったりしても、より許容してくれます。
2. EKSが優れた選択肢だと客観的に裏付けるには、状況要因をもう一歩踏み込んで検討する必要がある。
- ECSとEKSはどちらもメリットと欠点が表裏一体です。とはいえECSはバランス型で、メリットも欠点も比較的穏やか(ローリスク・ローリターン)と捉えられます。一方EKSは、メリットがより大きく欠点も中程度(ミドルリスク・ハイリターン)というタイプです。
- EKSのメリットに入る前に、まず欠点から確認するのが賢明です。先に欠点を踏まえておくほうが、視点を整える次の問いから多くを引き出せるからです。
「自分が見ているメリットは、欠点を打ち消す、あるいは上回るだけのものだろうか?」
- EKSの欠点 その1:EKSをうまく採用するにはDevOpsベストプラクティスの厳格な実装が必要で、それには本気度と相応のリソース投入が欠かせません。
多くの人が想定する以上に時間がかかる可能性があります。「DevOpsの問題」にはしばしば「DevOpsの解」が必要で、その解にたどり着く前に、まず問題変換器とセットで対処しなければならない場面が多いからです。
DevOpsの専門家が自らを「プロのヤクシェーバー」と冗談めかして呼ぶのも、このためです。問題を何度も変換していくと、最後はヤクの毛を剃る作業に行き着きます。
(ここではエンジニアリング工数として1〜4か月の一回限りの投資と大まかに見積もっておきましょう)
- この1〜4か月の時間コミットメントを良い方向へ導きたいなら、十分な報酬を払って、問題解決と問題変換の繊細な違いを理解できる批判的思考の持ち主を採用しましょう。チームが「EKSは簡単すぎるがゆえに難しい」というパラドックスの背後にあるロジックを腹落ちさせていることも確認してください。
そして、次のような原則と助言を優先しましょう。
KIS(Keep It Simple)、YAGNI(必要になるまで作るな)、v1安定APIは強い味方、Nginxのような自前のIngress ControllerよりAWS LB Controllerのようなマネージドサービスを優先する(ヒント:前者は解、後者は問題変換です。quay.ioの脆弱性スキャンによれば、6年前のnginx-ingress-controllerイメージには76件の重大脆弱性、つまり月あたり平均1件の重大CVEがあったとのこと!)、そしてEKS Auto Modeも検討する価値があります。
(Auto Modeも問題変換の一種で、ブラックボックス化やコスト増といった欠点はありますが、それでも小規模なグリーンフィールドクラスタには十分割に合うことが多いです)
こうした方針を貫けば、EKSは比較的扱いやすい状態を保てます。
忘れないでください。「EKSは人が難しくしている」のです。
- EKSの欠点 その2:逃れられない一定のメンテナンス負担がある。
(3クラスタの場合で年間2〜14日のメンテナンスと大まかに見積もりましょう)
- 2024年12月に登場したEKS Auto Modeは、EKSの2大欠点の双方を抑えるうえで大きな助けになる、と指摘しておく価値があります。
- EKSのAuto Modeは、数多くの前提作業(よくあるアドオンのセットアップ周り)、前提知識、継続的なメンテナンスの負担を取り除いてくれるうえ、v1安定APIに基づくアドオンだけを使い、そのアップグレードを自動化することで、破壊的変更による失敗モードまで回避します。
- とはいえメンテナンスを完全になくせるわけではなく、コストの上乗せや、EKSがブラックボックス化してデバッグ性が低下するといった欠点もあります。
(マネージドのコントロールプレーンノード上でkarpenter.shのPodが動くため、karpenter.sh Podのログにアクセスできなくなります。これらのログはエッジケースのデバッグでよく必要になります)
- EKS Auto Modeは前提条件を完全に消してくれるわけでもありません。こちらのページには、Auto Modeのすべての機能を活用するには、Auto Mode専用のIngressClass、ロードバランサーサービス用のアノテーション、Auto Mode専用のEBSボリュームプロビジョナーを参照するStorageClassを用意する必要があると記されています。
- 事前に押さえておきたいもう1つのポイントは、Auto Mode無効から有効への移行が容易ではないことです。EKSのWebポータルだけ見ると、Auto Modeのオン/オフを切り替えるだけのように見えます。
しかしこちらの移行リファレンスを読むと、インプレース移行はかなり手間のかかる手作業であり、新しいクラスタを作ってブルーグリーン移行したほうが楽な場合が多いほどだと分かります。これはEKS Auto Modeが独自のIngressClass、LoadBalancerClass、EBS CSIボリュームプロビジョナーを持つためで、既存クラスタでAuto Modeを無効から有効にインプレース移行しようとすると、LoadBalancer型のKubernetes Service、Ingressオブジェクト、Auto Mode有効化前に作成したPVCを作り直す必要が出てきます。
- こうした細かな問題と追加コストを踏まえると、すべてのケースでEKS Auto Modeを推奨するのは現実的ではありません。それでも、EKSに慣れていないチームが管理する小規模なグリーンフィールドクラスタには、よい選択肢になる場合が多いと感じます。長期運用するクラスタが6つを超える見込みの方にも、EKS Auto Modeは大いに理にかなうと思います。
- ここからメリットの話に移ります。最も強調したいのは、先ほど挙げた時間コストを相殺するうえで最大の効果を発揮する「時間節約効果」です。
- EKSは、より簡単で速いデバッグと速いフィードバックループという点で大きな恩恵をもたらします。状況がはまれば(開発はえてして継続的なデバッグの繰り返しです)、この特性だけで十分な時間節約を生み、時間コストを相殺し、EKSの他のメリットと合わせてトータルでプラスにできることもあります。
- EKSが正当化しやすくなるよくある場面はこんな状況です。アプリのデプロイ頻度が高く、可能な限り高速なCICDパイプラインを敷く価値がある、変更が頻繁、複雑な統合、サービス指向アーキテクチャ、ストラングラーパターンでモノリスからサービス指向へ移行中、あるいは複雑性が高く「速いフィードバックループでサクッとデバッグできること」の価値が極めて大きいと判断される場合。
- 急峻なトラフィックスパイクが想定され、できる限り速くスケールアップできるかが決め手になりそうですか?
そうであれば、EKSの高度なスケーリングオプション(keda.shアドオンによって実現)、たとえばゼロへのスケーリングやcronベースのスケーリングは、コスト削減のチャンスと並ぶ大きな武器になります。
- アプリの中に、設定をファイルとして読み込むことが要件になっているものはありますか?堅牢なストレージオプションが必要なものはありますか?
- クラスタレベルのRBAC、Policy as Code、GitOps、高度なロードバランシング、OIDC/Authn/z連携、そして優れたエンジニアリング体験を保ったままあらゆるアイデアを実装しやすいカスタマイズ性――こうした高度な機能やパターンへのアクセスが必要、または十分なメリットを感じていますか?
- EKSの導入で生じる年間2〜14日のメンテナンス負担をメリットが上回り、ベストプラクティスに沿った実装に必要な1〜4か月の一回限りの導入リードタイムについてもステークホルダーの合意が得られるようなプロジェクトであれば、EKSは絶好の選択肢になり得ます。
3. ステートフルアプリケーションは、経験則に基づくロジックの議論に値するほど頻出するシナリオである。
- EKSはステートフルアプリケーションを動かしやすく、サポートも手厚いのですが、簡単だからといって自動的に良い選択になるわけではありません。本記事ではEKSのメリットと表裏一体の難易度について、できる限り情報に基づいた見方を示してきましたが、ここで重要な但し書きが1つあります。これまで論じてきた難易度は、ステートレスなアプリ(およびvalkey/redisキャッシュや、Grafana LabsのPLGオブザーバビリティスタックのようなセルフホスト型監視ツールなど、データ消失が許容されるごく一部のステートフルアプリ)を運用していることを前提としていました。
- 多くの場合、ユーザーはステートフルアプリをKubernetesにインストールしますが、自動バックアップ、自動リストア、テスト、CICDパイプライン連携といったライフサイクル全体を考慮できていません。
これらをすべて織り込むと、長期にわたって高い信頼性を維持するために必要な運用オーバーヘッドは、しばしば極端に高くなります。
- そのため、次の3つの選択肢を検討するに値する水準になります。
- 1. ステートフルなworkloadsに関するベストプラクティスをあえて厳格に実装しないことで、運用オーバーヘッドを大幅に避ける代わりに、年に1度程度・数時間規模のダウンタイムが発生するリスク増を許容する。
- 2. 高い稼働率と容易な災害対策が必要なら、高価なマネージドサービスへ寄せたほうが、結果的に総所有コストが低くなる場合があります。
- 3. ステートフルなworkloadsに関するベストプラクティスを厳格に実装するために、(個別のステートフルアプリ/データベースごとに)1〜6か月の専任エンジニアリング工数と労力、そしてそれに伴うメンテナンス負担増を、ステークホルダーが受け入れる意思と意欲を持っているかを確認する。
ここまで説明してきたパラドックスをご理解いただければ、皮肉にもEKSは「簡単すぎるがゆえに難しい」と見なされがちであること、しかし正しい戦略を取ればEKSは扱いやすい状態を維持でき、多くのケースではより良い選択肢になり得ること、ただし常にそうとは限らないことが見えてくるはずです。なぜなら、ECSはデバッグこそ厄介ですが、いったん正しく動かせばメンテナンスフリーで動き続ける傾向があるからです。
本記事がお役に立ったなら、doit.com/servicesもぜひご覧ください。