Claude Code × AWS ECS/Fargate Complete Guide | Automate Container Deployments
Automate AWS ECS/Fargate deployments with Claude Code. From task definitions and service configuration to Blue/Green deployments and CDK infrastructure — based on Masa's real-world experience.
“I want to run containers on AWS, but ECS configuration is way too complex” — this is the wall many engineers hit first. Task definitions, services, clusters, load balancers, auto scaling… there are so many settings it’s hard to know where to start.
I’ve been building serverless container environments with ECS/Fargate at work, and since I started using Claude Code to generate everything from task definitions to CDK code just by describing my architecture, deployments have become dramatically easier. This article walks through the practical steps.
ECS/Fargate Basics in 3 Minutes
Cluster: The "box" where ECS containers run
Task Definition: Container specification (image, CPU, memory, env vars)
Service: Defines how many tasks to run (includes auto scaling)
Fargate: Serverless container execution engine — no server management needed
Unlike EC2, Fargate requires no server provisioning or patch management. You can focus entirely on container configuration.
Step 1: Auto-Generate a Task Definition
claude -p "
Generate an ECS task definition in JSON with the following requirements:
- App: Node.js API (port 3000)
- CPU: 512 (0.5 vCPU)
- Memory: 1024 MB
- Environment variables: DATABASE_URL (retrieved from Secrets Manager), NODE_ENV=production
- Logging: CloudWatch Logs (log group /ecs/myapp)
- Health check: /health endpoint, 30-second interval
- Container image: 123456789.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest
- Execution role: ecsTaskExecutionRole
- Task role: myapp-task-role (access to DynamoDB and S3)
"
Generated task definition:
{
"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: Build ECS/Fargate Infrastructure with CDK
Beyond just a task definition, we’ll generate the cluster, service, and ALB all at once using CDK.
claude -p "
Implement the following ECS/Fargate environment in CDK TypeScript in lib/ecs-stack.ts:
- VPC: Import an existing VPC (retrieve vpcId from environment variable)
- ECS Cluster: Fargate only
- Task Definition: Same spec as generated above
- ALB: HTTPS (retrieve ACM certificate ARN from environment variable), HTTP redirects to HTTPS with 301
- Service: Auto scaling with minimum 2, maximum 10 tasks
- Scale out at 70% CPU utilization
- Target tracking scaling
- Blue/Green deploy support (CodeDeploy integration)
- Display service health on a CloudWatch dashboard
"
// 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);
// Import existing VPC
const vpc = ec2.Vpc.fromLookup(this, "Vpc", {
vpcId: process.env.VPC_ID!,
});
// ECS Cluster
const cluster = new ecs.Cluster(this, "Cluster", {
vpc,
clusterName: "myapp-cluster",
containerInsights: true, // Enable CloudWatch Container Insights
});
// ACM Certificate
const certificate = acm.Certificate.fromCertificateArn(
this, "Certificate",
process.env.CERTIFICATE_ARN!
);
// Task Definition
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 Service (concise using patterns)
const service = new ecsp.ApplicationLoadBalancedFargateService(
this, "Service", {
cluster,
taskDefinition: taskDef,
desiredCount: 2,
certificate,
redirectHTTP: true,
publicLoadBalancer: true,
}
);
// Auto Scaling configuration
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: Build a CI/CD Pipeline with GitHub Actions
claude -p "
Create the following CI/CD pipeline with GitHub Actions:
1. Trigger on push to main branch
2. Build Docker image and push to ECR
3. Update the image tag in the ECS task definition to the new SHA
4. Deploy the new task definition to the ECS service
5. Notify Slack on successful deployment
Environment: ap-northeast-1, ECR repository name: 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: Configure Blue/Green Deployment
claude -p "
Generate CDK code and an AppSpec file to set up Blue/Green deployment (CodeDeploy) for an ECS service.
Rollback condition: automatically roll back if a CloudWatch alarm fires within 5 minutes of deployment.
"
# appspec.yaml (for 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"
Top 5 Pitfalls
1. Forgetting startPeriod in the health check
Fargate containers run health checks immediately on startup, but if your application is slow to start, it instantly becomes UNHEALTHY. Set startPeriod: 60 (seconds) to give your app time to initialize.
2. Confusing the task role and execution role
executionRole (ecsTaskExecutionRole): Permissions needed to start the container
→ Pull image from ECR, write to CloudWatch Logs
taskRole (myapp-task-role): Permissions used by the application
→ Access to DynamoDB, S3, SQS, etc.
It’s very easy to add permissions to the wrong role.
3. Security group configuration in awsvpc network mode
Fargate requires the awsvpc network mode. If you forget to restrict the container’s security group to allow traffic only from the ALB, the container will be directly exposed to the internet.
4. Execution role required to fetch from Secrets Manager
To retrieve Secrets Manager values via secrets, the executionRole must have secretsmanager:GetSecretValue permission. Missing this permission is a very common reason containers fail to start.
5. The desired_count: 0 problem during deployment
A service with a minimum of 0 in auto scaling will have all containers shut down overnight, causing slow restarts in the morning. Set the minimum to at least 2 in production.
Summary
| Task | Claude Code’s Contribution |
|---|---|
| Task definition generation | Complete JSON from requirements alone |
| CDK implementation | Cluster, service, ALB, auto scaling generated together |
| CI/CD setup | GitHub Actions workflow generation |
| Blue/Green deployment | Auto-generates AppSpec and CodeDeploy config |
| Troubleshooting | Identifies root cause and fixes from error logs |
ECS has many configuration items, but by telling Claude Code “I want this kind of setup,” you get a complete, best-practice configuration. Starting with CDK is the easiest and most recommended approach.
Related Articles
- Claude Code × AWS Lambda Complete Guide
- Claude Code × AWS IAM Complete Guide
- Claude Code × AWS CloudFormation/CDK Complete Guide
References
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
Free PDF: Claude Code Cheatsheet in 5 Minutes
Just enter your email and we'll send you the single-page A4 cheatsheet right away.
We handle your data with care and never send spam.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
Claude Code × Amazon Bedrock Complete Guide | Running Claude in Production on AWS
Complete guide to using Amazon Bedrock with Claude Code. From IAM authentication, streaming, Lambda integration, RAG implementation, to cost optimization — based on Masa's real production experience.
Claude Code × AWS CodePipeline/CodeBuild Complete Guide | Automate CI/CD Pipeline Build
Automatically build CI/CD with AWS CodePipeline & CodeBuild using Claude Code. Real code examples for pipeline design, buildspec.yml generation, test automation, and CDK infrastructure.
Claude Code × AWS CloudWatch Complete Guide | Log Analysis, Alarm Setup & Dashboard Automation
Boost AWS CloudWatch efficiency with Claude Code. Real-world code for log pattern analysis, automatic alarm configuration, metrics dashboards, and incident investigation.