Skip to main content

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

  1. What is the difference between ECS EC2 and Fargate?

  2. What is a Task Definition?

  3. How many tasks minimum for high availability?

  4. Which network mode is required for Fargate?

  5. How do you save on Fargate?

Answers
  1. EC2: you manage the infrastructure. Fargate: serverless, AWS manages everything.

  2. A blueprint that describes how the containers should run (image, CPU, memory, ports, etc.).

  3. At least 2 tasks in different AZs.

  4. awsvpc - each task gets an ENI with its own IP.

  5. Use Fargate Spot (up to 70% savings), ARM64 (40% cheaper), right-sizing.


4 - AWS certification

Relevant exams

CertificationLevel
AWS Solutions Architect AssociateFoundational
AWS Developer AssociateFoundational
AWS DevOps ProfessionalAdvanced

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

← Back to the table of contents