NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

ECSサービスの設計ポイントをざっくりまとめてみる

本記事は  初夏のAWSアワードエンジニア祭り  1日目の記事です。
🍦  告知記事  ▶▶ 本記事 ▶▶  2日目  💻

尾澤です。

この度、2023 Japan AWS All Certifications Engineers に選ばれました。

更新が不安です。

というわけで今回はAWSアワードとかはあまり関係ないですが、
私が日頃業務で対峙するECSさんについてお話ししようかと思います。

ECSとは

もう今となってはコンテナといえばこれというサービスですね。(?)

改めての説明ですが、

Amazon ECS(Elastic Container Service)は、AWSが提供するコンテナオーケストレーションサービスです。
Webサービスなどを構成する場合、コンテナ単体で動かすにはさまざまな運用課題があるため、
基本的にはオーケストレーションツール(ex: Kubernetes, e)を使います。

AWSでコンテナを動かそうと思うと、まず真っ先にこのサービスが第一候補に上がるかと思います。

今回このテーマを書く理由

ここ数年でコンテナアーキテクチャの知見や実績が増えてきたなぁと実感しています。

私自身、ここ数年はECS移行などの案件に複数携わらせていただきました。

その間、ECSサービス自身のアップデートもどんどん進んできており、振り返ってみると、
ECSサービス作るのって結構考えること多くね?と思うようになりました。

今からECSを始めよう!と思った人がいたとすると、 キャッチアップの量も多くて大変そうだなーとつくづく思います。

そこで、個人的に今までの経験上ここは気にかけて設計してるよなーというポイントについて、
とりあえずこういうところから考えたらなんとかなるよ!という部分について、
主にインフラ観点でざっくりまとめてみようと思います。(とはいえボリューミー。。)

もちろんシステム要件によって気にすべき設定や関連するサービスも異なりますが、
今回は汎用的にECSサービスを構築して運用するという部分にフォーカスしてまとめてみようと思います。

ECSサービスの設計

設計といっても色々ありますが、
個人的には下記の項目で大枠となる方式設計を行って、開発を進めることがほとんどです。

  • ネットワーク
    • ALB、VPCなど、ECSを動かすためのネットワーク部分
  • コンテナ設計
    • 主にタスク定義周りの設計に相当
  • CI/CD
    • ツールの選定等
  • モニタリング
    • 監視設計
    • メトリクス取得方式
  • セキュリティ
    • 主に脆弱性管理

もちろん、上記以外のアプローチもあるかと思いますが、
今回はこちらをベースに話を進めてみようと思います。

前提として

それではざっくりまとめてみますが、
今回はネットワーク設計については触れません。

コンテナネットワークという領域もありますが、
こちらについても今回は考慮しませんので、ご了承ください。

また、アプリケーションをどうやってコンテナアーキテクチャに落とし込むか、
という点についても今回は記載していません。
(どちらかというとマイクロサービス設計なので)
あくまでECSサービスを構築する前提で、どういったことを考えるのかという部分にフォーカスします。

今回は前提として、ECS on Fargate を想定しています。
ECS on EC2 で必要な考慮点は記載されていませんので、ご容赦ください。

コンテナ設計

ここでは、主にタスク定義で設定する項目を考えていきます。
前提として、サービスタスク内のコンテナ構成は既に設計済みとします。

まずは、どのコンテナにおいてもまずは下記から決めていきます。

  • タスクコンテナへのリソース配分
  • 環境情報/秘匿情報の受け渡し

タスクコンテナへのリソース配分

サービスタスク内で複数コンテナが存在する場合、
それぞれのコンテナに対して柔軟に割り当てリソースを設定することができます。

具体的には下記のタスク定義パラメータで指定可能です。

  • cpu
    • CPUユニットのハード制限
  • memory
    • メモリのハード制限
  • memoryReservation
    • メモリのソフト制限

CPUについてはハード制限のみ、メモリについてはハード/ソフト制限の両方で設定可能です。

初期設計段階では、あまりリソース消費が見込まれないコンテナには少ないリソースをハード制限で設定しておき、
メインアプリケーション等のメモリ消費が高くなりそうなコンテナにはメモリのソフト制限を設定しておきます。

サービスタスクには、上記で設定した割り当てメモリよりも少し大きな値を入れて置き、
アプリケーションコンテナへの余剰分として割り当てておく、といった具合で設計したりします。

  • コンテナリソース割り当ての設定例
コンテナのリソース消費 初期設定
(ex: nginx, サイドカー等) cpu: 256
memory: 512
(ex: rails, java等) cpu: 512
memoryReservation: 1024

まずはこんな具合で割り当てて、動作検証していく中でチューニングしていく形になります。

環境情報/秘匿情報の受け渡し

