Skip to main content

Automatisation d’Infrastructure as Code avec SAM

Objectif de cette partie

Recréer exactement la même application, mais cette fois avec du code ! SAM va déployer automatiquement tous les composants. Vous comprendrez pourquoi l'IaC est indispensable en production.

Installation des outils

Installation SAM CLI

# macOS (avec Homebrew)
brew install aws-sam-cli

# Windows (avec Chocolatey)
choco install aws-sam-cli

# Linux
wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip
unzip aws-sam-cli-linux-x86_64.zip -d sam-installation
sudo ./sam-installation/install

# Vérification
sam --version

Configuration AWS CLI

aws configure

AWS Access Key ID: VOTRE_ACCESS_KEY
AWS Secret Access Key: VOTRE_SECRET_KEY
Default region name: us-east-1
Default output format: json

Structure du projet SAM

Créez la structure de dossiers suivante :

tasks-api-sam/
├── template.yaml              # Template SAM principal
├── samconfig.toml             # Configuration de déploiement
├── src/
│   ├── create_task/
│   │   └── app.py
│   ├── get_tasks/
│   │   └── app.py
│   ├── get_task/
│   │   └── app.py
│   ├── update_task/
│   │   └── app.py
│   └── delete_task/
│       └── app.py
└── events/
    ├── create.json
    └── get.json

 

 

Création du template SAM

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Tasks API - Application TODO serverless complète

# Configuration globale pour toutes les fonctions Lambda
Globals:
  Function:
    Timeout: 30
    Runtime: python3.11
    MemorySize: 256
    Environment:
      Variables:
        TABLE_NAME: !Ref TasksTable
  Api:
    Cors:
      AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
      AllowHeaders: "'Content-Type,X-Amz-Date,Authorization'"
      AllowOrigin: "'*'"

Resources:
  # Table DynamoDB
  TasksTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: TasksSAM
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: taskId
          AttributeType: S
      KeySchema:
        - AttributeName: taskId
          KeyType: HASH
  
  # Fonction Lambda : Create Task
  CreateTaskFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: CreateTaskFunction-SAM
      CodeUri: src/create_task/
      Handler: app.lambda_handler
      Events:
        CreateTaskAPI:
          Type: Api
          Properties:
            Path: /tasks
            Method: POST
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref TasksTable
  
  # Fonction Lambda : Get All Tasks
  GetTasksFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: GetTasksFunction-SAM
      CodeUri: src/get_tasks/
      Handler: app.lambda_handler
      Events:
        GetTasksAPI:
          Type: Api
          Properties:
            Path: /tasks
            Method: GET
      Policies:
        - DynamoDBReadPolicy:
            TableName: !Ref TasksTable
  
  # Fonction Lambda : Get Single Task
  GetTaskFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: GetTaskFunction-SAM
      CodeUri: src/get_task/
      Handler: app.lambda_handler
      Events:
        GetTaskAPI:
          Type: Api
          Properties:
            Path: /tasks/{taskId}
            Method: GET
      Policies:
        - DynamoDBReadPolicy:
            TableName: !Ref TasksTable
  
  # Fonction Lambda : Update Task
  UpdateTaskFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: UpdateTaskFunction-SAM
      CodeUri: src/update_task/
      Handler: app.lambda_handler
      Events:
        UpdateTaskAPI:
          Type: Api
          Properties:
            Path: /tasks/{taskId}
            Method: PUT
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref TasksTable
  
  # Fonction Lambda : Delete Task
  DeleteTaskFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: DeleteTaskFunction-SAM
      CodeUri: src/delete_task/
      Handler: app.lambda_handler
      Events:
        DeleteTaskAPI:
          Type: Api
          Properties:
            Path: /tasks/{taskId}
            Method: DELETE
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref TasksTable

# Outputs affichés après le déploiement
Outputs:
  TasksApiUrl:
    Description: "URL de l'API Tasks"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
  
  TasksTableName:
    Description: "Nom de la table DynamoDB"
    Value: !Ref TasksTable

Code des fonctions Lambda

