AWS ECS/Fargateでコンテナ運用|Docker→本番デプロイの実践ガイド

kento_morota 20分で読めます

「Dockerで開発しているが、本番環境のコンテナ運用をどうすればいいかわからない」「Kubernetesは難しすぎる」――そんな悩みを持つ開発者・IT担当者に最適なのが、AWS ECS/Fargateです。

この記事では、Dockerコンテナを本番環境にデプロイするまでの具体的な手順を解説します。ECSの基本概念からタスク定義の設計、Fargateによるサーバーレスなコンテナ運用まで、実務で使える知識を体系的にお届けします。

ECS/Fargateとは?コンテナ運用の選択肢を整理する

AWS ECS(Elastic Container Service)は、Dockerコンテナを大規模に実行・管理するためのコンテナオーケストレーションサービスです。そしてFargateは、そのECSのコンピューティングエンジンの一つで、サーバーの管理なしにコンテナを実行できます。

EC2起動タイプとFargate起動タイプの比較

ECSには2つの起動タイプがあり、用途に応じて選択します。

項目 EC2起動タイプ Fargate起動タイプ
サーバー管理 EC2インスタンスの管理が必要 不要(サーバーレス)
スケーリング インスタンスの追加・削除が必要 タスク数の変更だけで完了
コスト インスタンス単位の課金 vCPU・メモリの使用量課金
カスタマイズ性 OS・カーネルレベルの設定が可能 限定的
推奨ケース GPU利用、大量のコンテナ実行 一般的なWebアプリ、API

中小企業や少人数チームには、運用負荷の低いFargate起動タイプを強く推奨します。サーバーのパッチ適用やキャパシティプランニングから解放され、アプリケーションの開発に集中できます。

Dockerの基本については、Dockerとは?中小企業向けガイドも参考にしてください。

ECSの主要コンポーネント

ECSを理解するために、主要なコンポーネントを整理しましょう。

  • クラスター:タスクやサービスをグルーピングする論理的な単位
  • タスク定義:コンテナの設計図。イメージ、CPU、メモリ、環境変数などを定義
  • タスク:タスク定義に基づいて実行されるコンテナのインスタンス
  • サービス:タスクの実行数を維持し、ロードバランサーと連携する仕組み

事前準備|ECRにDockerイメージをプッシュする

ECSでコンテナを実行するには、まずDockerイメージをAWS ECR(Elastic Container Registry)にプッシュする必要があります。

ECRリポジトリの作成

# ECRリポジトリを作成
aws ecr create-repository \
  --repository-name mycompany/web-app \
  --image-scanning-configuration scanOnPush=true \
  --encryption-configuration encryptionType=AES256 \
  --region ap-northeast-1

scanOnPush=trueを設定すると、イメージをプッシュするたびに脆弱性スキャンが自動実行されます。本番環境で使用するイメージには必ず有効にしましょう。

Dockerイメージのビルドとプッシュ

# ECRにログイン
aws ecr get-login-password --region ap-northeast-1 | \
  docker login --username AWS --password-stdin \
  123456789012.dkr.ecr.ap-northeast-1.amazonaws.com

# イメージをビルド(マルチステージビルド推奨)
docker build -t mycompany/web-app:latest .

# タグ付け
docker tag mycompany/web-app:latest \
  123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/mycompany/web-app:latest

docker tag mycompany/web-app:latest \
  123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/mycompany/web-app:$(git rev-parse --short HEAD)

# プッシュ
docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/mycompany/web-app:latest
docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/mycompany/web-app:$(git rev-parse --short HEAD)

タグにはlatestだけでなく、Gitのコミットハッシュやバージョン番号も付与しましょう。デプロイの追跡やロールバックが容易になります。

本番向けDockerfileのベストプラクティス

# マルチステージビルドの例(Node.jsアプリケーション)
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
RUN addgroup --system appgroup && adduser --system appuser --ingroup appgroup
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]

本番用Dockerfileのポイントは以下の通りです。

  • マルチステージビルド:ビルドツールを含まない軽量なイメージを作成
  • 非rootユーザー:セキュリティのためrootで実行しない
  • HEALTHCHECK:コンテナの正常性を自動チェック
  • alpineベース:イメージサイズの最小化

タスク定義の設計|実務で押さえるべきポイント

タスク定義は、ECSの核となる設定です。実務で重要なポイントを押さえた設計例を紹介します。

実践的なタスク定義の例

{
  "family": "web-app",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
  "containerDefinitions": [
    {
      "name": "web-app",
      "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/mycompany/web-app:latest",
      "essential": true,
      "portMappings": [
        {
          "containerPort": 3000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "NODE_ENV",
          "value": "production"
        }
      ],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod/database-url"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/web-app",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      }
    }
  ]
}

