Use Cases

Claude Code × AWS ECS/Fargate 完全ガイド|コンテナデプロイを自動化する

AWS ECS/FargateへのデプロイをClaude Codeで自動化。タスク定義・サービス設定・Blue/Greenデプロイ・CDKでのインフラ構築まで、Masaの実務経験をもとに解説。

「コンテナをAWSで動かしたいけど、ECSの設定が複雑すぎる」——これは多くのエンジニアが最初にぶつかる壁です。タスク定義・サービス・クラスター・ロードバランサー・オートスケーリング……設定項目が多すぎて、どこから手をつければいいかわからない。

私は業務でECS/Fargateを使ったサーバーレスコンテナ環境を構築していますが、Claude Code に構成を伝えるだけでタスク定義からCDKコードまで一式生成できるようになってから、デプロイ作業が格段に楽になりました。この記事では、その実践手順を解説します。


ECS/Fargate の基礎を3分で整理

クラスター: ECSコンテナが動く「箱」
タスク定義: コンテナの設定仕様書 (イメージ・CPU・メモリ・環境変数)
サービス:   タスクを何台起動するかの設定 (オートスケーリング含む)
Fargate:    サーバー管理不要のコンテナ実行エンジン

EC2と違い、Fargateはサーバーのプロビジョニング・パッチ適用が不要。コンテナの設定に集中できます。


Step 1: タスク定義を自動生成

claude -p "
以下の条件で ECS タスク定義を JSON で生成して。

- アプリ: Node.js API (ポート3000)
- CPU: 512 (0.5 vCPU)
- メモリ: 1024 MB
- 環境変数: DATABASE_URL (Secrets Manager から取得), NODE_ENV=production
- ログ: CloudWatch Logs (ロググループ /ecs/myapp)
- ヘルスチェック: /health エンドポイント、30秒間隔
- コンテナイメージ: 123456789.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest
- 実行ロール: ecsTaskExecutionRole
- タスクロール: myapp-task-role (DynamoDB・S3へのアクセス権)
"

生成されるタスク定義:

{
  "family": "myapp-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789:role/myapp-task-role",
  "containerDefinitions": [
    {
      "name": "myapp",
      "image": "123456789.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest",
      "portMappings": [{ "containerPort": 3000, "protocol": "tcp" }],
      "environment": [{ "name": "NODE_ENV", "value": "production" }],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789:secret:prod/database-url"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/myapp",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      }
    }
  ]
}

Step 2: CDKでECS/Fargate環境を構築

タスク定義だけでなく、クラスター・サービス・ALBまで一括でCDK化します。

claude -p "
lib/ecs-stack.ts に以下の ECS/Fargate 環境を CDK TypeScript で実装して。

- VPC: 既存のVPCをimport (vpcId を環境変数から取得)
- ECSクラスター: Fargate のみ
- タスク定義: 上で生成したものと同仕様
- ALB: HTTPS (ACM証明書 ARN を環境変数から取得)、HTTPは301リダイレクト
- サービス: 最小2台、最大10台のオートスケーリング
  - CPU使用率70%でスケールアウト
  - ターゲット追跡スケーリング
- Blue/Greenデプロイ対応 (CodeDeploy連携)
- サービスの稼働状態を CloudWatch ダッシュボードに表示
"
// lib/ecs-stack.ts
import * as cdk from "aws-cdk-lib";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as ecs from "aws-cdk-lib/aws-ecs";
import * as ecsp from "aws-cdk-lib/aws-ecs-patterns";
import * as acm from "aws-cdk-lib/aws-certificatemanager";

export class EcsStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // 既存VPCをimport
    const vpc = ec2.Vpc.fromLookup(this, "Vpc", {
      vpcId: process.env.VPC_ID!,
    });

    // ECSクラスター
    const cluster = new ecs.Cluster(this, "Cluster", {
      vpc,
      clusterName: "myapp-cluster",
      containerInsights: true,  // CloudWatch Container Insights有効
    });

    // ACM証明書
    const certificate = acm.Certificate.fromCertificateArn(
      this, "Certificate",
      process.env.CERTIFICATE_ARN!
    );

    // タスク定義
    const taskDef = new ecs.FargateTaskDefinition(this, "TaskDef", {
      cpu: 512,
      memoryLimitMiB: 1024,
    });

    const container = taskDef.addContainer("app", {
      image: ecs.ContainerImage.fromEcrRepository(
        ecr.Repository.fromRepositoryName(this, "Repo", "myapp")
      ),
      environment: { NODE_ENV: "production" },
      logging: ecs.LogDrivers.awsLogs({ streamPrefix: "ecs" }),
      healthCheck: {
        command: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        interval: cdk.Duration.seconds(30),
        timeout: cdk.Duration.seconds(5),
        retries: 3,
        startPeriod: cdk.Duration.seconds(60),
      },
    });
    container.addPortMappings({ containerPort: 3000 });

    // ALB + Fargate サービス (パターンを使って簡潔に)
    const service = new ecsp.ApplicationLoadBalancedFargateService(
      this, "Service", {
        cluster,
        taskDefinition: taskDef,
        desiredCount: 2,
        certificate,
        redirectHTTP: true,
        publicLoadBalancer: true,
      }
    );

    // オートスケーリング設定
    const scaling = service.service.autoScaleTaskCount({
      minCapacity: 2,
      maxCapacity: 10,
    });
    scaling.scaleOnCpuUtilization("CpuScaling", {
      targetUtilizationPercent: 70,
      scaleInCooldown: cdk.Duration.seconds(60),
      scaleOutCooldown: cdk.Duration.seconds(60),
    });

    // Output
    new cdk.CfnOutput(this, "LoadBalancerDns", {
      value: service.loadBalancer.loadBalancerDnsName,
    });
  }
}

