MFormations
Modern Backend Engineering

Chapitre 15

Chapitre 15 — Cloud Déploiement

Chapitre 15 — Cloud Déploiement

Cours — Cloud Déploiement

1. AWS Fondamentaux

VPC (Virtual Private Cloud)

Réseau virtuel isolé dans AWS.

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  tags = { Name = "prod-vpc" }
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
  map_public_ip_on_launch = true
}

resource "aws_subnet" "private" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.2.0/24"
}

IAM (Identity and Access Management)

Gestion des identités et permissions.

resource "aws_iam_role" "ecs_task" {
  name = "ecs-task-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = { Service = "ecs-tasks.amazonaws.com" }
    }]
  })
}

resource "aws_iam_policy" "s3_access" {
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = ["s3:GetObject", "s3:PutObject"]
      Effect = "Allow"
      Resource = "arn:aws:s3:::my-bucket/*"
    }]
  })
}

2. AWS ECS (Elastic Container Service)

Fargate vs EC2

CritèreFargateEC2
Gestion des serveursAWSVous
PricingPar tâchePar instance
IsolationVMConteneur
GPUNonOui
Cas d'usageMicroservices, batchML, workloads lourds

Task Definition (Fargate)

{
  "family": "api-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123:role/ecs-execution",
  "containerDefinitions": [{
    "name": "api",
    "image": "registry.example.com/api:latest",
    "portMappings": [{ "containerPort": 3000 }],
    "environment": [
      { "name": "NODE_ENV", "value": "production" },
      { "name": "DB_HOST", "value": "database.cluster-xxx.eu-west-3.rds.amazonaws.com" }
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group": "/ecs/api",
        "awslogs-region": "eu-west-3",
        "awslogs-stream-prefix": "api"
      }
    },
    "healthCheck": {
      "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
      "interval": 30,
      "timeout": 5,
      "retries": 3
    }
  }]
}

Service ECS

resource "aws_ecs_service" "api" {
  name            = "api-service"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.api.arn
  desired_count   = 3
  launch_type     = "FARGATE"

  network_configuration {
    subnets         = aws_subnet.private[*].id
    security_groups = [aws_security_group.ecs.id]
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.api.arn
    container_name   = "api"
    container_port   = 3000
  }

  deployment_circuit_breaker {
    enable   = true
    rollback = true
  }
}

3. AWS RDS (Relational Database Service)

Configuration PostgreSQL

resource "aws_db_instance" "postgres" {
  identifier = "app-db"
  engine     = "postgres"
  engine_version = "16.3"
  instance_class = "db.t3.medium"

  db_name  = "app"
  username = "admin"
  password = random_password.db.result

  allocated_storage     = 100
  storage_type          = "gp3"
  storage_encrypted     = true
  backup_retention_period = 30
  backup_window         = "03:00-04:00"
  maintenance_window    = "sun:04:00-sun:05:00"

  vpc_security_group_ids = [aws_security_group.rds.id]
  db_subnet_group_name   = aws_db_subnet_group.main.name

  deletion_protection = true
  skip_final_snapshot = false

  enabled_cloudwatch_logs_exports = ["postgresql"]

  performance_insights_enabled = true
  performance_insights_retention_period = 7

  tags = { Name = "app-db" }
}

Aurora Serverless v2

resource "aws_rds_cluster" "aurora" {
  engine           = "aurora-postgresql"
  engine_version   = "16.3"
  database_name    = "app"
  master_username  = "admin"
  master_password  = random_password.db.result
  serverlessv2_scaling_configuration {
    min_capacity = 0.5
    max_capacity = 16
  }
}

4. AWS Lambda (Serverless)

Lambda function (Node.js)

exports.handler = async (event) => {
  const { userId } = JSON.parse(event.body);

  const user = await db.users.findById(userId);

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
      'Cache-Control': 'no-cache',
    },
    body: JSON.stringify(user),
  };
};

Terraform

resource "aws_lambda_function" "get_user" {
  filename         = "function.zip"
  function_name    = "get-user"
  role             = aws_iam_role.lambda.arn
  handler          = "index.handler"
  runtime          = "nodejs22.x"
  memory_size      = 256
  timeout          = 10

  environment {
    variables = {
      DB_HOST = aws_db_instance.postgres.address
    }
  }
}

resource "aws_lambda_function_url" "public" {
  function_name      = aws_lambda_function.get_user.function_name
  authorization_type = "AWS_IAM"
  cors {
    allow_origins = ["*"]
    allow_methods = ["GET", "POST"]
  }
}

5. AWS SQS, SNS, S3

SQS (Simple Queue Service)

