Use Cases (更新: 2026/6/2)

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

用Claude Code部署ECS/Fargate:覆盖Docker、ECR、任务定义、日志、IAM与生产陷阱。

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

想把容器放到AWS上运行时,ECS/Fargate通常是很稳妥的选择。真正困难的不是写Dockerfile,而是把ECR、任务定义、IAM角色、Secrets Manager、负载均衡、CloudWatch Logs、健康检查和成本控制连成一个不会在生产环境出问题的整体。

这篇文章把Claude Code当作实现助手,而不是无人审查的自动驾驶。任务定义可以理解为“容器启动说明书”,Fargate是“无需管理服务器的容器运行环境”,execution role负责让ECS拉取镜像、读取secret和写日志,task role才是应用代码调用AWS API时使用的权限。

Masa第一次把小型Node.js API迁到Fargate时,失败点不是Docker,而是健康检查。应用启动约40秒,但ECS太早开始检查,导致新任务还没准备好就被替换。Claude Code可以很快生成文件,但你必须把启动时间、私有网络、日志、回滚和IAM边界讲清楚。

目标架构

Developer
  |
  | docker build / push
  v
Amazon ECR ----> Amazon ECS Service on AWS Fargate
                       |
                       | pulls secrets / writes logs
                       v
Secrets Manager     CloudWatch Logs
                       ^
                       |
Application Load Balancer -> /health -> Node.js container

示例使用ap-northeast-1、已有VPC和已有ALB target group。如果你想用IaC一起创建VPC和ALB,可以配合阅读内部的Claude Code × AWS CloudFormation/CDK指南。如果IAM边界还不清楚,建议先看Claude Code × AWS IAM指南

三个真实用例

用例为什么适合Fargate注意点
SaaS REST API可以在ALB后保持两台以上任务并滚动部署先设计DB连接数和健康检查
管理后台后端不需要维护EC2和AMI,小规模起步更轻desiredCount设为0会让首次请求变慢
API和批处理共用镜像同一镜像可用于service和run-tasktask role只给最小权限

如果工作负载短且事件驱动,Claude Code × AWS Lambda指南可能更简单。需要常驻HTTP、较长请求、Docker一致性或特殊运行时时,再选择Fargate。

1. 带健康检查的最小API

先保证应用在本地可运行。/health会被ECS和ALB同时使用,所以不要把它做得过重。数据库短暂变慢就返回500,会让ECS误判并替换健康容器。

{
  "scripts": {
    "start": "node src/server.js"
  },
  "dependencies": {
    "express": "^4.19.2"
  }
}
// src/server.js
const express = require("express");

const app = express();
const port = Number(process.env.PORT || 3000);

app.get("/health", (_req, res) => {
  res.status(200).json({
    ok: true,
    service: "myapp",
    time: new Date().toISOString(),
  });
});

app.get("/", (_req, res) => {
  res.json({ message: "Hello from ECS Fargate" });
});

app.listen(port, "0.0.0.0", () => {
  console.log(`myapp listening on ${port}`);
});
# Dockerfile
FROM node:22-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev

COPY src ./src
ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000

CMD ["node", "src/server.js"]

进入ECS之前,先确认curl -f http://localhost:3000/health成功。给Claude Code下指令时,要明确“ALB和ECS使用同一个健康路径”“应用监听0.0.0.0”“启动时间由startPeriod保护”。

2. 构建镜像并推送到ECR

下面的脚本会在需要时创建ECR仓库、登录、构建并推送带版本的镜像。不要只依赖latest,否则回滚和审计都会变难。

set -euo pipefail

export AWS_REGION="ap-northeast-1"
export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export ECR_REPOSITORY="myapp"
export IMAGE_TAG="$(git rev-parse --short HEAD 2>/dev/null || date +%Y%m%d%H%M%S)"
export IMAGE_URI="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY}:${IMAGE_TAG}"

aws ecr describe-repositories \
  --repository-names "${ECR_REPOSITORY}" \
  --region "${AWS_REGION}" >/dev/null 2>&1 || \
aws ecr create-repository \
  --repository-name "${ECR_REPOSITORY}" \
  --image-scanning-configuration scanOnPush=true \
  --region "${AWS_REGION}"

