2021.02.13

AWS EKSとECSの比較と選択基準

概要

AWSには、マネージドなコンテナプラットフォームとして、EKS(Elastic Kubernetes Service)とECS(Elastic Container Service)があります。

どちらもコンテナオーケストレーションを提供するサービスで、EKSはデファクトスタンダードであるKubernetesが、ECSはAWS独自仕様がそれぞれ使用されており、使用方法や学習コスト、運用やメンテナンスコストについて異なる点も多くあります。

本記事では、EKSとECSの特徴を比較し、それぞれの選択基準について解説します。

AWSのコンテナプラットフォーム

AWSの主なコンテナプラットフォームには、EKS(Elastic Kubernetes Service)とECS(Elastic Container Service)があります。

以下に、EKSとECSの概要比較、およびコンテナイメージを登録するECR(Elastic Container Registry)との関連を示します。

platform outline

それぞれのサービスには、コンテナイメージや環境変数等を記述する定義ファイル(マニフェスト、タスク定義)が存在します。

定義ファイル内のコンテナイメージにはECRに登録されたイメージURLが記述され、このイメージでコンテナが起動します。

ここではECRしか記述していませんが、DockerHub等の別のDocker Registryも使用可能です。

EKSとECSは、どちらも定義ファイルをクラスターに反映することで、定義ファイルの内容に従ったコンテナを稼働します。

両者の定義ファイルには、記述可能な範囲が異なります。

大きな違いは以下です。

  • クラスター内通信が記述可能であるか否か
  • インバウンド(クラスター外からの通信受け付け)が記述可能であるか否か

定義ファイルで記述できないものについては、それを実現するためのAWSリソースの別途構築が必要となります。

EKS

EKSは、Kubernetesクラスターのマネージドサービスです。

Kubernetesはコンテナオーケストレーションのデファクトスタンダードであり、GCPやAzule、DigitalOcean等の多数のクラウドサービスでも提供されています。

以下に、構成要素とマニフェストの適用、関連インフラやGitOpsと呼ばれるCICDの外観を示します。

eks feature

EKSはコントロールプレーンとワーカーノード群で構成されています。

KubernetesマニフェストはGitリポジトリに格納されており、この内容がクラスターに適用された様子を示しています。

コントロールプレーン

コントロールプレーンは、AWSマネージドであり、マニフェストの適用やCLI(kubectl)によるコマンドを受け付け、リソースのワーカーノードへの展開および管理する役割を担います。

クラスターには 0.1USD/hour の料金が発生します。(月額約74USD)

ワーカーノード

マニフェストが実際に展開されるコンピューティングリソースです。

具体的には、EC2インスタンスもしくはFargateで構成されます。

ワーカーノード内部には、マニフェストのリソース以外に、コントロールプレーンから制御可能とするためのシステム関連のコンポーネントが配置されます。

システム関連コンポーネントは、Kubernetesリソースのものと、単にデーモンプロセスとして起動しているものとがあります。

EC2インスタンスを使用する場合は、システム関連コンポーネント等がセットアップされた、EKS最適化AMIを使用するか、独自にEKS最適化AMIをビルドする必要があります。

EKSバージョン

クラスターおよびワーカーノードには、EKSバージョンが存在します。

2021年2月13日時点では、EKSでサポートしている最新バージョンは1.18.9です。

また、クラスターだけでなく、ワーカーノードについても、EKS最適化AMIのバージョンを更新する必要があります。(Fargateは不要)

約3ヶ月サイクルで新バージョンがリリースされ、一年間程度サポートされます。

Kubernetesリソースの概要

Kubernetesの最小実行単位はPodと呼ばれ、Podの中でコンテナが起動します。

Pod等の定義はKubernetesマニフェストに記述し、マニフェストをクラスターにapplyすることで、Kubernetesリソースが作成されます。

Kubernetesマニフェストには、Podの他にも、環境変数やSecret、CronJobのような様々なリソースを記述可能です。

