ECSのタスク定義は「動く」だけなら数分で書けますが、本番で安定させるにはCPU/メモリ予約、ログ、Secrets、ヘルスチェック、2つのIAMロール、そして停止時の挙動まで詰める必要があります。現場でつまずきやすい要点を順に整理します。
ECSのタスク定義は、コンテナ基盤の設計思想がそのまま現れる場所です。docker run のオプションをJSONに落としただけの状態でも起動はしますが、本番でSLOを守り、障害時に迷わないためには、リソース予約・ログ・機密情報・ヘルスチェック・権限・停止処理までを一つずつ意図を持って決める必要があります。本記事ではFargate/EC2どちらのlaunch typeでも共通して効く「タスク定義の勘所」を、実務でつまずきやすい順に整理します。数値・上限はバージョンやプラットフォーム依存のため、最終的な確定値は必ず公式ドキュメントで最新を確認してください。
01タスク定義の全体像 — familyとcontainerDefinitions
タスク定義は複数のパートに分かれます。family(バージョン管理の単位)、IAMタスクロール、ネットワークモード、containerDefinitions、ボリューム、そしてlaunch typeです。このうち必須なのは family と containerDefinitions の2つだけで、残りは任意です。family に登録するたびにリビジョン番号が1から順に採番され、これがロールバックやデプロイ履歴の実体になります。
containerDefinitions は最低1つのコンテナエントリを含む配列です。ここに複数コンテナを同居させるか、別タスクに分けるかが最初の設計判断になります。AWSのベストプラクティスは明快で、以下がすべて当てはまるときだけ同一タスクにまとめよ、としています。
- コンテナ同士がライフサイクルを共有する(同時に起動・停止する)
- 同一ホスト上で動く必要がある(localhostポートで参照し合う)
- リソースやデータボリュームを共有する
当てはまらないなら別タスク定義に分け、個別にスケール・プロビジョニングできるようにします。「Webアプリ + ログルーター」のようなサイドカー構成は前者、「Webアプリ + バックエンドAPI」のように独立してスケールさせたいものは後者、が基本線です。
02CPU/メモリの予約 — 予約と上限を分けて考える
Fargateではタスクレベルで cpu と memory を指定し、その組み合わせは決められた表(例: 0.25 vCPU なら 0.5/1/2 GB など)から選びます。EC2 launch typeではコンテナレベルの memory(ハードリミット)と memoryReservation(ソフトリミット)を使い分けられるのが要点です。
memoryReservation(ソフトリミット): スケジューリング時に確保する量。ホストのメモリが逼迫したときにDockerがこの値まで抑えようとします。memory(ハードリミット): これを超えるとOOMでコンテナが強制終了されます。
例えば通常128 MiB、たまに256 MiBまでバーストするコンテナなら、memoryReservation を128 MiB、memory を300 MiBに設定します。こうすると配置計算では128 MiBしか消費せず、必要時には300 MiBまで使えます。タスクレベルのメモリを指定しない場合、各コンテナで memory か memoryReservation の少なくとも一方を非ゼロで指定する必要があり、両方指定するなら memory は memoryReservation より大きくしなければなりません。
memory)を必ず設定し、OOMの発生をCloudWatchで可視化しておくと原因追跡が早くなります。FargateかEC2かの判断はFargate vs EC2 launch typeを参照してください。03サイドカーとFireLens — ログルーティングの型
サイドカーの代表例がFireLensによるログルーティングです。アプリのログ処理をインフラ層に切り離せるため、送信先の変更(CloudWatch → Firehose → S3 など)をアプリの再ビルドなしに設定だけで行えます。構成は次の3点セットです。
firelensConfiguration(type: fluentbit推奨)を持つログルーターコンテナ。essential: trueにするのが推奨です。- アプリコンテナ側で
logConfigurationのlogDriverをawsfirelensに設定。 - ログ送信に必要な権限を持つタスクIAMロール。
ECSは logConfiguration のオプションからFluent Bitの出力設定を自動生成し、match はFireLensが管理するのでタスク定義には書きません。イメージは public.ecr.aws/aws-observability/aws-for-fluent-bit を使います。デフォルトで ecs_cluster / ecs_task_arn / ecs_task_definition などのメタデータが自動付与され、不要なら enable-ecs-log-metadata を false にできます。
24224 でリッスンします。タスクのセキュリティグループでこのポートへのイングレスを絶対に許可しないでください(awsvpc ならタスクのSG、bridge なら 24224 のポートマッピングを作らない)。外部から到達可能だとログ経路が汚染されます。ログ設計全体は監視・アラート設計と合わせて詰めておくと過不足がありません。04Secrets Manager / SSMからの環境注入
DB接続情報やAPIキーを平文で environment に書くのはアンチパターンです。DescribeTaskDefinition で誰でも読めてしまうためです。代わりに secrets パラメータで、値の参照(ARN)だけを持たせ、起動時にECSエージェントが解決してコンテナの環境変数に注入します。
- Secrets Manager:
"valueFrom": "arn:aws:secretsmanager:region:acct:secret:name"。JSONキー指定で特定フィールドだけ取り出すこともできます。 - SSM Parameter Store:
"valueFrom": "arn:aws:ssm:region:acct:parameter/name"。
形式は共通で {"name": "環境変数名", "valueFrom": "ARN"} です。ここで重要なのは、この解決を行うのはタスクロールではなく実行ロールだという点です。実行ロールに secretsmanager:GetSecretValue や ssm:GetParameters、KMS復号が必要なら kms:Decrypt を付与しないと、タスクは起動時に失敗します。どちらのストアを使うかは要件次第で、ローテーション必須ならSecrets Manager、単純な設定値でコストを抑えたいならParameter Storeが基本です。詳しくはSecrets Manager vs Parameter Storeを参照してください。
logConfiguration の secretOptions も同じ仕組みで注入します。またVPCエンドポイント経由でSecretsを解決する構成では、エンドポイント未整備が「起動時だけ失敗」の典型原因になります。マルチアカウント統制下では解決先アカウントとKMSキーポリシーも要確認です。05ヘルスチェック — ECS・ALB・アプリの3層を混同しない
「ヘルスチェック」と一口に言っても、ECSコンテナヘルスチェック、ALBターゲットグループのヘルスチェック、アプリ内部のヘルスの3層があります。混同すると「ALBは正常判定なのにECSがタスクを殺し続ける」といった噛み合わない事故が起きます。タスク定義で設定するのは healthCheck パラメータで、コマンドの形式と各値の範囲は次のとおりです。
command:[ "CMD-SHELL", "curl -f http://localhost/ || exit 1" ]の形。成功判定は終了コード(exit code)のみで、0でhealthy、非ゼロでunhealthyです。標準出力/標準エラーの内容や有無は判定に影響せず、診断用にHealth.Logに記録されるだけです。interval: チェック間隔。5〜300秒、デフォルト30秒。timeout: 成功待ち時間。2〜60秒、デフォルト5秒。retries: unhealthy判定までの再試行回数。1〜10回、デフォルト3回。startPeriod: 起動猶予。0〜300秒、デフォルトは無効。この間の失敗はリトライ回数にカウントされません。
起動に時間のかかるJVMアプリなどでは startPeriod を適切に設定しないと、まだ立ち上がり中のコンテナがunhealthy扱いで殺され、再起動ループに陥ります。ALB側のヘルスチェックとは目的が異なる(ALBは「トラフィックを流してよいか」、ECSは「コンテナを生かすか殺すか」)ため、両者のパラメータは独立して調整します。
06ログ設定 — logConfigurationとドライバの選択
ログはアプリから stdout/stderr に書き、logConfiguration で送信先を決めるのが鉄則です。代表的なドライバは awslogs(CloudWatch Logs直送)と awsfirelens(FireLens経由)の2つです。
- awslogs: 最小構成。
mode: non-blockingとmax-buffer-sizeを指定すると、ログI/OがアプリのスループットをブロックするリスクをFireLensなしで下げられます。 - awsfirelens: フィルタリング・複数宛先・S3やFirehoseへのルーティングが必要な場合。前述のサイドカーが必要です。
判断軸はシンプルで、「CloudWatch Logsに素直に集約できればawslogs、加工・振り分け・別宛先が要るならFireLens」です。CloudWatch Agentやtd-agentとの使い分けはCloudWatch Agent vs td-agentも参考になります。
07タスクロール vs 実行ロール — 混同が事故の温床
ECSには紛らわしい2つのIAMロールがあり、この違いを言語化できるかが実務の分かれ目です。
タスク実行ロール(executionRoleArn)は、ECS/Fargateエージェントがユーザーに代わってAWS APIを呼ぶためのロールです。ECRからのイメージpull、CloudWatch Logsへの書き込み、そして前述のSecrets/SSM解決に使われます。AWS管理ポリシー AmazonECSTaskExecutionRolePolicy がベースになります。
タスクロール(taskRoleArn)は、コンテナ内で動くアプリケーションのコードがAWSサービス(S3、DynamoDB、SQSなど)を呼ぶための権限です。アプリが業務で使う権限はすべてこちらに集約します。
08graceful shutdown — SIGTERMとstopTimeoutの落とし穴
スケールインやデプロイでタスクが停止するとき、ECSはまず SIGTERM を送り、その後 SIGKILL を送ります。この間隔を決めるのが stopTimeout です。デフォルトは30秒、最大は120秒(Linux、プラットフォームバージョン 1.3.0 以降)です。アプリが SIGTERM を無視すると、ECSは SIGKILL まで待たされ、処理中のリクエストが途中で切られます。
ここで見落としがちなのが、DockerとECSは SIGTERM をPID 1にしか送らない点です。シェル経由(sh -c "...")で起動するとシェルがPID 1になり、シグナルが子プロセスのアプリに伝わりません。exec 形式で起動するか、initProcessEnabled でinitプロセスを挟むことでゾンビプロセスとシグナル伝播の問題を回避します。アプリ側では SIGTERM を受けたら新規リクエストの受付を止め、処理中のものを完了させる(またはタスク外へ退避する)実装が必要です。
deregistration_delay.timeout_seconds と stopTimeout、アプリのgraceful shutdownの3つが噛み合っていないと、無停止デプロイのつもりで502が出ます。EC2 launch typeではエージェントの ECS_CONTAINER_STOP_TIMEOUT も関係するため、長い処理を扱うサービスでは併せて確認してください。—まとめ
ECSタスク定義は、コンテナ1つを動かすだけならすぐ書けますが、本番品質にするには次の勘所を押さえる必要があります。
- 同居させるコンテナはライフサイクル・ホスト・リソースの共有条件で判断する
- メモリはソフトリミット(
memoryReservation)とハードリミット(memory)を分けて設計する - ログはFireLensサイドカーで切り離し、ポート24224は外部非公開にする
- 機密情報は
secretsでARN参照し、解決権限は実行ロールに付ける - ヘルスチェックはECS・ALB・アプリの3層を混同せず、
startPeriodで起動猶予を与える - 実行ロール(起動時のエージェント)とタスクロール(実行中のアプリ)の責務を分ける
- graceful shutdownは
SIGTERMのPID 1問題・stopTimeout・ALB drainingを揃える
数値・上限はプラットフォームバージョンで変わり得るため、確定値は必ず公式ドキュメントで最新を確認してください。設計や運用の相談は導入事例もあわせてご覧のうえ、お問い合わせください。
—参考(一次情報)
- Amazon ECS task definition parameters(AWS公式ドキュメント)
- Example Amazon ECS task definition: Route logs to FireLens(AWS公式ドキュメント)
- Pass sensitive data to a container using Secrets Manager(AWS公式ドキュメント)
- Amazon ECS task execution IAM role(AWS公式ドキュメント)
- Best practices for Amazon ECS container images / applications(AWS公式ドキュメント)