例えば、DBへの接続情報や特定の外部サービスへの接続情報については、
アプリケーションコードに埋め込んでしまうと疎結合性が失われるだけでなく、
秘匿情報の漏洩にもつながりかねません。

ECSサービスで稼働するアプリケーションに対しては、
AWS SSM ParameterStoreを利用することで、これらの問題を回避できます。

SSM ParameterStoreは、AWSが提供する Key-Value Store なサービスです。

具体的には、必要となる環境情報/秘匿情報を、ParameterStore に登録します。
秘匿情報については、暗号化パラメータとして登録することで、secret としてECSサービスタスクに受け渡すことができます。

ECSタスク定義において secret セクションに、対象となるパラメータのKeyを指定することで、
タスクコンテナ側の環境変数に読み込ませることが可能です。

  • タスク定義の例
"containerDefinitions": [
        {
            "name": "awesome-app",
            "image": "1234567890.dkr.ecr.ap-northeast-1.amazonaws.com/awesome-app:v1",
            "cpu": 512,
            "memory": 1024,
            "environment": [
                {
                    "name": "ENVIRONMENT",
                    "value": "honban"
                }
            ],
            "secrets": [
                {
                    "name": "SECRET",  # ↓ honban/secret という KeySSMパラメータのValueが渡される
                    "valueFrom": "arn:aws:ssm:ap-northeast-1:1234567890:parameter/honban/secret"
                }

(おまけ)FargateにおけるCPU/Memoryの割り当て制限

Fargate で ECSサービスタスクを起動する際の注意点として、
サービスタスクに割り当てるCPUに対して、割り当て可能なメモリの範囲が決められていることです。

この範囲内で設定しないと、サービスタスクへのデプロイが正常にできなくなるため、
注意が必要です。

指定された CPU またはメモリの値が無効 - Amazon Elastic Container Service

CI/CD

CI/CDでは主に、

  • 実行基盤をどうするか
  • タスク定義をどう管理するか

といった点について考えることが多いです。

実行基盤をどうするか

基本的にECSサービスを構築する際には、
CI/CDパイプラインを利用する前提で設計することがほとんどです。

その場合、CI/CDをどういった実行基盤(ツール/サービス)で実現するかという問題があります。

すでにチーム内で運用されているCI/CD実行基盤(Jenkins/GitHub/GitLab/CircleCI/etc…)がある場合は、
そちらに相乗りするでよいかと思います。

AWSの場合、CI/CDと聞くとすぐに思い出すのは AWS Codeシリーズです。

例えば、ECSサービス用のコンテナイメージをビルド→デプロイまでを実現しようとすると、
CodePipeline(CodeCommit + CodeBuild (+ CodeDeploy))で対応可能です。

ECSなCodePipeline構成

上記の構成の場合は、AWS内で完結するという点と、
パイプラインの実行基盤(インフラ)を管理しなくてよいというメリットがあります。

ただし、細かな設定はAWSサービスの仕様に準拠する必要があります。

一方、外部ツールを使ったパイプラインを構成する場合、
処理実装に関しては自由度が高くなります。

ある程度作りこまないといけない箇所は、Codeシリーズと比較すると多くなる印象ですが、
AWSが提供するSDKやアドオンに対応するツールであれば、より簡単に実装できるかもしれません。

ただ、実行基盤の管理も必要になりますし、
外部ツールを利用する場合には、ツールとAWS間の通信・認証方式を考えないといけません。

  • 表: ざっくりとしたCI/CD実行基盤の比較
ツール インフラ管理 実装コスト 設定の自由度 AWSとの接続
AWS Codeシリーズ 不要 基本的に考慮不要
外部ツール
(Jenkins, GitHub/GitLab等)
中〜大 ネットワークレイヤーでの制御、
AssumeRole 方式の検討が必要

GitHub Actions の場合は、OIDC経由でIAM Role に Assume できる設定方法もありますので、
こういった機能をつかって、よりセキュアに接続する方式をとることも大事かと思います。

アマゾン ウェブ サービスでの OpenID Connect の構成 - GitHub Docs

タスク定義の管理

ECSタスク定義とは、
ECSサービスタスク内で稼働するタスクコンテナの構成情報を定義したファイルです。

ECSサービスは、このタスク定義をもとにタスクコンテナを起動していきます。

タスク定義にはざっと下記の設定項目があります。

  • 基となるコンテナイメージURI
  • 割り当てリソース(CPU/Memory)
  • Volume
  • Network
  • Logging
  • 環境変数/シークレット
  • などなど

タスク定義はリビジョン管理されており、上記の項目に変更や追加・削除があった場合は、
新しいリビジョンのタスク定義が作成される形となります。

気にすべきは、このタスク定義をどうやって管理するかです。

IaC(Terraform、CFn等)でAWSリソースをコード管理する場合、
タスク定義も同様に管理可能です。

しかし、コンテナイメージが変更されるといった場合に、
IaCでタスク定義を管理してしまうと、
アプリケーション更新時に毎回この部分の反映が必要になってしまいます。

これについては、下記のような棲み分けをすることで、
より運用に適した形になるかと思います。

  • タスク定義のテンプレートはIaCで管理する
    • 割り当てリソース、環境変数、Volume といったコンテナにおけるインフラ面の設定を管理
  • コンテナイメージの更新についてはアプリケーションデプロイパイプラインに任せる
    タスク定義更新処理の棲み分け

タスク定義にはコンテナイメージというアプリケーションのベースとなる部分と、
CPU/メモリやVolume、環境変数といったインフラ面に関与する設定が混在しているので、
可能な限り、各種設定を適切なライフサイクルで管理したいという意図があります。

モニタリング

コンテナのモニタリングについては大きく下記の二つになるかと思います。

  • コンテナリソース(CPU/Memory/Network/etc…)
  • APM(Application Perfomance Management)

コンテナリソース

ECSにおいては、Container InsightsをECSクラスターで有効化することで、
タスクコンテナ単位でCPU/メモリなどの詳細なメトリクスを取得することができます。

Container Insightsによって取得されたコンテナリソース情報は、CloudWatch Logsにログ情報として出力されます。

タスクコンテナ単位でのメトリクスを監視したい場合は、CloudWatch Logsからメトリクスフィルターを作成することで、
CloudWatchメトリクスとしても収集可能です。

基本的には有効化しておいて、
より高精細なメトリクスを見たい場合は適宜メトリクスフィルターを作成する、
といった具合で進めていくことが多いです。

APM

コンテナリソースの場合は、コンテナ自身のリソース消費について確認できますが、
その上で動いているアプリケーションがどういった動き方をしているのかを確認するには、
アプリケーションをトレースして、詳細なメトリクスを取得する必要があります。

APMを実現するには、AWSだとAWS X-Rayがあります。
外部のモニタリングツールですと、DatadogNewRelicといったものがあります。

基本的にこれらを導入する際は、
エージェントタスクを対象となるECSサービス内でサイドカーとして配置する必要があります。

また、エージェントタスクがX-Rayまたはモニタリングツールのエンドポイントにアクセスする必要があり、
特に対象サービスがPrivate Subnetに配置されている場合は通信方式についても考慮が必要です。

APMトレースする際の基本的なタスク構成

  • 既に外部のモニタリングツールを利用している→相乗りして使ってみる
  • モニタリングツールを利用していない / AWSで完結させたい → X-Ray でスタートしてみる

といった具合で進めるのが適切かと思います。

セキュリティ

最後はセキュリティです。

今回はECSサービス設計ということで、
イメージの脆弱性管理について記載します。

脆弱性管理

AWSにおけるコンテナイメージの脆弱性管理については、
Amazon ECRのイメージスキャンを使うことで実現可能です。

ECRイメージスキャンには下記の2つがあります。

  • ベーシックスキャン
  • 拡張スキャン

詳細は下記をご確認ください。

イメージスキャン - Amazon ECR

そのほかですと、Trivy等のOSSもあります。
これらを使って独自にパイプラインを組むこともできます。

ECR ベーシックスキャンはOSライブラリまでを対象としているので、
アプリケーションライブラリに対してのチェックについては、拡張スキャンを実施するか、
Trivy等の言語固有の脆弱性を検知できるツールを使う必要があります。

ツール OSライブラリの脆弱性検知 言語固有の脆弱性検知 コスト 備考
ECR ベーシックスキャン × ECR利用料金のみ
ECR 拡張スキャン 別途料金が発生
詳細→ 料金 - Amazon Inspector | AWS
Trivy(OSS) なし 別途実行基盤の整備が必要

AWSで完結させたい場合は、拡張スキャンを有効化すればよいですが追加料金が発生しますので、
これを回避したいようであれば、外部ツールで代替するといった方式をとる形になります。

まとめ

今では ECS Copilot App Runner といった簡単にECSサービスを構築できるツールもあり、
これらを使って土台を作る→細かくチューニングしていく、といった作り方もできるのかなと思います。
その上で、運用を意識するとやはり今回記した設計観点においては、最低限知っておいた方が良いかなと思っています。
もう触り慣れている方にとっては今更感がある内容かもしれませんが、
これからECS触るよーという人たちにとっても参考になると幸いです。

執筆者尾澤公亮

しがないインフラエンジニアです
AWSの入門書を執筆したりしてます

Twitter:@jstozw

Amazon 著者ページ:尾澤 公亮:作品一覧、著者略歴 - Amazon.co.jp