Podには、内部で起動するコンテナの詳細な定義が記述されます。

Deploymentは、Podをラッピングし、Podの起動数等の制御を担います。

Serviceは、Podと紐づいており、クラスタ内の別のPodからServiceを通してアクセス可能です。

Ingressは、クラスタ外部からのインバウンドを制御します。

クラスター外インフラ

EKSでは、Ingressリソースによってインバウンドを記述でき、AWSのALBやNLBと紐づけることが可能です。

単に紐づけるだけでなく、ALBやRoute53レコード自体の構築をEKSによって行わせることも可能です。

この場合、マニフェストをapplyすると、EKSによって自動的にALB等が作成されます。

GitOps

Kubernetesではマニフェストにリソース定義を記述しますが、マニフェストが常にクラスターと同期されている状態を保つための仕組みとして、GitOpsというものがあります。

GitOpsの詳細について本記事では割愛しますが、上図ではGitOps向けのCDツールもクラスターに展開し、マニフェストが保管されたGitリポジトリと常に同期する構成を記載しています。

ECS

ECSは、AWS独自のコンテナオーケストレーションのマネージドサービスです。

以下に、構成要素とマニフェストの適用、関連インフラやCICDの外観を示します。

ecs feature

クラスタ

ECSクラスターは、AWSによって管理・運用されています。

クラスターには料金がかかりません。

ワーカーノード

EKSと同様に、EC2インスタンスもしくはFargateで構成されます。

EC2インスタンスの場合は、ECSエージェントが起動している必要があります。

また、ECSにも最適化AMIが提供されています。

ECSリソースの概要

ECSの最小実行単位はTaskと呼ばれ、Taskの中でコンテナが起動します。

Taskの設定はタスク定義に記述し、環境変数やSecretも記述可能です。

ServiceはTaskを常時稼働させるための機能で、ALBやNLBと紐づけることで、クラスター外部からのインバウンドを受け付け可能となります。

CronのようなスケジュールタスクについてもECSでサポートしており、別途設定可能ですが、こちらはタスク定義の範囲外です。

クラスター外インフラ

EKSとは異なり、ECSではインバウンドに関するインフラは、別途構築が必要です。

また、クラスター内部のTask間での通信には、別途プライベートホステッドゾーンにに用意されたRoute53レコードおよびCloudMap等を構築して、プライベートドメインでアクセスできるようにする必要があります。

CloudMapの使用は、AWSマネジメントコンソールから手動でECSサービスを作成する際には、ウィーザードがあるため設定しやすいですが、Terraform等でIaC(Infrastructure as Code)したい場合には、これら必要なインフラを構築する必要があります。

CICD

タスク定義をGitリポジトリで管理する必要性はありませんが、今回の例ではタスク定義をGitリポジトリで管理し、CICDパイプラインにてリポジトリの内容を反映する構成例を記載しています。

EKSでは、Gitリポジトリと完全に同期可能ですが、ECSではそのような仕組みやエコシステムは(私の知る限り)存在しないため、都度CICDツール等でデプロイが必要です。

Lambda

最近Lambdaでもコンテナがサポートされました。

Amazon Web Services ブログ: AWS Lambda の新機能 – コンテナイメージのサポート

本記事ではLambdaについては記載していません。

別途検証したいと思います。

各プラットフォームの特徴

EKS

[Pros] クラスター内外通信をKubernetesで記述可能

前述の通り、EKSでは以下の機能をKuberntesの文脈で記述可能です。

  • Serviceリソースによるクラスター内部通信
  • Ingressとそれに付随するAWSリソースの自動構築によるクラスター外部からのインバウンド

これらに関するインフラを別途手動であったり、CloudformationやTerraformのようなツールでの作成・管理が不要となります。

新たなサービスを追加していくと、そのサービスとの関連や通信に関するインフラも増えて行きますが、Kubernetesマニフェストやリソースを見るだけでその全体を把握できるというのは、非常に大きな特徴です。