タスク定義で注意すべきポイント

1. executionRoleArnとtaskRoleArnの違い

ロール 用途 必要な権限の例
executionRoleArn ECSエージェントがタスクを起動するために使用 ECRからのイメージ取得、CloudWatch Logsへの書き込み
taskRoleArn コンテナ内のアプリケーションが使用 S3アクセス、DynamoDBアクセスなど

IAMロールの設計については、AWS IAMのベストプラクティスを参照してください。

2. シークレットの管理

環境変数にパスワードやAPIキーを直接書くのは絶対に避けてください。AWS Systems Manager Parameter StoreやSecrets Managerを使い、secretsフィールドで参照します。

3. CPU・メモリの適切なサイジング

Fargateで指定できるCPU・メモリの組み合わせは制限があります。代表的な組み合わせは以下の通りです。

CPU(vCPU) メモリ(MB) 用途目安
256(0.25) 512〜2048 軽量API、バッチ処理
512(0.5) 1024〜4096 一般的なWebアプリ
1024(1) 2048〜8192 中規模のWebアプリ
2048(2) 4096〜16384 高負荷なアプリケーション
4096(4) 8192〜30720 データ処理、機械学習推論

ECSサービスの作成とロードバランサー連携

タスク定義ができたら、次はサービスを作成してALB(Application Load Balancer)と連携させます。

ALBターゲットグループの作成

# ターゲットグループの作成(IPタイプ:Fargate必須)
aws elbv2 create-target-group \
  --name web-app-tg \
  --protocol HTTP \
  --port 3000 \
  --vpc-id vpc-0123456789abcdef0 \
  --target-type ip \
  --health-check-path /health \
  --health-check-interval-seconds 30 \
  --healthy-threshold-count 2 \
  --unhealthy-threshold-count 3

ECSサービスの作成

aws ecs create-service \
  --cluster mycompany-prod \
  --service-name web-app-service \
  --task-definition web-app:1 \
  --desired-count 2 \
  --launch-type FARGATE \
  --network-configuration '{
    "awsvpcConfiguration": {
      "subnets": ["subnet-0123456789abcdef0", "subnet-0123456789abcdef1"],
      "securityGroups": ["sg-0123456789abcdef0"],
      "assignPublicIp": "DISABLED"
    }
  }' \
  --load-balancers '[
    {
      "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/web-app-tg/1234567890123456",
      "containerName": "web-app",
      "containerPort": 3000
    }
  ]' \
  --deployment-configuration '{
    "maximumPercent": 200,
    "minimumHealthyPercent": 100,
    "deploymentCircuitBreaker": {
      "enable": true,
      "rollback": true
    }
  }'

重要な設定ポイントを解説します。

  • desired-count: 2:最低2つのタスクを異なるAZに配置して可用性を確保
  • assignPublicIp: DISABLED:プライベートサブネットに配置し、ALB経由でのみアクセス可能にする
  • deploymentCircuitBreaker:デプロイ失敗時に自動でロールバック
  • minimumHealthyPercent: 100:デプロイ中もサービスが停止しないローリングアップデート

Auto Scalingの設定

トラフィックの変動に対応するため、ECSサービスにAuto Scalingを設定します。

ターゲット追跡スケーリングポリシー

# スケーラブルターゲットの登録
aws application-autoscaling register-scalable-target \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/mycompany-prod/web-app-service \
  --min-capacity 2 \
  --max-capacity 10

# CPU使用率に基づくスケーリングポリシー
aws application-autoscaling put-scaling-policy \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/mycompany-prod/web-app-service \
  --policy-name cpu-scaling \
  --policy-type TargetTrackingScaling \
  --target-tracking-scaling-policy-configuration '{
    "TargetValue": 70.0,
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "ECSServiceAverageCPUUtilization"
    },
    "ScaleInCooldown": 300,
    "ScaleOutCooldown": 60
  }'

この設定では、CPU使用率が70%を超えるとタスクが追加され、下回ると削減されます。スケールアウトは60秒、スケールインは300秒のクールダウンを設定して、頻繁なスケーリングを防いでいます。

デプロイ戦略とCI/CD連携

本番環境では、安全なデプロイ戦略が不可欠です。

ローリングアップデート

ECSのデフォルトのデプロイ方式です。新しいタスクを起動してから古いタスクを停止することで、ダウンタイムゼロのデプロイを実現します。

