Introduction
Container orchestration and Infrastructure as Code (IaC) are fundamental to modern cloud applications. AWS provides Amazon ECS and Fargate for running containerized workloads, CloudFormation for declarative infrastructure management, and SAM (Serverless Application Model) for simplified serverless deployments.
This guide explores ECS task definitions, Fargate serverless containers, CloudFormation stack management, and SAM template syntax. We'll cover container deployment patterns, blue/green deployments, and production best practices.
AWS Developer Certification Series
📚 View Complete AWS Developer Certification Guide - Master all 7 parts with our comprehensive learning path.
This is Part V (Current Article) of our comprehensive 7-part AWS developer guide:
- Part I: IAM EC2 & Auto Scaling
- Part II: RDS Aurora & DynamoDB
- Part III: SQS SNS & Kinesis
- Part IV: Lambda API Gateway
- Part V: ECS Fargate & IaC (Current Article)
- Part VI: Cognito KMS Security
- Part VII: CodePipeline & Monitoring
← Part IV: Lambda API Gateway | Part VI: Cognito KMS Security →
Amazon ECS (Elastic Container Service)
ECS Architecture
ECS orchestrates Docker containers across EC2 instances or serverless Fargate, with built-in load balancing and auto-scaling.
Key Concepts:
- Cluster: Logical grouping of tasks or services
- Task Definition: Blueprint for containers (image, CPU, memory, ports)
- Task: Running instance of task definition
- Service: Maintains desired number of tasks, integrates with load balancer
- ECS Agent: Runs on EC2 instances to communicate with ECS control plane
EC2 vs Fargate Launch Types
| Feature | EC2 Launch Type | Fargate Launch Type |
|---|---|---|
| Infrastructure | Manage EC2 instances | Serverless (no servers) |
| Pricing | EC2 instance cost | Per vCPU/GB-hour |
| Scaling | Manual + Auto Scaling | Automatic |
| Use Case | Cost optimization, control | Simplicity, pay-per-use |
| Storage | EBS, EFS | Ephemeral (20GB) + EFS |
ECS Task Definition
Example task definition (JSON):
{
"family": "web-app",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "nginx",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest",
"portMappings": [
{
"containerPort": 80,
"protocol": "tcp"
}
],
"environment": [
{
"name": "ENVIRONMENT",
"value": "production"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/web-app",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost/ || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3
}
}
],
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsExecutionRole"
}
Register task definition:
aws ecs register-task-definition --cli-input-json file://task-definition.json
Running ECS Tasks
Run task (one-off execution):
aws ecs run-task \
--cluster production \
--task-definition web-app:5 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-12345],securityGroups=[sg-67890],assignPublicIp=ENABLED}"
Create service (maintains desired count):
aws ecs create-service \
--cluster production \
--service-name web-service \
--task-definition web-app:5 \
--desired-count 3 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-12345],securityGroups=[sg-67890]}" \
--load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:...,containerName=nginx,containerPort=80"
ECS Service Auto Scaling
Target tracking scaling:
# Register scalable target
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/production/web-service \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 10
# Create scaling policy (CPU-based)
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/production/web-service \
--scalable-dimension ecs:service:DesiredCount \
--policy-name cpu-scaling \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
}
}'
Amazon ECR (Elastic Container Registry)
ECR Basics
ECR stores Docker images with built-in scanning, encryption, and lifecycle policies.
Push image to ECR:
# Authenticate Docker to ECR
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
# Tag image
docker tag my-app:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
# Push to ECR
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
Lifecycle policy (auto-delete old images):
{
"rules": [
{
"rulePriority": 1,
"description": "Keep last 10 images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": {
"type": "expire"
}
}
]
}
AWS CloudFormation
CloudFormation Architecture
CloudFormation provisions infrastructure using declarative templates (JSON/YAML).
Template Components:
- Resources (required): AWS resources to create
- Parameters: Input values for customization
- Mappings: Static key-value pairs
- Outputs: Values to export or display
- Conditions: Control resource creation
CloudFormation Template Example
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Simple web application stack'
Parameters:
InstanceType:
Type: String
Default: t3.micro
AllowedValues: [t3.micro, t3.small, t3.medium]
Environment:
Type: String
Default: dev
AllowedValues: [dev, staging, prod]
Mappings:
RegionMap:
us-east-1:
AMI: ami-0c55b159cbfafe1f0
us-west-2:
AMI: ami-0d1cd67c26f5fca19
Conditions:
IsProduction: !Equals [!Ref Environment, prod]
Resources:
WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
WebServer:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceType
ImageId: !FindInMap [RegionMap, !Ref 'AWS::Region', AMI]
SecurityGroups:
- !Ref WebServerSecurityGroup
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "Hello from ${Environment}" > /var/www/html/index.html
Outputs:
WebsiteURL:
Description: URL of the website
Value: !Sub 'http://${WebServer.PublicDnsName}'
Export:
Name: !Sub '${AWS::StackName}-URL'
CloudFormation Stack Operations
Create stack:
aws cloudformation create-stack \
--stack-name my-web-app \
--template-body file://template.yaml \
--parameters ParameterKey=Environment,ParameterValue=prod \
--capabilities CAPABILITY_IAM
Update stack:
aws cloudformation update-stack \
--stack-name my-web-app \
--template-body file://template-v2.yaml \
--parameters ParameterKey=InstanceType,ParameterValue=t3.small
Delete stack:
aws cloudformation delete-stack --stack-name my-web-app
Describe stack events (troubleshooting):
aws cloudformation describe-stack-events --stack-name my-web-app
AWS SAM (Serverless Application Model)
SAM Overview
SAM simplifies serverless deployments with concise CloudFormation syntax for Lambda, API Gateway, and DynamoDB.
SAM Template Example:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Serverless API with Lambda and DynamoDB
Globals:
Function:
Runtime: nodejs18.x
Timeout: 30
Environment:
Variables:
TABLE_NAME: !Ref UsersTable
Resources:
# API Gateway
ApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: prod
Cors:
AllowOrigin: "'*'"
AllowHeaders: "'Content-Type,Authorization'"
# Lambda Function
GetUserFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./src
Handler: index.handler
Events:
GetUser:
Type: Api
Properties:
RestApiId: !Ref ApiGateway
Path: /users/{id}
Method: GET
Policies:
- DynamoDBReadPolicy:
TableName: !Ref UsersTable
# DynamoDB Table
UsersTable:
Type: AWS::Serverless::SimpleTable
Properties:
PrimaryKey:
Name: userId
Type: String
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
Outputs:
ApiUrl:
Description: API Gateway endpoint
Value: !Sub 'https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod'
SAM CLI Commands
Build and deploy:
# Initialize new SAM project
sam init --runtime nodejs18.x --name my-app
# Build application
sam build
# Deploy to AWS
sam deploy --guided
# Local testing
sam local start-api
sam local invoke GetUserFunction -e events/test.json
Package for deployment:
# Package and upload to S3
sam package \
--template-file template.yaml \
--output-template-file packaged.yaml \
--s3-bucket my-deployment-bucket
# Deploy packaged template
sam deploy \
--template-file packaged.yaml \
--stack-name my-serverless-app \
--capabilities CAPABILITY_IAM
Production Best Practices
ECS Best Practices
- Task Definitions: Use versioning, immutable task definitions
- Service Discovery: Use AWS Cloud Map for service-to-service communication
- Fargate vs EC2: Use Fargate for simplicity, EC2 for cost optimization (Reserved Instances)
- Secrets: Store in Secrets Manager or Parameter Store, reference in task definition
- Logging: Enable CloudWatch Logs with structured logging
- Health Checks: Configure ELB health checks and container health checks
CloudFormation Best Practices
- Modular Templates: Use nested stacks for reusability
- Parameters: Externalize environment-specific values
- Change Sets: Preview changes before applying (like Terraform plan)
- Stack Policies: Prevent accidental deletion of critical resources
- Cross-Stack References: Use Outputs and
!ImportValuefor dependencies - Rollback: Enable automatic rollback on failure
SAM Best Practices
- Local Testing: Use
sam localfor development before deploying - Environment Variables: Use Globals section for shared config
- Policies: Use SAM policy templates (DynamoDBReadPolicy, S3CrudPolicy)
- Canary Deployments: Use
AutoPublishAliaswith CodeDeploy for gradual rollouts - Layers: Share dependencies across functions
Monitoring and Troubleshooting
ECS Metrics (CloudWatch):
CPUUtilization- Task CPU usageMemoryUtilization- Task memory usageRunningTasksCount- Number of running tasks
CloudFormation Events:
CREATE_IN_PROGRESS→CREATE_COMPLETEUPDATE_IN_PROGRESS→UPDATE_COMPLETEROLLBACK_IN_PROGRESS(on failure)
Common Issues:
- ECS task fails to start: Check task role permissions, security groups, subnet routes
- CloudFormation rollback: Check stack events for resource creation failures
- SAM deployment fails: Verify S3 bucket permissions, IAM capabilities
Exam Tips
Key Concepts:
- ECS task placement strategies: Binpack (cost), Random, Spread (availability)
- Fargate: Serverless, no EC2 management, pay per vCPU/GB
- CloudFormation intrinsic functions:
!Ref,!GetAtt,!Sub,!Join - SAM Transform:
AWS::Serverless-2016-10-31enables SAM syntax - ECS Service: Maintains desired task count, integrates with ALB/NLB
Common Scenarios:
- "Need serverless containers" → Fargate
- "Cost-optimize containers" → ECS EC2 with Reserved Instances
- "Deploy Lambda + API Gateway" → SAM
- "Manage infrastructure as code" → CloudFormation
- "Rollback failed deployment" → CloudFormation automatic rollback
- "Blue/Green deployment for ECS" → CodeDeploy with ECS
Frequently Asked Questions
Q: What is the difference between ECS and Fargate?
ECS (Elastic Container Service) is the orchestration platform that manages container deployment. Fargate is a serverless compute engine for ECS that eliminates EC2 instance management. ECS can run on EC2 instances you manage or on Fargate. Use Fargate for simplicity, EC2 for cost optimization with Reserved Instances.
Q: How does AWS CloudFormation work?
CloudFormation is Infrastructure as Code that provisions AWS resources using JSON or YAML templates. You define desired resources, parameters, and dependencies. CloudFormation creates, updates, or deletes resources to match the template. It provides rollback on failure, change sets for previewing updates, and drift detection.
Q: When should I use SAM instead of CloudFormation?
SAM (Serverless Application Model) extends CloudFormation specifically for serverless applications with simplified syntax. Use SAM for Lambda, API Gateway, and DynamoDB projects. SAM includes local testing, built-in deployment commands, and policy templates. Use CloudFormation for complex infrastructure mixing serverless and traditional services.
Q: What are ECS task placement strategies?
Task placement strategies determine how ECS distributes tasks across EC2 instances. Binpack minimizes instances for cost efficiency by filling instances before adding new ones. Spread maximizes availability by distributing across availability zones or instances. Random distributes evenly without specific logic. Combine strategies for optimal placement.
Q: How do I manage secrets in ECS containers?
Store secrets in AWS Secrets Manager or Systems Manager Parameter Store, then reference them in task definitions using secretOptions or environment variables. ECS retrieves secrets at task startup and injects them securely. Never hardcode secrets in Docker images or task definitions. Enable encryption for sensitive data.
Q: What is CloudFormation drift detection?
Drift detection identifies when actual resource configurations differ from CloudFormation template definitions, typically from manual console changes. CloudFormation compares live resources against templates and reports differences. Use drift detection to maintain infrastructure consistency and prevent configuration drift from causing unexpected behavior.
Q: How does ECS service auto-scaling work?
ECS service auto-scaling uses Application Auto Scaling to adjust desired task count based on CloudWatch metrics like CPU or memory utilization. Target tracking policies automatically scale tasks to maintain metrics at target values. Step scaling provides granular control with multiple thresholds. Scheduled scaling handles predictable traffic patterns.
Conclusion
AWS container orchestration with ECS and Fargate, combined with Infrastructure as Code through CloudFormation and SAM, provides powerful tools for deploying and managing modern applications. ECS offers flexibility between EC2 and serverless Fargate, CloudFormation enables declarative infrastructure management, and SAM simplifies serverless deployments.
Choose ECS EC2 for cost optimization and control, Fargate for serverless simplicity, CloudFormation for complex infrastructure, and SAM for serverless applications. Understanding task definitions, stack management, and deployment patterns is essential for both production architectures and the AWS Certified Developer Associate exam.