Exercises and Projects
1 - Hands-on exercises
Exercise 1: First cluster and task
Objective: Create an ECS cluster and run a Fargate task.
# Tâches :
# 1. Créer un cluster ECS
# 2. Créer une Task Definition pour nginx
# 3. Exécuter une task
# 4. Vérifier les logs
Solution
# 1. Créer le cluster
aws ecs create-cluster --cluster-name demo-cluster
# 2. Créer la task definition
cat > task-def.json << 'EOF'
{
"family": "nginx-demo",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"executionRoleArn": "arn:aws:iam::ACCOUNT_ID:role/ecsTaskExecutionRole",
"containerDefinitions": [
{
"name": "nginx",
"image": "nginx:latest",
"essential": true,
"portMappings": [{"containerPort": 80}],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/nginx-demo",
"awslogs-region": "eu-west-1",
"awslogs-stream-prefix": "nginx",
"awslogs-create-group": "true"
}
}
}
]
}
EOF
aws ecs register-task-definition --cli-input-json file://task-def.json
# 3. Exécuter la task
aws ecs run-task \
--cluster demo-cluster \
--task-definition nginx-demo:1 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}"
# 4. Voir les logs
aws logs tail /ecs/nginx-demo --follow
Exercise 2: Service with ALB
Objective: Deploy a service behind an ALB.
Solution (CloudFormation)
AWSTemplateFormatVersion: '2010-09-09'
Resources:
ALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Type: application
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
SecurityGroups:
- !Ref ALBSecurityGroup
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Port: 80
Protocol: HTTP
VpcId: !Ref VPC
TargetType: ip
HealthCheckPath: /
Listener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref ALB
Port: 80
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
ECSService:
Type: AWS::ECS::Service
DependsOn: Listener
Properties:
Cluster: !Ref ECSCluster
TaskDefinition: !Ref TaskDefinition
DesiredCount: 2
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
Subnets:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
SecurityGroups:
- !Ref ServiceSecurityGroup
LoadBalancers:
- TargetGroupArn: !Ref TargetGroup
ContainerName: app
ContainerPort: 80
Exercise 3: Auto Scaling
Objective: Configure CPU-based auto scaling.
Solution
ScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MinCapacity: 2
MaxCapacity: 10
ResourceId: !Sub service/${ECSCluster}/${ECSService.Name}
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
CPUScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: CPUScaling
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref ScalableTarget
TargetTrackingScalingPolicyConfiguration:
TargetValue: 70
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageCPUUtilization
ScaleInCooldown: 300
ScaleOutCooldown: 60
Exercise 4: Blue/Green Deployment
Objective: Configure a Blue/Green deployment with CodeDeploy.
Solution
# Service avec CodeDeploy
ECSService:
Type: AWS::ECS::Service
Properties:
DeploymentController:
Type: CODE_DEPLOY
LoadBalancers:
- TargetGroupArn: !Ref BlueTargetGroup
ContainerName: app
ContainerPort: 8080
# CodeDeploy
CodeDeployApplication:
Type: AWS::CodeDeploy::Application
Properties:
ComputePlatform: ECS
DeploymentGroup:
Type: AWS::CodeDeploy::DeploymentGroup
Properties:
ApplicationName: !Ref CodeDeployApplication
DeploymentConfigName: CodeDeployDefault.ECSLinear10PercentEvery1Minutes
ServiceRoleArn: !GetAtt CodeDeployRole.Arn
DeploymentStyle:
DeploymentOption: WITH_TRAFFIC_CONTROL
DeploymentType: BLUE_GREEN
ECSServices:
- ClusterName: !Ref ECSCluster
ServiceName: !GetAtt ECSService.Name
LoadBalancerInfo:
TargetGroupPairInfoList:
- TargetGroups:
- Name: !GetAtt BlueTargetGroup.TargetGroupName
- Name: !GetAtt GreenTargetGroup.TargetGroupName
ProdTrafficRoute:
ListenerArns:
- !Ref Listener
2 - Complete project: 3-tier Web Application
Architecture
Project structure
project/
├── infrastructure/
│ ├── vpc.yaml
│ ├── ecs-cluster.yaml
│ ├── alb.yaml
│ ├── services.yaml
│ └── database.yaml
├── services/
│ ├── web/
│ │ ├── Dockerfile
│ │ └── task-definition.json
│ └── api/
│ ├── Dockerfile
│ └── task-definition.json
└── deploy/
├── buildspec.yml
└── pipeline.yaml
API Task Definition
{
"family": "api-service",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::ACCOUNT:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::ACCOUNT:role/apiTaskRole",
"containerDefinitions": [
{
"name": "api",
"image": "ACCOUNT.dkr.ecr.eu-west-1.amazonaws.com/api:latest",
"essential": true,
"portMappings": [
{"containerPort": 8080, "protocol": "tcp"}
],
"environment": [
{"name": "NODE_ENV", "value": "production"},
{"name": "PORT", "value": "8080"}
],
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:eu-west-1:ACCOUNT:secret:db-url"
},
{
"name": "REDIS_URL",
"valueFrom": "arn:aws:secretsmanager:eu-west-1:ACCOUNT:secret:redis-url"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/api-service",
"awslogs-region": "eu-west-1",
"awslogs-stream-prefix": "api"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 60
}
}
]
}
CI/CD Pipeline
# buildspec.yml
version: 0.2
phases:
pre_build:
commands:
- aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REPO
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
build:
commands:
- docker build -t $ECR_REPO:$COMMIT_HASH .
- docker push $ECR_REPO:$COMMIT_HASH
post_build:
commands:
- printf '{"ImageURI":"%s"}' $ECR_REPO:$COMMIT_HASH > imageDetail.json
- cat appspec.yml
- cat taskdef.json
artifacts:
files:
- imageDetail.json
- appspec.yml
- taskdef.json
3 - Review quiz
-
What is the difference between ECS EC2 and Fargate?
-
What is a Task Definition?
-
How many tasks minimum for high availability?
-
Which network mode is required for Fargate?
-
How do you save on Fargate?
Answers
-
EC2: you manage the infrastructure. Fargate: serverless, AWS manages everything.
-
A blueprint that describes how the containers should run (image, CPU, memory, ports, etc.).
-
At least 2 tasks in different AZs.
-
awsvpc - each task gets an ENI with its own IP.
-
Use Fargate Spot (up to 70% savings), ARM64 (40% cheaper), right-sizing.
4 - AWS certification
Relevant exams
| Certification | Level |
|---|---|
| AWS Solutions Architect Associate | Foundational |
| AWS Developer Associate | Foundational |
| AWS DevOps Professional | Advanced |
Resources
Course summary
Congratulations! You have completed the AWS ECS and Fargate course.
You now have a firm grasp of:
- The ECS concepts (clusters, tasks, services)
- Task Definitions and their configuration
- Networking and load balancing
- Fargate for serverless containers
- Service auto scaling
- Monitoring with CloudWatch
- Production best practices
Next steps
- Practice with real projects
- Explore EKS for Kubernetes
- Study AWS App Runner for more simplicity
- Take the AWS certifications