Step 3: GitHub ActionsでCI/CDパイプラインを構築

claude -p "
GitHub Actions で以下のCI/CDパイプラインを作成して:

1. main ブランチへの push をトリガー
2. Dockerイメージをビルドして ECR にプッシュ
3. ECS タスク定義の image タグを新しいSHAに更新
4. ECS サービスに新しいタスク定義をデプロイ
5. デプロイ完了をSlackに通知

環境: ap-northeast-1、ECR リポジトリ名: myapp
"
name: Deploy to ECS

on:
  push:
    branches: [main]

env:
  AWS_REGION: ap-northeast-1
  ECR_REPOSITORY: myapp
  ECS_CLUSTER: myapp-cluster
  ECS_SERVICE: myapp-service
  CONTAINER_NAME: app

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build, tag, and push image to ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

      - name: Download task definition
        run: |
          aws ecs describe-task-definition --task-definition myapp-task \
            --query taskDefinition > task-definition.json

      - name: Update ECS task definition with new image
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: ${{ env.CONTAINER_NAME }}
          image: ${{ steps.build-image.outputs.image }}

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true

      - name: Notify Slack on success
        if: success()
        uses: slackapi/slack-github-action@v1
        with:
          webhook: ${{ secrets.SLACK_WEBHOOK }}
          payload: |
            {"text": "✅ Deployed to ECS: ${{ github.sha }}"}

Step 4: Blue/Greenデプロイの設定

claude -p "
ECS サービスで Blue/Green デプロイ (CodeDeploy) を設定するための
CDK コードと AppSpec ファイルを生成して。
ロールバック条件: デプロイ後5分以内に CloudWatch アラームが発火したら自動ロールバック
"
# appspec.yaml (CodeDeploy用)
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: app
          ContainerPort: 3000
        PlatformVersion: LATEST
Hooks:
  - BeforeAllowTraffic: "arn:aws:lambda:ap-northeast-1:123456789:function:health-check"
  - AfterAllowTraffic: "arn:aws:lambda:ap-northeast-1:123456789:function:smoke-test"

落とし穴5選

1. ヘルスチェックの startPeriod を忘れる

Fargateコンテナは起動直後にヘルスチェックが走りますが、アプリの起動が遅いと即UNHEALTHYになります。startPeriod: 60 (秒) を設定してアプリの起動時間を確保しましょう。

2. タスクロールと実行ロールを混同する

executionRole (ecsTaskExecutionRole): コンテナ起動に必要な権限
  → ECR からのイメージ pull、CloudWatch Logs への書き込み

taskRole (myapp-task-role): アプリが使う権限
  → DynamoDB、S3、SQS などへのアクセス

どちらのロールに何を追加するか、よく間違えます。

3. awsvpc ネットワークモードでのセキュリティグループ設定

Fargateは必ず awsvpc ネットワークモードが必要です。コンテナのセキュリティグループをALBからのみに制限するのを忘れると、コンテナが直接外部に公開されます。

4. Secrets Manager の取得に実行ロールが必要

secrets で Secrets Manager の値を取得するには executionRolesecretsmanager:GetSecretValue 権限が必要です。抜け漏れでコンテナが起動しないことがよくあります。

5. デプロイ時の desired_count: 0 問題

オートスケーリングで最小値が0のサービスは、深夜に全コンテナが落ちて朝の起動が遅くなります。最小値は本番で最低2台に設定しましょう。


まとめ

タスクClaude Code の貢献
タスク定義生成要件を伝えるだけでJSON完成
CDK実装クラスター・サービス・ALB・オートスケーリング一括生成
CI/CD設定GitHub Actions ワークフロー生成
Blue/GreenデプロイAppSpec・CodeDeploy設定を自動生成
トラブル解決エラーログから原因と修正方法を提示

ECSは設定項目が多いですが、Claude Code に「こういう構成が欲しい」と伝えるだけで、ベストプラクティスに沿った設定が一式揃います。まずCDKから試すのが一番楽でおすすめです。

関連記事

参考資料

#claude-code #aws #ecs #fargate #container #devops

Claude Codeをもっと活用しませんか?

実務で使えるプロンプトテンプレート50選。コピペですぐ使えます。

無料プレゼント

無料PDF: Claude Code 5分でわかるチートシート

メールアドレスを登録するだけで、A4 1枚のチートシートPDFを今すぐお送りします。

個人情報は厳重に管理し、スパムは送りません。

Masa

この記事を書いた人

Masa

現役DX室長|Claude Code でゼロから多言語AI技術メディア運営中。実務直結の自動化、AI開発相談・研修受付中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。