Les codes des fonctions sont identiques à ceux de la partie Console, mais ils utilisent la variable d'environnement TABLE_NAME au lieu d'un nom en dur.

 

Exemple : src/create_task/app.py

import json
import boto3
import uuid
import os
from datetime import datetime

# Récupération du nom de table depuis l'environnement
TABLE_NAME = os.environ['TABLE_NAME']

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(TABLE_NAME)

def lambda_handler(event, context):
    """Crée une nouvelle tâche"""
    try:
        body = json.loads(event.get('body', '{}'))
        title = body.get('title')
        description = body.get('description', '')
        
        if not title:
            return {
                'statusCode': 400,
                'headers': {'Content-Type': 'application/json'},
                'body': json.dumps({'error': 'Le champ title est obligatoire'})
            }
        
        task = {
            'taskId': str(uuid.uuid4()),
            'title': title,
            'description': description,
            'status': 'pending',
            'createdAt': datetime.now().isoformat(),
            'updatedAt': datetime.now().isoformat()
        }
        
        table.put_item(Item=task)
        
        return {
            'statusCode': 201,
            'headers': {'Content-Type': 'application/json'},
            'body': json.dumps({'message': 'Tâche créée', 'task': task})
        }
    except Exception as e:
        print(f"Erreur: {str(e)}")
        return {
            'statusCode': 500,
            'headers': {'Content-Type': 'application/json'},
            'body': json.dumps({'error': 'Erreur serveur interne'})
        }

Créez les autres fonctions (get_tasks, get_task, update_task, delete_task) avec le même code que dans la partie Console, en remplaçant "Tasks" par os.environ["TABLE_NAME"].

 

Déploiement avec SAM

valider le template

sam validate

Sortie attendue : template.yaml is a valid SAM Template

 

Build de l'application

sam build

Cette commande : Installe les dépendances + Package le code + Prépare les artefacts

 

Déploiement guidé

sam deploy --guided

 

Stack Name: tasks-api-sam
AWS Region: us-east-1
Confirm changes before deploy: y
Allow SAM CLI IAM role creation: Y
Disable rollback: N
CreateTaskFunction may not have authorization defined, Is this okay?: y
(répétez pour toutes les fonctions)
Save arguments to configuration file: Y

 

Résultat du déploiement

Après un déploiement réussi, vous verrez :

CloudFormation outputs from deployed stack
---------------------------------------------------------
Outputs                                                  
---------------------------------------------------------
Key                 TasksApiUrl                          
Description         URL de l'API Tasks                   
Value               https://abc123xyz.execute-api.us-east-1.amazonaws.com/Prod/

Successfully created/updated stack - tasks-api-sam

Tester l'API SAM

Créer une tâche

curl -X POST https://abc123xyz.execute-api.us-east-1.amazonaws.com/Prod/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Tâche SAM", "description": "Déployée avec IaC"}'

Lister les tâches

curl https://abc123xyz.execute-api.us-east-1.amazonaws.com/Prod/tasks

 

Surveillance et debugging

Voir les logs CloudWatch

Afficher les logs en temps réel

sam logs -n CreateTaskFunction --stack-name tasks-api-sam --tail

Afficher les derniers logs

sam logs -n CreateTaskFunction --stack-name tasks-api-sam

 

Mise à jour de l'application

Modifiez le code Python ou le template.yaml
Lancez sam build
Lancez sam deploy
SAM détecte les changements et met à jour uniquement ce qui a changé

 

Suppression de l'application

Cette commande supprime TOUTES les ressources, y compris la table DynamoDB et toutes vos données. Utilisez avec précaution !

sam delete

Are you sure you want to delete the stack tasks-api-sam? [y/N]: y
Are you sure you want to delete the folder in S3? [y/N]: y

 

Pour aller plus loin

Ajouter l'authentification avec Cognito

Implémenter des websockets pour le temps réel

Créer un frontend React/Vue.js

Ajouter des tests unitaires et d'intégration

Configurer un pipeline CI/CD avec GitHub Actions

Implémenter le monitoring avec X-Ray

Ajouter une couche de cache avec ElastiCache

Gérer les secrets avec AWS Secrets Manager