resource "aws_sqs_queue" "order_queue" {
  name                      = "order-queue"
  delay_seconds             = 0
  max_message_size          = 262144
  message_retention_seconds = 345600 // 4 jours
  receive_wait_time_seconds = 10     // long polling
  visibility_timeout_seconds = 30

  redrive_policy = jsonencode({
    deadLetterTargetArn = aws_sqs_queue.order_dlq.arn
    maxReceiveCount     = 3
  })

  tags = { Name = "order-queue" }
}

resource "aws_sqs_queue" "order_dlq" {
  name = "order-dlq"
}

S3 (Simple Storage Service)

resource "aws_s3_bucket" "assets" {
  bucket = "myapp-assets-prod"
}

resource "aws_s3_bucket_versioning" "assets" {
  bucket = aws_s3_bucket.assets.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "assets" {
  bucket = aws_s3_bucket.assets.id
  rule {
    id     = "expire-old-versions"
    status = "Enabled"
    noncurrent_version_expiration {
      noncurrent_days = 30
    }
  }
}

6. GCP et Azure (Comparatif)

ServiceAWSGCPAzure
ContainersECS/EKSGKEAKS
ServerlessLambdaCloud FunctionsAzure Functions
DatabaseRDS/AuroraCloud SQLAzure SQL
QueueSQSPub/SubService Bus
StorageS3Cloud StorageBlob Storage
CDNCloudFrontCloud CDNAzure CDN
DNSRoute53Cloud DNSAzure DNS
MonitoringCloudWatchCloud MonitoringAzure Monitor

7. Infrastructure as Code

Terraform Best Practices

# Structurer en modules
modules/
├── network/
│   ├── main.tf
│   ├── variables.tf
│   └── outputs.tf
├── database/
├── compute/
└── monitoring/

# Use remote state
terraform {
  backend "s3" {
    bucket         = "myapp-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "eu-west-3"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

# Use workspaces
terraform workspace new prod
terraform workspace select prod

Pulumi (TypeScript)

import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const cluster = new aws.ecs.Cluster("app-cluster");

const lb = new awsx.lb.ApplicationLoadBalancer("app-lb");

const service = new awsx.ecs.FargateService("app-service", {
  cluster,
  desiredCount: 3,
  taskDefinitionArgs: {
    containers: {
      api: {
        image: "registry.example.com/api:latest",
        memory: 512,
        portMappings: [{ containerPort: 3000 }],
      },
    },
  },
});

8. Serverless et Edge Computing

Lambda + API Gateway

# serverless.yml
service: my-api
frameworkVersion: '4'
provider:
  name: aws
  runtime: nodejs22.x
  region: eu-west-3

functions:
  createUser:
    handler: src/handler.createUser
    events:
      - httpApi:
          method: POST
          path: /users
  getUser:
    handler: src/handler.getUser
    events:
      - httpApi:
          method: GET
          path: /users/{id}

Edge Computing (CloudFront Functions / Lambda@Edge)

// CloudFront Function (lightweight)
function handler(event) {
  var request = event.request;
  request.headers['x-edge'] = { value: 'cloudfront' };
  return request;
}

9. Auto-scaling et Load Balancing

Application Auto Scaling

resource "aws_appautoscaling_target" "api" {
  max_capacity       = 20
  min_capacity       = 2
  resource_id        = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.api.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}

resource "aws_appautoscaling_policy" "cpu" {
  name               = "cpu-scaling"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.api.resource_id
  scalable_dimension = aws_appautoscaling_target.api.scalable_dimension
  service_namespace  = aws_appautoscaling_target.api.service_namespace

  target_tracking_scaling_policy_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ECSServiceAverageCPUUtilization"
    }
    target_value = 70
  }
}

Load Balancer

resource "aws_lb" "main" {
  name               = "app-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets           = aws_subnet.public[*].id
}

resource "aws_lb_target_group" "api" {
  name        = "api-tg"
  port        = 3000
  protocol    = "HTTP"
  target_type = "ip"
  vpc_id      = aws_vpc.main.id

  health_check {
    path                = "/health"
    healthy_threshold   = 2
    unhealthy_threshold = 5
    timeout             = 5
    interval            = 30
  }
}

10. Cost Optimization

Stratégies

  1. Rightsizing : adapter la taille des instances
  2. Reserved Instances : engagement 1-3 ans (-40%)
  3. Spot Instances : jusqu'à -90% (tolérant aux interruptions)
  4. Auto-scaling : éteindre les ressources inutilisées
  5. S3 Lifecycle : déplacer vers des classes moins chères
  6. Serverless : payer seulement à l'usage
  7. RDS : Aurora Serverless, arrêt la nuit (dev)

AWS Budgets

resource "aws_budgets_budget" "monthly" {
  budget_type  = "COST"
  limit_amount = "5000"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator = "GREATER_THAN"
    threshold          = 80
    threshold_type     = "PERCENTAGE"
    notification_type  = "ACTUAL"
    subscriber_email_addresses = ["team@example.com"]
  }
}