aws ecr get-login-password --region "${AWS_REGION}" | \
  docker login --username AWS --password-stdin \
  "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"

docker build -t "${IMAGE_URI}" .
docker push "${IMAGE_URI}"

echo "Pushed ${IMAGE_URI}"

AWS官方ECR流程也使用get-login-password。在CI中更推荐GitHub Actions OIDC和短期AWS凭证,不要长期把访问密钥放在仓库secret里。

3. 注册ECS任务定义

Fargate任务使用awsvpc网络模式。通过Secrets Manager注入值时,需要在execution role上授予secretsmanager:GetSecretValue;如果secret使用自管理KMS key,还需要kms:Decrypt。task role用于应用代码访问AWS资源,不负责拉镜像和写日志。

set -euo pipefail

export AWS_REGION="ap-northeast-1"
export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export IMAGE_URI="${IMAGE_URI:?Run the ECR push script first}"
export EXECUTION_ROLE_ARN="arn:aws:iam::${AWS_ACCOUNT_ID}:role/ecsTaskExecutionRole"
export TASK_ROLE_ARN="arn:aws:iam::${AWS_ACCOUNT_ID}:role/myapp-task-role"
export SECRET_ARN="arn:aws:secretsmanager:${AWS_REGION}:${AWS_ACCOUNT_ID}:secret:prod/myapp/DATABASE_URL"

aws logs create-log-group --log-group-name /ecs/myapp --region "${AWS_REGION}" 2>/dev/null || true
aws logs put-retention-policy --log-group-name /ecs/myapp --retention-in-days 30 --region "${AWS_REGION}"

