Use Cases

Claude Code × AWS ECS/Fargate 完整指南 | 自动化容器部署

使用Claude Code自动化AWS ECS/Fargate部署。从任务定义、服务配置到Blue/Green部署和CDK基础设施构建——基于Masa的实际工作经验。

“我想在AWS上运行容器,但ECS配置太复杂了”——这是许多工程师最初遇到的障碍。任务定义、服务、集群、负载均衡器、自动扩展……配置项太多,根本不知道从哪里开始。

我在工作中使用ECS/Fargate构建无服务器容器环境,自从开始用Claude Code描述架构配置,就能一键生成从任务定义到CDK代码的全套内容,部署工作变得轻松了许多。本文将详细讲解其实践步骤。


3分钟理解ECS/Fargate基础

集群(Cluster):   ECS容器运行的"容器箱"
任务定义(Task Definition):容器配置规格书(镜像、CPU、内存、环境变量)
服务(Service):   设置启动多少个任务(含自动扩展)
Fargate:          无需服务器管理的容器执行引擎

与EC2不同,Fargate无需进行服务器配置和补丁维护,您可以专注于容器配置本身。


第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
      }
    }
  ]
}

第2步:用CDK构建ECS/Fargate环境

不仅是任务定义,还要用CDK一次性生成集群、服务和ALB。

claude -p "
在lib/ecs-stack.ts中用CDK TypeScript实现以下ECS/Fargate环境:

- VPC:导入现有VPC(从环境变量获取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
    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),
    });

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

第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 }}"}

第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"

五大常见陷阱

1. 忘记健康检查的 startPeriod

Fargate容器启动后立即进行健康检查,但如果应用启动较慢,则会立即变为UNHEALTHY状态。请设置 startPeriod: 60(秒)为应用的启动留出时间。

2. 混淆任务角色和执行角色

executionRole(ecsTaskExecutionRole):启动容器所需的权限
  → 从ECR拉取镜像,向CloudWatch Logs写入日志

taskRole(myapp-task-role):应用使用的权限
  → 访问DynamoDB、S3、SQS等

很容易把权限添加到错误的角色上。

3. awsvpc网络模式下的安全组配置

Fargate必须使用 awsvpc 网络模式。如果忘记将容器的安全组限制为仅允许来自ALB的流量,容器就会直接暴露在公网上。

4. 从Secrets Manager获取值需要执行角色权限

通过 secrets 获取Secrets Manager的值时,executionRole 需要 secretsmanager: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 个经过实战检验的提示词模板,现在就能复制粘贴到 Claude Code 中使用。

免费

免费 PDF:5 分钟看懂 Claude Code 速查表

只需留下邮箱,我们就会立即把这份 A4 一页速查表 PDF 发送给你。

我们会严格保护你的个人信息,绝不发送垃圾邮件。

Masa

本文作者

Masa

深度使用 Claude Code 的工程师。运营 claudecode-lab.com——一个涵盖 10 种语言、超过 2,000 页内容的科技媒体。