Discover AWS Fargate, the serverless compute engine that eliminates EC2 instance management entirely. Learn when to use Fargate vs ECS with EC2, understand the cost trade-offs, and simplify your container orchestration.
Building Highly Available AWS Infrastructure: Fargate Simplicity - Part 3
Welcome to the final part of our series! In Part 1, we built highly available infrastructure with ALB, Auto Scaling, and EC2. In Part 2, we containerized our applications with ECS but discovered the complexity of two-dimensional scaling.
Now, let's talk about AWS Fargate—the technology that makes you ask: "Why was I managing EC2 instances at all?"
🚀 What is AWS Fargate?
AWS Fargate is a serverless compute engine for containers. The key word is "serverless"—you don't provision, configure, or manage any servers.
The Traditional Model (ECS with EC2)
You manage:
├── EC2 instances (choosing types, patching, scaling)
├── ECS cluster capacity
├── Capacity providers
├── Task placement strategies
└── Container tasks
AWS manages:
└── The underlying hardware
The Fargate Model
You manage:
└── Container tasks (that's it!)
AWS manages:
├── The underlying hardware
├── The operating system
├── The container runtime
├── Capacity planning
└── Infrastructure scaling
In other words: You define what you want to run (containers), AWS figures out where and how to run it.
🎯 How Fargate Works: The High-Level View
With Fargate, your architecture simplifies dramatically:
Application Load Balancer
↓
ECS Service (Fargate)
↓
ECS Tasks (Containers)
↓
??? (You don't care—AWS handles it)
When you launch a Fargate task:
- You define: Task definition (CPU, memory, container image)
- AWS provisions: The exact compute capacity needed for that task
- Your container runs: In an isolated environment
- You're billed: Per-second for the vCPU and memory you requested
- Task ends: Resources are released immediately
No instances to manage. No capacity to worry about. No bin-packing optimization.
🔄 From ECS with EC2 to Fargate: The Migration
Let's take our Part 2 setup and migrate it to Fargate. Spoiler: It's easier than you think.
What Stays the Same
- Task definitions (mostly—small networking change)
- ECS services
- Application Load Balancer integration
- Service auto scaling policies
- CloudWatch monitoring
What Changes
1. Task Definition Network Mode
// ECS with EC2 - Multiple network modes supported
{
"networkMode": "bridge" // or "host" or "awsvpc"
}
// Fargate - Only awsvpc mode
{
"networkMode": "awsvpc", // Required for Fargate
"requiresCompatibilities": ["FARGATE"]
}
2. No More EC2 Instance Management
# DELETE these (no longer needed):
- Launch templates
- Auto Scaling Groups for instances
- Capacity providers
- ECS-optimized AMIs
- Instance profiles
- SSH key pairs for instance access
3. Launch Type Changes
# Before: ECS with EC2
aws ecs create-service \
--launch-type EC2 \
--cluster production
# After: Fargate
aws ecs create-service \
--launch-type FARGATE \
--cluster production \
--network-configuration "awsvpcConfiguration={...}" # Required for Fargate
The Complete Migration
# 1. Update task definition for Fargate
{
"family": "web-app",
"networkMode": "awsvpc", # Changed from bridge
"requiresCompatibilities": ["FARGATE"], # Added
"cpu": "256", # Now a task-level string, not integer
"memory": "512", # Now a task-level string, not integer
"containerDefinitions": [{
"name": "web-app-container",
"image": "123456789.dkr.ecr.us-east-1.amazonaws.com/web-app:latest",
"portMappings": [{
"containerPort": 8080,
"protocol": "tcp"
}]
}]
}
# 2. Create Fargate service
aws ecs create-service \
--cluster production-cluster \
--service-name web-app-fargate \
--task-definition web-app:2 \
--desired-count 4 \
--launch-type FARGATE \
--platform-version LATEST \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-1a,subnet-1b,subnet-1c],
securityGroups=[sg-12345],
assignPublicIp=DISABLED
}" \
--load-balancers "targetGroupArn=<tg-arn>,containerName=web-app-container,containerPort=8080"
# 3. That's it! No step 3.
# (Seriously, you're done with infrastructure management)
📈 Single-Dimensional Scaling: Back to Simplicity
Remember the two-dimensional scaling nightmare from Part 2? With Fargate, we're back to one dimension: tasks.
Fargate Auto Scaling
# Configure service auto scaling (same as before!)
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/production-cluster/web-app-fargate \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 100 # Can scale much higher without capacity concerns
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/production-cluster/web-app-fargate \
--scalable-dimension ecs:service:DesiredCount \
--policy-name cpu-tracking \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 75.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
},
"ScaleInCooldown": 300,
"ScaleOutCooldown": 60
}'
The Scaling Flow (So Much Simpler!)
09:00 AM - Normal Traffic
└── 4 Fargate tasks running
09:15 AM - Traffic Spike
├── Task CPU hits 80%
├── Auto Scaling triggers
└── ⚡ Service desired count: 4 → 8
09:16 AM - Tasks Launch
├── AWS provisions capacity for 4 new tasks
├── Tasks start immediately (no waiting for instances!)
└── New tasks begin receiving traffic
09:17 AM - Fully Scaled
└── 8 Fargate tasks running (all healthy)
No capacity provider. No instance scaling. No pending tasks.
Just works. ✨
Why It's Faster
ECS with EC2:
- Task scaling triggers (5 seconds)
- Wait for instance launch (60-90 seconds)
- Instance joins cluster (10 seconds)
- Task placement (5 seconds)
- Task startup (10-30 seconds) Total: ~100-140 seconds
Fargate:
- Task scaling triggers (5 seconds)
- AWS provisions capacity (invisible to you)
- Task startup (10-30 seconds) Total: ~15-35 seconds
💰 The Cost Question: EC2 vs Fargate
Let's be real: Fargate costs more per compute hour than EC2. But is it actually more expensive overall?
Direct Compute Cost Comparison
Scenario: Running a web app continuously (24/7)
ECS with EC2:
- 2x t3.medium instances ($0.0416/hour each)
- 4 tasks (2 per instance)
- Monthly cost: 2 × $0.0416 × 730 = $60.74/month
Fargate:
- 4 tasks (0.25 vCPU, 0.5 GB each)
- Fargate pricing: $0.04048/vCPU/hour + $0.004445/GB/hour
- Per task: (0.25 × $0.04048) + (0.5 × $0.004445) = $0.0123/hour
- Monthly cost: 4 × $0.0123 × 730 = $35.95/month
Wait... Fargate is CHEAPER? 🤔
But wait, that's not the full picture. EC2 instances have overhead:
- ECS agent uses ~200-300 MB memory
- OS overhead
- You can't perfectly pack tasks
More realistic EC2 comparison:
- 2x t3.medium can really only fit 3 tasks comfortably
- Need 4 tasks → must run 4 instances (2 per AZ for HA)
- Monthly cost: 4 × $0.0416 × 730 = $121.48/month
Now Fargate looks better!
When EC2 is Cheaper
1. Large, Predictable Workloads with Reserved Instances
Reserved Instance (1-year, no upfront):
- t3.medium: ~$0.025/hour (40% savings)
- Running 4 instances continuously: $73/month
Fargate (same workload):
- $144/month (no reserved pricing)
EC2 wins: ~50% cheaper with commitment
Real-World Example: Acme Web Application
Here's an actual cost comparison from a production workload:
Requirements:
- .NET web application with moderate, steady traffic
- 2 tasks needed for high availability (multi-AZ)
- Each task: 1 vCPU, 1.5 GB memory
- Running 24/7 with minimal variance
Option A: ECS with EC2 (with Reserved Instances)
Strategy: 1 task per t3.small instance
- 2× t3.small Reserved (1-year, no upfront): ~$0.025/hour each
- Monthly: 2 × $0.025 × 730 hours = $36.50/month
- Total yearly commitment: ~$438
Benefits:
✅ Already had other Reserved Instances → pooled savings
✅ Predictable monthly costs
✅ Can use excess capacity for other workloads
✅ Dedicated resources per task (no "noisy neighbors")
Option B: Fargate
Task pricing: 1 vCPU = $0.04048/hour, 1.5 GB = $0.006668/hour
- Per task: $0.04048 + (1.5 × $0.004445) = $0.0471/hour
- 2 tasks running continuously: 2 × $0.0471 × 730 = $68.76/month
- Total yearly: ~$825
Benefits:
✅ Zero infrastructure management
✅ No commitment required
✅ Easy to scale if traffic patterns change
✅ Faster deployment iterations
The Math:
- EC2 saves $32.26/month or $387/year (47% cheaper)
- Fargate costs $22/month extra for zero ops overhead
The Decision:
For this specific workload, EC2 made sense because:
- Traffic is steady and predictable (not variable)
- Team already managed EC2 infrastructure for other services
- Already had Reserved Instance commitment
- Wanted dedicated resources for consistent performance
- Cost optimization was a priority
If traffic had been variable or the team lacked ops experience, Fargate's simplicity would have outweighed the $22/month difference.
Key Insight: The "right" choice depends on your specific context. For $22/month (~$264/year), Fargate eliminates all infrastructure management. For high-scale workloads or existing RI commitments, EC2's savings multiply significantly.
2. High-Density Task Packing
r5.xlarge instance:
- 4 vCPU, 32 GB RAM
- Can run 32 small tasks (0.25 vCPU, 0.5 GB each)
- Instance cost: ~$0.252/hour = $184/month
Same tasks on Fargate:
- 32 tasks × $0.0123/hour × 730 = $287/month
EC2 wins: ~35% cheaper with good bin-packing
When Fargate is Cheaper
1. Variable Workloads
Workload that scales:
- 2 tasks at night (8 hours)
- 10 tasks during business hours (12 hours)
- 4 tasks evening (4 hours)
ECS with EC2:
- Must maintain minimum capacity for peak (10 tasks)
- Need 4 instances running 24/7
- Cost: $121/month
Fargate:
- Pay only for actual task hours
- (2 × 8 + 10 × 12 + 4 × 4) × 30 days = 4560 task-hours/month
- Cost: 4560 × $0.0123 = $56/month
Fargate wins: ~54% cheaper
2. Batch Jobs and Scheduled Tasks
Daily ETL job:
- Runs for 2 hours/day
- Needs 10 tasks during run
ECS with EC2:
- Keep instances running 24/7 or deal with startup time
- Cost: ~$121/month (for 24/7) or complex scheduling
Fargate:
- Run only when needed
- 10 tasks × 2 hours × 30 days = 600 task-hours
- Cost: 600 × $0.0123 = $7.38/month
Fargate wins: ~94% cheaper
The Hidden Costs of EC2
Don't forget:
Operational Overhead:
- Time spent managing instances, AMIs, capacity
- Monitoring instance health
- Patching and updates
- On-call for instance-related issues
Opportunity Cost:
- Your engineers could be building features instead
- Faster time to market with less infrastructure complexity
For many teams, Fargate's simplicity justifies the marginal price difference.
🎯 Fargate vs EC2: Decision Framework
Choose Fargate When:
✅ You have variable or unpredictable traffic ✅ You're running microservices with different scaling patterns ✅ Your team is small or lacks dedicated ops resources ✅ You want to scale to zero during off-hours ✅ Fast iteration and deployment speed matter more than marginal cost savings ✅ You're running batch jobs or scheduled tasks ✅ You want to focus on application code, not infrastructure
Choose ECS with EC2 When:
✅ You already have Reserved Instances or Savings Plans ← Often the deciding factor! ✅ You have steady, predictable workloads (24/7 operation with minimal variance) ✅ Cost optimization is a priority and you can commit to 1-3 year reservations ✅ You have dedicated ops team comfortable managing EC2 infrastructure ✅ You need specialized instance types (GPUs, high memory, ARM/Graviton) ✅ You're running large-scale, high-density workloads with efficient bin-packing ✅ You need instance-level access or deep OS customization ✅ You want dedicated resources per task (no multi-tenancy) ✅ You're already heavily invested in EC2 infrastructure and tooling
Use Both! Hybrid Approach
Many organizations use a mix:
Production Cluster:
├── Fargate: Web APIs (variable traffic)
├── Fargate: Background workers (scale to zero at night)
├── EC2: Core services (24/7, reserved instances)
└── EC2: ML training (GPU instances)
🔧 Fargate Platform Versions
Fargate has evolved over time. Always use LATEST unless you have specific needs:
--platform-version LATEST # Recommended
Platform versions include:
- 1.4.0 (Latest as of 2025): Supports EBS volumes, Amazon Linux 2023
- 1.3.0: Task-level ephemeral storage configuration
- 1.2.0: Improved network performance
⚡ Fargate Spot: Even Cheaper
Want Fargate simplicity at EC2 Spot prices? Enter Fargate Spot:
aws ecs create-service \
--capacity-provider-strategy "capacityProvider=FARGATE_SPOT,weight=4" \
"capacityProvider=FARGATE,weight=1,base=2"
Pricing: Up to 70% cheaper than regular Fargate Trade-off: Tasks can be interrupted with 2-minute warning
Perfect for:
- Fault-tolerant workloads
- Batch processing
- Background jobs
- Non-critical tasks
Not for:
- Real-time APIs
- Stateful applications without proper handling
- Critical production services
📊 Monitoring Fargate
Monitoring is actually simpler with Fargate:
Key Metrics
# Service-level metrics (same as before)
- CPUUtilization
- MemoryUtilization
- RunningTaskCount
- DesiredTaskCount
# No instance-level metrics to worry about!
# No cluster capacity metrics!
CloudWatch Container Insights
Enable detailed container metrics:
aws ecs create-cluster \
--cluster-name production \
--settings "name=containerInsights,value=enabled"
Provides:
- CPU and memory at task and container level
- Network metrics
- Storage I/O (if using EFS or EBS)
- Automatic dashboards
Logging
// Task definition logging
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/web-app",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "fargate"
}
}
With Fargate, all logs go to CloudWatch Logs—no SSH access to check instance logs because there are no instances!
🚨 Common Fargate Pitfalls
Pitfall 1: ENI Limits
Each Fargate task gets its own ENI (Elastic Network Interface). VPCs have ENI limits.
Solution:
- Plan subnet CIDR blocks appropriately
- Request ENI limit increases if needed
- Use larger subnets (/24 or larger)
Pitfall 2: Task Startup Time
Fargate tasks can take 30-60 seconds to start (pulling image, initializing).
Solutions:
- Keep container images small
- Use ECR image caching
- Set appropriate health check grace periods
- Pre-scale before known traffic spikes
Pitfall 3: Storage Costs
Fargate includes 20 GB ephemeral storage. Need more? You pay.
"ephemeralStorage": {
"sizeInGiB": 100 // You'll pay for the extra 80 GB
}
Solution: Only request what you need, or use EFS for shared storage.
Pitfall 4: Cold Start for Infrequent Tasks
First task launch in a while can be slower than subsequent launches.
Solution: Keep minimum task count > 0 for latency-sensitive services.
🎓 Real-World Fargate Example
Complete production-ready Fargate deployment:
# 1. Create cluster with Container Insights
aws ecs create-cluster \
--cluster-name production \
--settings "name=containerInsights,value=enabled"
# 2. Register task definition
aws ecs register-task-definition \
--family web-app \
--network-mode awsvpc \
--requires-compatibilities FARGATE \
--cpu 256 \
--memory 512 \
--execution-role-arn arn:aws:iam::123456789:role/ecsTaskExecutionRole \
--task-role-arn arn:aws:iam::123456789:role/ecsTaskRole \
--container-definitions '[{
"name": "web-app",
"image": "123456789.dkr.ecr.us-east-1.amazonaws.com/web-app:latest",
"portMappings": [{"containerPort": 8080}],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/web-app",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "fargate"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3
}
}]'
# 3. Create service with auto scaling
aws ecs create-service \
--cluster production \
--service-name web-app \
--task-definition web-app:1 \
--desired-count 4 \
--launch-type FARGATE \
--platform-version LATEST \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-1a,subnet-1b,subnet-1c],
securityGroups=[sg-12345],
assignPublicIp=DISABLED
}" \
--load-balancers "targetGroupArn=<tg-arn>,containerName=web-app,containerPort=8080" \
--health-check-grace-period-seconds 60
# 4. Configure auto scaling
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/production/web-app \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 50
# Target tracking on CPU
aws application-autoscaling put-scaling-policy \
--policy-name cpu-tracking \
--service-namespace ecs \
--resource-id service/production/web-app \
--scalable-dimension ecs:service:DesiredCount \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 75.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
}
}'
# Target tracking on request count
aws application-autoscaling put-scaling-policy \
--policy-name request-count-tracking \
--service-namespace ecs \
--resource-id service/production/web-app \
--scalable-dimension ecs:service:DesiredCount \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 1000.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ALBRequestCountPerTarget",
"ResourceLabel": "app/my-alb/xxx/targetgroup/my-targets/yyy"
}
}'
📚 Quick Decision Matrix
| Factor | EC2 | Fargate |
|---|---|---|
| Operational Complexity | High | Low |
| Cost (Variable Workloads) | Higher | Lower |
| Cost (Steady + Reserved) | Lower | Higher |
| Startup Time | Slower | Faster |
| Scaling Complexity | 2D (tasks + instances) | 1D (tasks only) |
| Customization | High | Limited |
| Best For | Large-scale, predictable | Variable, microservices |
🎉 What Did We Miss?
Throughout this series, we covered:
- ✅ ALB fundamentals and health checks
- ✅ Auto Scaling with EC2
- ✅ ECS with containers
- ✅ Two-dimensional scaling challenges
- ✅ Fargate serverless simplicity
- ✅ Cost comparisons
- ✅ When to use each approach
What we didn't cover (but you might explore):
- Service mesh (AWS App Mesh) for advanced traffic management
- Blue/green deployments with CodeDeploy
- ECS Anywhere (run ECS on your own infrastructure)
- Multi-region deployments for global applications
- Cost optimization with Savings Plans and Spot
- Security deep dive (IAM roles, secrets management)
📖 A Brief History of Fargate (For Those Still Here!)
As promised, for those dedicated readers who made it to the end...
2017: AWS announces Fargate at re:Invent
- Initial reaction: "Serverless containers? Is this real?"
- Pricing: Expensive, limited adoption
- Platform: 1.0.0, basic functionality
2018-2019: Gradual improvements
- Platform 1.2.0: Better networking
- Platform 1.3.0: Ephemeral storage config
- Price reductions (~50% over time)
- Adoption grows, especially for microservices
2020: Game changers
- Fargate Spot launched (70% cheaper!)
- EFS support (persistent storage)
- ECS Exec (ability to "SSH" into containers)
2021-2022: Enterprise-ready
- Platform 1.4.0: Windows containers support
- Graviton2 support (better price/performance)
- 20 GB default ephemeral storage (was 10 GB)
- CloudWatch Container Insights GA
2023-2024: Mainstream adoption
- Most new ECS deployments use Fargate
- Major enterprises migrate from EC2 to Fargate
- Considered "the default" for containers on AWS
2025 and beyond: What's next?
- Better cold start times
- More compute options
- Integration with emerging AWS services
- Continued price/performance improvements
The lesson: Technology adoption takes time. Fargate went from "interesting but expensive" to "default choice for containers" in ~6 years.
🚀 Coming Up in Part 4: Graceful Failure Handling
You now have bulletproof infrastructure that scales perfectly. But what happens when your database goes down?
Even with perfect scaling, dependencies can fail. In Part 4, we'll explore:
- Handling database failures gracefully
- Application-level error handling and maintenance pages
- Route 53 health checks and DNS failover
- CloudFront functions for edge-level error interception
- Comparing different strategies (pros and cons of each)
- Real-world implementations and testing
Because high availability isn't just about scaling—it's about handling failures gracefully when they happen.
🏁 Series Overview
Part 1: Built the foundation—ALB, ASG, EC2, health checks, high availability
Part 2: Added containers with ECS—discovered the complexity of two-dimensional scaling
Part 3: Simplified everything with Fargate—serverless containers, single-dimensional scaling
Part 4: Graceful failure handling—turning ugly 500 errors into elegant user experiences
The throughline: AWS gives you choices. Pick the right tool for your use case:
- Need control and cost optimization? → ECS with EC2
- Want simplicity and operational ease? → Fargate
- Have mixed requirements? → Use both!
There's no single "best" answer. The best architecture is the one that fits your team's skills, your application's needs, and your organization's constraints.
🚀 What Now?
Next steps:
- Try Fargate with a small service
- Monitor and measure cost and performance
- Iterate based on learnings
- Scale what works, abandon what doesn't
Remember: All three approaches (EC2, ECS+EC2, Fargate) are valid. Don't let perfect be the enemy of good. Ship something, learn, improve.
Building reliable, scalable infrastructure is a journey. Start simple, add complexity only when needed, and always monitor your decisions.
Ready to learn about graceful failure handling? Continue to Part 4!
Comments