[Pros] GitOpsを構築できる

GitOpsは、ツールや手動操作によるコマンドを実行することなく、クラスターの状態とGitリポジトリのマニフェストとが同期する仕組みです。

GitOpsは、デプロイ対象の状態がマニフェストと一致しているかどうかを監視可能です。

このため、マニフェストの内容が確実にクラスターに反映されている、ということを信頼できます。

非GitOpsでは、別途CICDツールや手動でコマンドを実行し、デプロイする必要があります。

たとえマニフェストがGit管理されていたとしても、それが前回のコマンドで確実に反映されているか、という保証が難しくなります。

サービスが今、どの状態で稼働しているかが確実に保証されていることは、マニフェストがそのシステムの確実なドキュメントとして機能することでもあります。

例えば、以下のような局面で有効です。

  • 複数人で開発を進める際に、デプロイ状況を確実に共有する
  • システムを引き継ぐ場合
  • ある程度期間を置いたことで、メンテナンス時にどうなっていたかを思い出すところから始めるような場合

[Pros] CronやJobをKubertetesで記述可能

単発のJobやスケジュール指定可能なCronJobをKubernetesの文脈で記述可能です。

単発のJobは工夫次第でワーカキューから取り出して並列で起動する、というような構成にも応用できます。

[Cons] Kubernetesの学習コストが高い

Kubernetesは難しいと言われますが、Kubernetesリソースやマニフェストを理解すること自体はそれほど大変ではないと思います。

ECSでも、タスク定義やECS ServiceとTaskの関係等をキャッチアップする必要があるので、ECSよりはやや覚えることが多い程度と思います。

私見では、それ以外の以下の点で学習コストが高いと考えています。

  • クラスターのRBAC
  • ログ・メトリクス収集
  • Secretの取り扱い
  • 新バージョンへの追従
  • 関連ツール・エコシステムの理解と追従(kubectl, kustomize, helm など)

AWSの各種リソース(IAMやCloudwatch、SSM ParameterStore など)の理解がある前提ですが、ECSでは上記については設定が簡単に行えます。

また、関連ツールやエコシステムが数多く、進化も早いため、こちらのキャッチアップもそれなりに必要です。

[Cons] メンテナンスコストが高い

以下のメンテナンスコストを予め見積もっておくべきです。

  • バージョン更新

EKSでは、約3ヶ月サイクルで新バージョンがリリースされます。

各バージョンのサポート期限は、マイナーバージョンがリリースされてから一年間です。

(EKSバージョンの公式ドキュメントはこちらです。)

このように、それなりな頻度でクラスターおよびワーカーノードのEKSバージョンを更新する必要があります。

バージョン更新によって、Kubernetesで提供されるAPIバージョンが変更されたり、クラスターやワーカーノードで必要とされるシステム関連コンポーネントのバージョン更新を予め行う必要がでてきます。

マニフェストの変更や、システム関連コンポーネントの更新作業および検証を行うコストを見積もっておく必要があります。

  • pod、nodeの状態監視と異常時の対処

また、消費リソース等の影響で、Podが意図通りに適用できなかったり、Nodeが異常な状態となることが起こりえます。

この場合は、CLI等でワーカーノードにどのような異常が発生しているかの調査と対処が必要です。

単にリソース不足でPodが展開できなかったり、Nodeのシステム関連コンポーネントに異常が出ていたりなど、原因を特定できる知見が必要です。

  • クラスター運用費用

EKSでは、クラスター自体に料金がかかります。

月額74USD程度なので、大きなハードルではないですが、極小規模のサービスを展開する場合は考慮した方が良さそうです。

ECS

[Pros] EKSより学習コストが低い

EKSで学習コストが高い部分の習得が不要もしくはかなり楽です。

[Pros] メンテナンスコストが低い

ECSには、クラスターのバージョンは存在しないため、EKSのようにバージョン更新にコストがかかりません。

