Claude Code × AWS ECS/Fargate完整指南|自动化安全容器部署
用Claude Code部署ECS/Fargate:覆盖Docker、ECR、任务定义、日志、IAM与生产陷阱。
想把容器放到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-task | task 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官方文档核对点
- AWS Fargate指南:确认Fargate约束和平台行为。
- 任务定义参数:确认
awsvpc、CPU/内存和health check字段。 - 任务执行IAM角色:确认ECR pull、日志和Secrets Manager所需权限。
- ECS日志发送到CloudWatch:确认
awslogs驱动配置。 - AWS Fargate价格:价格会随Region、vCPU、内存、额外ephemeral storage和运行时间变化。
- 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修正和重新部署步骤。
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
从Obsidian到CLAUDE.md的Claude Code流程:不再反复解释上下文
把 Obsidian 工作笔记整理成 CLAUDE.md 运行说明,让 Claude Code 每次都带着正确上下文开始。
Claude Code 收入 CTA 路由:从文章分流到 PDF、Gumroad 与咨询
用 Claude Code 按读者意图把文章流量分到免费 PDF、Gumroad 教材或咨询入口。
Claude Code 团队交接规则: 把审查证据、权限、回滚和收入路径一起交付
面向团队的 Claude Code 交接格式: 证据、权限、回滚、免费 PDF、Gumroad 与咨询路径都要可审查。