Amazon Elastic Container Service(ECS)を本番運用するうえでの設計・運用のベストプラクティスをまとめたドキュメント。
目次
- コンピューティングオプションの選択
- タスク定義
- コンテナイメージ
- ネットワーク
- セキュリティ
- デプロイ
- オートスケーリング
- 可用性・耐障害性
- オブザーバビリティ
- コスト最適化
- IaC・運用
- チェックリスト
1. コンピューティングオプションの選択
ECS ではキャパシティプロバイダーを通じて実行基盤を選ぶ。
| オプション | 管理負荷 | 柔軟性 | 向いているケース |
|---|---|---|---|
| AWS Fargate | 最小(サーバー管理不要) | 中 | 一般的な Web/API、バッチ、まず迷ったらこれ |
| ECS Managed Instances | 小(EC2 のライフサイクルは ECS が管理) | 高 | GPU、特定インスタンスタイプ、Capacity Reservation を使いたい場合 |
| EC2(自己管理) | 大(AMI・パッチ・ASG を自前管理) | 最大 | カーネル設定や特殊なホスト構成が必要な場合 |
| ECS Express Mode | 最小(ALB・TLS・スケーリング等を自動構成) | 低〜中 | 素早く Web サービスを立ち上げたい場合 |
ポイント
- デフォルトは Fargate。Fargate で要件を満たせない(GPU、大容量インスタンス、特定 CPU アーキテクチャ等)場合に Managed Instances を検討する。
- 自己管理の EC2 起動タイプは、Managed Instances でも要件を満たせない場合の最終手段と考える。
- 起動タイプ(launchType)ではなくキャパシティプロバイダー戦略を使う。Fargate と Fargate Spot の比率指定など、後から柔軟に変更できる。
- Graviton(ARM64)を選択肢に入れる。互換性があれば x86 より価格性能比が高い。
2. タスク定義
リソース設定
- タスクレベルで
cpu/memoryを必ず指定する。 - コンテナレベルでは
memoryReservation(ソフトリミット)とmemory(ハードリミット)を使い分ける。ハードリミット超過でコンテナは OOM Kill される。 - 実測値(CloudWatch Container Insights)を見てライトサイジングする。過剰なリソース割り当てはコストの最大要因になりやすい。
1タスク = 1つの関心事
- 1タスク定義には「一緒にスケールし、一緒にデプロイされるもの」だけを入れる。
- サイドカー(ログルーター、プロキシ、エージェント等)は同一タスクに含めてよいが、独立したアプリケーションは別サービスに分ける。
essential: trueはメインコンテナに設定し、補助的なサイドカーは要件に応じてfalseにする。
コンテナの依存関係とヘルスチェック
dependsOnで起動順序を制御する(例: ログルーター → アプリ)。- コンテナの
healthCheckを定義する。ALB のヘルスチェックとは別に、コンテナ自体の健全性を ECS が把握できる。 startPeriodを適切に設定し、起動の遅いアプリが早々に unhealthy 判定されないようにする。
グレースフルシャットダウン
- アプリは SIGTERM を受け取って処理中のリクエストを完了してから終了するよう実装する。
stopTimeout(デフォルト 30 秒、Fargate は最大 120 秒)をアプリの終了処理時間に合わせる。- ALB のターゲットグループの
deregistration_delayもあわせて調整する(デフォルト 300 秒は長すぎることが多い)。 initProcessEnabled: trueを設定し、PID 1 問題(シグナル伝搬やゾンビプロセス)を回避する。
その他
- ルートファイルシステムを読み取り専用にする(
readonlyRootFilesystem: true)。書き込みが必要なパスは tmpfs やボリュームを使う(tmpfs は Fargate・Managed Instances でも利用可能)。 - タスク定義のリビジョンは IaC で管理し、手動での登録は避ける。
3. コンテナイメージ
- Amazon ECR を使い、VPC エンドポイント経由でプルする。
- イメージタグは不変(immutable)にする。
latestタグの運用は避け、Git SHA やセマンティックバージョンでタグ付けする。ECR のタグイミュータビリティ設定を有効化する。 - ECR のイメージスキャン(Amazon Inspector 拡張スキャン推奨)を有効化し、脆弱性を継続的に検出する。
- マルチステージビルドでイメージを小さく保つ。distroless や軽量ベースイメージを検討する。
- コンテナは 非 root ユーザーで実行する(
USER指示)。 - ECR のライフサイクルポリシーで古いイメージを自動削除する。
- 起動速度が重要な場合は SOCI(Seekable OCI)による遅延ロードを検討する。
4. ネットワーク
ネットワークモード
awsvpcモードを使う(Fargate・Managed Instances では必須)。タスクごとに ENI が割り当てられ、セキュリティグループをタスク単位で適用できる。- EC2 起動タイプで
awsvpcを使う場合、ENI 数の上限に注意し、ENI トランキングを有効化する。
サブネット設計
- タスクはプライベートサブネットに配置し、パブリック IP を付与しない。
- インターネット向けトラフィックは ALB/NLB をパブリックサブネットに置いて受ける。
- 外部への通信は NAT Gateway、または可能なら VPC エンドポイントを使う。
- 複数 AZ にまたがるサブネットを指定する(最低 3 AZ 推奨)。
- タスク数×ENI に対して十分な IP アドレス空間を確保する。
VPC エンドポイント
NAT Gateway のデータ処理コスト削減とセキュリティ向上のため、以下のエンドポイントを用意する。
com.amazonaws.<region>.ecr.apicom.amazonaws.<region>.ecr.dkrcom.amazonaws.<region>.s3(Gateway 型。ECR のレイヤー取得に必要)com.amazonaws.<region>.logscom.amazonaws.<region>.secretsmanager/ssm(シークレット利用時)com.amazonaws.<region>.ssmmessages(ECS Exec 利用時)
サービス間通信
- ECS Service Connect を第一候補にする。サービスディスカバリ、ロードバランシング、リトライ、メトリクスがサイドカーの管理なしで得られる。
- シンプルな DNS ベースの解決で十分なら Cloud Map によるサービスディスカバリでもよい。
- App Mesh はサポート終了予定のため、新規採用は避け Service Connect へ移行する。
セキュリティグループ
- タスク用セキュリティグループのインバウンドは ALB のセキュリティグループからのみ許可する(CIDR ではなく SG 参照)。
- サービスごとにセキュリティグループを分け、最小限の通信のみ許可する。
5. セキュリティ
IAM ロールの分離
| ロール | 用途 | 付与する権限の例 |
|---|---|---|
| タスク実行ロール(Task Execution Role) | ECS エージェントが使用 | ECR からのプル、CloudWatch Logs への書き込み、シークレット取得 |
| タスクロール(Task Role) | アプリケーションが使用 | S3、DynamoDB、SQS など業務に必要な権限のみ |
| インフラストラクチャロール | ECS がロードバランサーや Managed Instances 等を操作 | AWS 管理ポリシーを利用 |
- 2つのロールを混同しない。アプリに必要な権限はタスクロールに、起動に必要な権限は実行ロールに付与する。
- サービスごとにタスクロールを分け、最小権限を徹底する。
- EC2 起動タイプでは、タスクからインスタンスメタデータ(IMDS)経由でインスタンスロールを取得できないようブロックする(
ECS_AWSVPC_BLOCK_IMDS=true、IMDSv2 必須化)。
シークレット管理
- 環境変数に平文でシークレットを書かない。
- タスク定義の
secretsで Secrets Manager または SSM Parameter Store(SecureString) を参照する。 - Secrets Manager のローテーションを有効化する。シークレットはタスク起動時に注入されるため、ローテーション後は新しいタスクへの入れ替えが必要な点に注意。
ランタイムセキュリティ
privileged: trueは使わない。- Linux capabilities は不要なものを
dropする(ALLを drop して必要なものだけaddするのが理想)。 - Amazon GuardDuty Runtime Monitoring(ECS/Fargate 対応)を有効化する。
- 本番での調査用に ECS Exec を有効化しつつ、IAM 条件と CloudTrail / ログ記録で利用を監査する。
ガバナンス
- IAM 条件キー(
ecs:cluster、ecs:task-definition、CPU/メモリ等)で、誰がどのクラスターでどのサイズのタスクを起動できるかを制御する。 - AWS Config ルール / Security Hub の ECS 関連コントロールでドリフトを検知する。
- タグ伝搬(
propagateTags: SERVICEまたはTASK_DEFINITION)とマネージドタグ(enableECSManagedTags)を有効化する。
6. デプロイ
デプロイ戦略の選択
ECS はネイティブで以下の戦略をサポートしている(CodeDeploy 不要)。
| 戦略 | 特徴 | 向いているケース |
|---|---|---|
| ローリングアップデート | 旧タスクを段階的に置き換え | シンプルなサービス、内部向けワーカー |
| ブルー/グリーン | 新リビジョンを並行起動し、検証後に一括切替 | 即時ロールバックが必要なサービス |
| リニア | 一定割合ずつトラフィックを移行(例: 10% ずつ) | 慎重に段階リリースしたい場合 |
| カナリア | 少量のトラフィックで検証後、残りを一括移行 | 決済など影響の大きいサービス |
- ブルー/グリーン・リニア・カナリアは ALB、NLB、Service Connect で利用できる。
- 新規構築では CodeDeploy 連携ではなく ECS ネイティブのデプロイを使う(AWS 推奨)。
- ベイク時間(bake time) を設定し、トラフィック移行後もしばらく旧リビジョンを残して問題があれば即ロールバックできるようにする。
安全装置
- デプロイサーキットブレーカーを有効化し、
rollback: trueにする。タスクが起動し続けられない場合に自動ロールバックされる。 - CloudWatch アラームベースのロールバックを設定する(エラー率、レイテンシ、5xx 等)。
- ライフサイクルフック(Lambda)で、トラフィック移行前のテスト実行や検証を自動化する。
- 手動承認が必要な場合は PAUSE ライフサイクルフックでデプロイを一時停止し、確認後に継続・ロールバックする。
ローリングアップデートの設定
minimumHealthyPercentは 100%、maximumPercentは 200% を基本とし、デプロイ中の容量低下を防ぐ。healthCheckGracePeriodSecondsをアプリの起動時間に合わせる。
CI/CD
- イメージビルド → スキャン → ECR プッシュ → タスク定義更新 → サービス更新 をパイプライン化する。
- デプロイはイメージのダイジェスト(sha256) または不変タグで行い、再現性を確保する。
- ステージング環境で同じタスク定義・同じイメージを使って検証する。
7. オートスケーリング
サービスオートスケーリング
- ターゲット追跡スケーリングを基本とする。
- CPU 使用率(目安 50〜70%)
- メモリ使用率
ALBRequestCountPerTarget(Web サービスでは最も実態に即しやすい)
- キューワーカーは SQS のキュー長(タスクあたりのバックログ)をカスタムメトリクスにする。
- 高解像度(20 秒)メトリクスによるスケーリングを活用し、スケールアウトの反応速度を上げる。
- スケールアウトは速く、スケールインはゆっくり(クールダウンを長め)に設定する。
- 予測可能な負荷パターンにはスケジュールスケーリングや予測スケーリングを併用する。
minCapacityは AZ 数以上(例: 3 AZ なら最低 3)にする。
クラスターオートスケーリング(EC2 / Managed Instances)
- EC2 の場合はキャパシティプロバイダーのマネージドスケーリングを有効化し、
targetCapacityを 100% 未満(例: 90%)にしてヘッドルームを確保する。 - マネージドターミネーション保護を有効化し、タスク実行中のインスタンスが終了されないようにする。
- Managed Instances ではインスタンスのプロビジョニングとビンパッキングを ECS に任せられる。
8. 可用性・耐障害性
- 複数 AZ に分散する。Fargate では指定したサブネットの AZ に自動分散される。EC2 では
spread配置戦略(attribute:ecs.availability-zone)を使う。 - サービスの
desiredCountは最低 2、推奨は AZ 数以上。 - ヘルスチェックを多層で設計する:
- コンテナヘルスチェック(プロセスの生存)
- ALB ターゲットグループヘルスチェック(リクエスト処理可否)
- ヘルスチェックエンドポイントは軽量にし、外部依存先の障害でカスケード的に全タスクが unhealthy にならないよう注意する。
- Fargate Spot は中断(2 分前通知)を前提とし、ステートレスかつ中断耐性のあるワークロードに限定する。オンデマンドの
baseを確保する。 - ステートはコンテナ内に持たず、RDS / DynamoDB / ElastiCache / S3 / EFS などの外部サービスに保持する。
- 重要なワークロードでは EC2 Capacity Reservation(Managed Instances で利用可)で容量を確保する。
9. オブザーバビリティ
ログ
awslogsドライバーで CloudWatch Logs に送るのが最もシンプル。- 複数の送信先やフィルタリングが必要なら FireLens(Fluent Bit) を使う。
mode: non-blockingとmax-buffer-sizeを設定し、ログ送信の詰まりでアプリが停止しないようにする(トレードオフとしてログ欠損の可能性がある)。- 構造化ログ(JSON) で出力し、CloudWatch Logs Insights で検索しやすくする。
- ロググループに保持期間を必ず設定する(無期限はコスト増の原因)。
メトリクス
- CloudWatch Container Insights(オブザーバビリティ強化版) を有効化し、タスク・コンテナ単位のメトリクスを取得する。
- 主要アラーム:
- サービスの
RunningTaskCount<DesiredTaskCount - CPU / メモリ使用率の高止まり
- ALB の 5xx 率、ターゲットレスポンスタイム(p99)
UnHealthyHostCount
- サービスの
トレース
- AWS Distro for OpenTelemetry(ADOT) をサイドカーとして配置し、X-Ray 等へトレースを送る。
- Service Connect のメトリクスでサービス間通信の状況を可視化する。
イベント
- ECS のサービスイベント・タスク状態変化を EventBridge で捕捉し、タスクの異常停止(
stoppedReason)を通知する。
10. コスト最適化
- ライトサイジング:Container Insights の実測値に基づき CPU/メモリを見直す。AWS Compute Optimizer の ECS on Fargate 推奨も活用する。
- Graviton(ARM64) を採用する。
- Fargate Spot を中断耐性のあるワークロード(バッチ、開発環境、ワーカー)に使う。キャパシティプロバイダー戦略でオンデマンドと混在させる。
- Compute Savings Plans で Fargate・EC2 の継続利用分を割引する。
- 開発・検証環境は夜間・休日に
desiredCount: 0にスケールダウンする。 - VPC エンドポイントで NAT Gateway のデータ処理料金を削減する。
- CloudWatch Logs の保持期間とログ量(不要なデバッグログ)を管理する。
- ECR ライフサイクルポリシーで不要イメージを削除する。
- コスト配分タグを設定し、サービス・チーム単位でコストを可視化する。
11. IaC・運用
- クラスター、サービス、タスク定義、IAM、ネットワークはすべて IaC(CloudFormation / CDK / Terraform) で管理する。
- 環境(dev / stg / prod)ごとにクラスター、できればアカウントを分離する。
- コンソールでの手動変更を禁止し、ドリフトを防ぐ。
- ECS Exec を有効化しておき、障害調査時にコンテナへ安全にアクセスできるようにする(SSH は使わない)。
- Fargate のプラットフォームバージョンは
LATESTを使い、定期的なタスクの入れ替えでパッチを適用する。Fargate はメンテナンスのためにタスクをリタイアさせることがあるため、タスク置き換えに耐える設計にする。 - EC2 起動タイプでは ECS 最適化 AMI を定期的に更新する(または Managed Instances に移行して運用負荷を下げる)。
- ランブック(障害対応手順)を整備し、ロールバック手順を事前に確認しておく。
12. チェックリスト
設計
- 実行基盤は Fargate を第一候補とし、要件に応じて Managed Instances を選択している
- キャパシティプロバイダー戦略を使用している
- タスクはプライベートサブネットに配置し、複数 AZ に分散している
-
awsvpcネットワークモードを使用している - サービス間通信に Service Connect を使用している
- 必要な VPC エンドポイントを作成している
セキュリティ
- タスク実行ロールとタスクロールを分離し、最小権限にしている
- シークレットは Secrets Manager / Parameter Store から注入している
- コンテナは非 root で実行し、ルートファイルシステムを読み取り専用にしている
- ECR イメージスキャンを有効化し、タグをイミュータブルにしている
- GuardDuty Runtime Monitoring を有効化している
- セキュリティグループは SG 参照で最小限に絞っている
デプロイ・可用性
- デプロイサーキットブレーカーと自動ロールバックを有効化している
- CloudWatch アラームによるロールバックを設定している
- 重要サービスではブルー/グリーン・カナリア・リニアのいずれかを採用している
- コンテナヘルスチェックと ALB ヘルスチェックを設定している
- SIGTERM によるグレースフルシャットダウンを実装している
-
desiredCount/minCapacityは AZ 数以上にしている
運用
- Container Insights を有効化している
- 主要メトリクスにアラームを設定している
- ロググループに保持期間を設定している
- オートスケーリング(ターゲット追跡)を設定している
- ECS Exec を有効化し、利用を監査している
- すべてのリソースを IaC で管理している