Fargateを使用する場合、プラットフォームバージョンというものがあり、これのメジャーバージョン更新が必要となる可能性はありますが、頻繁な更新は行われていません。

マイナーバージョンが更新されることはあるようで、時々AWSから再デプロイを求めるメールが届きます。

この際も、単に同じタスク定義を再度デプロイするだけで済み、基本的にはダウンタイムも発生することなく作業できます。

[Pros] スケジュールタスクを設定可能

ECSの機能として、タスクのスケジューリングがあり、Taskと同様にタスク定義を指定してデプロイ可能です。

[Cons] クラスター内外通信には別途インフラ構築が必要

ECSは、KubernetesのServiceに相当する機能を持たないため、クラスター内部にあるコンテナ同士で通信したい場合には、別途インフラ(Private Rtoute53 RecordやCloudMap)が必要となります。

また、クラスター外部からのインバウンドを受け付ける、Route53レコードやALB等のインフラについても、EKSのようにマニフェストに記述するようなことはできません。

インバウンドインフラ構築も別途必要になります。

連携させたいサービス数が多くなると、EKSで発生しないこれらのインフラ管理コストが大きくなります。

選択基準

サービスの複雑度

サービスの複雑度は、構築するPodやTaskの数に比例します。

PodやTask同士で通信する経路数や外部公開するサービス数が増えると、これに関連するインフラも合わせて増えていきます。

EKSでは、クラスタ内部のPod同士の通信およびクラスタ外部からのインバウンドインフラを、それぞれKubernetesマニフェスト内で記述できます。

ECSで、これと同様の機能を実現するためには、手動もしくはTerraform等で別途インフラを構築する必要があります。

サービス数が少なく、サービス間通信に関するインフラが定義ファイルで記述できないとしても、全体を無理なく見通せる程度のシンプルさに抑えられるのであれば、ECSを選択するのが良さそうです。

メンテナンスコストと、Kubernetesのキャッチアップができていない場合は学習コストも低く抑えることが見込めます。

開発状況

対象となるサービスが機能追加や変更でガンガン開発中なのか、それとも開発はほとんど発生せず運用・保守フェーズのものをレガシーな環境から移行したいのか、といった状況によっても選択基準が変わってくると思います。

EKSでは、バージョン更新等のメンテナンスコストを見積もる必要がありますが、サービスが増えていくことへ柔軟に対応できます。

一方、ECSではメンテナンスコストを低く抑えることができますが、サービス数に比例して付随するインフラの管理コストも増えていきます。

サービスが開発途上で、サービスをどれだけ追加するか見通しが立たない状況では、EKSを選択するのが良さそうです。

一方、運用・保守フェーズのものをレガシー環境から移行する際に、サービス複雑度が高くない場合は、ECSを選択するのが良さそうです。

但し、EKSを採用する場合は、後述のKubernetesの習得状況についても考慮が必要です。

kubernetesの習得状況

サービスの複雑度で記述した「全体を無理なく見通せる程度のシンプルさに抑えられる」程度の複雑度であったとしても、もしKubernetesを十分にキャッチアップできているのであれば、EKSを選択することも現実的です。

難しいのは、Kubernetesがキャッチアップできておらずかつ複雑度が高い場合ですが、Kubernetes習得への投資が可能な状況であれば、EKSを選択するメリットが大きいと思います。

まとめ

EKSとECSの特徴を比較し、サービスの複雑度や学習コスト、インフラ記述範囲、構築・運用・メンテナンスコストの各観点から、それぞれの選択基準について解説しました。

EKSは、柔軟に大規模で複雑なサービスを記述しやすい反面、学習コストやメンテナンスコストを受け入れる必要があります。

ECSは、EKSに比べると学習コストおよび運用コストが低く、シンプルなサービスを構築しやすい反面、クラスタ内外通信インフラを意識する必要があったり、複雑度に比例する管理コストがEKSよりも高くなる可能性があります。

どちらが正しい選択であるかの判断は難しいですが、選択基準の参考になれば幸いです。