cat > ecs-task-definition.json <<EOF
{
  "family": "myapp-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "${EXECUTION_ROLE_ARN}",
  "taskRoleArn": "${TASK_ROLE_ARN}",
  "runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  },
  "containerDefinitions": [
    {
      "name": "app",
      "image": "${IMAGE_URI}",
      "essential": true,
      "portMappings": [
        { "containerPort": 3000, "hostPort": 3000, "protocol": "tcp" }
      ],
      "environment": [
        { "name": "NODE_ENV", "value": "production" },
        { "name": "PORT", "value": "3000" }
      ],
      "secrets": [
        { "name": "DATABASE_URL", "valueFrom": "${SECRET_ARN}" }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/myapp",
          "awslogs-region": "${AWS_REGION}",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "wget -qO- http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      }
    }
  ]
}
EOF

aws ecs register-task-definition \
  --cli-input-json file://ecs-task-definition.json \
  --region "${AWS_REGION}"

startPeriod很不起眼,但排障成本很高。它能避免ECS在应用还没启动完成时就判定容器失败。

4. 创建Fargate服务

下面的命令使用已有private subnet、任务security group和ALB target group。任务security group只应允许来自ALB security group的3000端口流量。

set -euo pipefail

export AWS_REGION="ap-northeast-1"
export CLUSTER_NAME="myapp-cluster"
export SERVICE_NAME="myapp-service"
export TASK_FAMILY="myapp-task"
export SUBNET_1="subnet-xxxxxxxx"
export SUBNET_2="subnet-yyyyyyyy"
export TASK_SECURITY_GROUP="sg-xxxxxxxx"
export TARGET_GROUP_ARN="arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/myapp/abc123"

aws ecs create-cluster \
  --cluster-name "${CLUSTER_NAME}" \
  --region "${AWS_REGION}" >/dev/null

aws ecs create-service \
  --cluster "${CLUSTER_NAME}" \
  --service-name "${SERVICE_NAME}" \
  --task-definition "${TASK_FAMILY}" \
  --desired-count 2 \
  --launch-type FARGATE \
  --platform-version LATEST \
  --health-check-grace-period-seconds 90 \
  --network-configuration "awsvpcConfiguration={subnets=[${SUBNET_1},${SUBNET_2}],securityGroups=[${TASK_SECURITY_GROUP}],assignPublicIp=DISABLED}" \
  --load-balancers "targetGroupArn=${TARGET_GROUP_ARN},containerName=app,containerPort=3000" \
  --region "${AWS_REGION}"

aws ecs wait services-stable \
  --cluster "${CLUSTER_NAME}" \
  --services "${SERVICE_NAME}" \
  --region "${AWS_REGION}"

如果private subnet使用assignPublicIp=DISABLED,任务仍然需要访问ECR、CloudWatch Logs和Secrets Manager。可以使用NAT Gateway或VPC Endpoint。NAT很方便,但在小型测试环境中常常是主要成本。

5. 查看CloudWatch Logs和ECS事件

ECS排障通常要同时看service事件、停止任务原因和应用日志。把这三类信息一起交给Claude Code,诊断会明显更准。

export AWS_REGION="ap-northeast-1"
export CLUSTER_NAME="myapp-cluster"
export SERVICE_NAME="myapp-service"

aws ecs describe-services \
  --cluster "${CLUSTER_NAME}" \
  --services "${SERVICE_NAME}" \
  --query "services[0].events[0:5].[createdAt,message]" \
  --output table \
  --region "${AWS_REGION}"

aws ecs list-tasks \
  --cluster "${CLUSTER_NAME}" \
  --service-name "${SERVICE_NAME}" \
  --desired-status STOPPED \
  --region "${AWS_REGION}"

aws logs tail /ecs/myapp \
  --follow \
  --since 10m \
  --region "${AWS_REGION}"

常见失败包括:ECR拉取被阻止、secret权限不足、ALB无法访问任务security group、应用只监听localhost而不是0.0.0.0

Claude Code实现请求模板

请为Node.js API构建AWS ECS/Fargate部署实现。

前提:
- Region: ap-northeast-1
- ECR repository: myapp
- Container port: 3000
- Health endpoint: /health
- ECS launch type: FARGATE
- Network mode: awsvpc
- Desired count: 2
- Task CPU/memory: 512 / 1024
- Secret: 从Secrets Manager注入DATABASE_URL
- Logs: CloudWatch Logs /ecs/myapp, retention 30 days

交付物:
1. 生产用Dockerfile
2. 推送到ECR的bash脚本
3. 注册ECS task definition的bash脚本
4. 创建Fargate service的bash脚本
5. 查看CloudWatch Logs的bash脚本
6. 说明execution role和task role的区别

限制:
- 不要写伪代码。填入变量后必须能用AWS CLI执行。
- 不要硬编码secret值。
- 不要把task直接暴露在public subnet。
- 最后列出需要核对的AWS官方文档点。

AWS官方文档核对点

具体陷阱

第一,混淆execution role和task role。ECR、日志、secret读取属于execution role;DynamoDB、S3、SQS等应用访问属于task role。

第二,secret所在区域不一致。ECS任务、Secrets Manager secret和KMS key需要对齐。多区域系统要把secret ARN做成环境变量。

第三,费用估算不完整。Fargate按用量计费,但ALB、NAT Gateway、CloudWatch Logs和ECR存储也会收费。测试环境要设置日志保留、停掉不用的service,并检查NAT使用。

第四,健康检查过于严格。/health应保持轻量,深度依赖检查放到/ready或smoke test。

第五,镜像架构不匹配。在Apple Silicon上构建ARM64镜像,但任务定义写X86_64时会启动失败。使用docker buildx build --platform linux/amd64,或调整runtimePlatform

CTA和下一步

个人练习可以把这些脚本复制到一个小型API里,并用免费Claude Code速查表改进提示词。团队如果需要把ECS、IAM、CI/CD、监控和回滚一起设计,可以从Claude Code培训与咨询开始。需要可复用提示词和审查材料时,可以看ClaudeCodeLab产品

总结

ECS/Fargate不是“上传Docker镜像就结束”。它同时涉及IAM、网络、secret、日志、健康检查和成本。Claude Code最有价值的用法,是先给出清晰的运行规则,再让它生成可执行文件。

实际试用这个流程后,最大的改善来自提示词,而不是Dockerfile。明确要求Claude Code区分execution role和task role、输出CloudWatch日志命令、设置health check grace period后,同类失败明显减少。第一次运行仍然暴露了secret权限缺失,但把ECS事件和日志交回Claude Code后,它一次性整理出了IAM修正和重新部署步骤。

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

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。