# 新しいイメージでタスク定義を更新してデプロイ
aws ecs update-service \
  --cluster mycompany-prod \
  --service web-app-service \
  --task-definition web-app:2 \
  --force-new-deployment

Blue/Greenデプロイ

より安全なデプロイには、AWS CodeDeployと連携したBlue/Greenデプロイを使用します。新しいバージョンに段階的にトラフィックを移行し、問題があれば即座にロールバックできます。

# Blue/Greenデプロイの設定は、サービス作成時にdeploymentControllerを指定
{
  "deploymentController": {
    "type": "CODE_DEPLOY"
  }
}

デプロイの自動化スクリプト

CI/CDパイプラインからECSにデプロイするスクリプトの例です。

#!/bin/bash
set -e

# 変数の設定
CLUSTER="mycompany-prod"
SERVICE="web-app-service"
FAMILY="web-app"
IMAGE_URI="123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/mycompany/web-app"
TAG=$(git rev-parse --short HEAD)

# 1. イメージのビルドとプッシュ
docker build -t ${IMAGE_URI}:${TAG} .
docker push ${IMAGE_URI}:${TAG}

# 2. 新しいタスク定義を登録
TASK_DEF=$(aws ecs describe-task-definition --task-definition ${FAMILY} --query taskDefinition)
NEW_TASK_DEF=$(echo $TASK_DEF | jq --arg IMAGE "${IMAGE_URI}:${TAG}" \
  '.containerDefinitions[0].image = $IMAGE | del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)')
NEW_REVISION=$(aws ecs register-task-definition --cli-input-json "$NEW_TASK_DEF" --query 'taskDefinition.revision' --output text)

# 3. サービスを更新
aws ecs update-service \
  --cluster ${CLUSTER} \
  --service ${SERVICE} \
  --task-definition ${FAMILY}:${NEW_REVISION}

# 4. デプロイ完了を待機
aws ecs wait services-stable --cluster ${CLUSTER} --services ${SERVICE}
echo "Deploy completed: ${FAMILY}:${NEW_REVISION}"

トラブルシューティングとモニタリング

ECS/Fargateの運用で遭遇しやすい問題と対処法を紹介します。

よくあるエラーと対処法

エラー 原因 対処法
CannotPullContainerError ECRからイメージを取得できない executionRoleのECR権限、VPCエンドポイントを確認
ResourceNotFoundException 指定したリソースが存在しない タスク定義のARN、サブネットIDを確認
Task stopped: Essential container exited コンテナがクラッシュ CloudWatch Logsでアプリケーションログを確認
Service is unable to place a task リソース不足 サブネットのIPアドレス枯渇、セキュリティグループを確認

CloudWatch Logsでのログ確認

# タスクのログを確認
aws logs get-log-events \
  --log-group-name /ecs/web-app \
  --log-stream-name "ecs/web-app/タスクID" \
  --limit 50

# 停止したタスクの理由を確認
aws ecs describe-tasks \
  --cluster mycompany-prod \
  --tasks タスクARN \
  --query 'tasks[0].{stoppedReason:stoppedReason,stopCode:stopCode}'

AWS Lambdaの活用事例と組み合わせれば、ECSタスクの異常検知をLambdaで処理し、Slackに通知するような仕組みも構築できます。

まとめ|ECS/Fargateで運用負荷を最小限にコンテナを本番運用する

AWS ECS/Fargateを使えば、サーバー管理の負担なくDockerコンテナを本番環境で運用できます。本記事のポイントを振り返りましょう。

  • Fargateを選択:サーバー管理不要で、アプリケーション開発に集中できる
  • ECRでイメージ管理:脆弱性スキャンを有効にし、Gitハッシュでタグ管理する
  • タスク定義の設計:シークレット管理、ヘルスチェック、ログ設定を適切に行う
  • サービスとALBの連携:複数AZに分散配置して可用性を確保する
  • Auto Scaling:CPU使用率に基づく自動スケーリングで負荷に対応する
  • 安全なデプロイ:ローリングアップデートとサーキットブレーカーで安全にデプロイする

コンテナ運用の基盤ができたら、RDSでのデータベース構築CloudFrontによるCDN配信と組み合わせて、本格的なWebアプリケーション基盤を構築していきましょう。インフラ全体をTerraformでコード管理することも忘れずに。

#AWS#ECS#Fargate
共有:
無料メルマガ

週1回、最新の技術記事をお届け

AI・クラウド・開発の最新記事を毎週月曜にメールでお届けします。登録は無料、いつでも解除できます。

プライバシーポリシーに基づき管理します

AI活用のヒントをお探しですか?お気軽にご相談ください。

まずは話だけ聞いてもらう