Introduction à AWS Lambda : guide pour développeurs intermédiaires
AWS Lambda est un service serverless qui exécute du code en réponse à des événements, sans que vous ayez à provisionner ni administrer des serveurs. En tant que développeur intermédiaire, vous connaissez probablement déjà les bases (fonction, déclencheur, logs). Ce guide vise à aller plus loin : modèle d’exécution, packaging, observabilité, sécurité, performances, déploiement automatisé, et bonnes pratiques de conception.
1) Modèle mental : ce que fait réellement Lambda
1.1 Événements, invocations et cycle de vie
Une fonction Lambda est invoquée par un événement (API Gateway, SQS, EventBridge, S3, etc.). Chaque invocation s’exécute dans un environnement d’exécution isolé. Deux notions sont cruciales :
- Cold start : création d’un nouvel environnement d’exécution (téléchargement du code, initialisation runtime, exécution du code d’initialisation).
- Warm start : réutilisation d’un environnement existant (plus rapide).
Lambda sépare conceptuellement :
- Phase d’initialisation : code exécuté au chargement du module (hors handler). Idéal pour créer des clients AWS, initialiser des pools, charger des variables, etc.
- Phase d’invocation : exécution du handler pour chaque événement.
Exemple (Node.js) : le client est créé hors handler pour être réutilisé lors des warm starts.
// index.mjs
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
const ddb = new DynamoDBClient({}); // initialisation (souvent une seule fois)
export const handler = async (event) => {
// invocation
return { ok: true, input: event };
};
1.2 Concurrence et scalabilité
Lambda scale automatiquement en créant plusieurs environnements si plusieurs invocations arrivent en parallèle. Deux paramètres influencent fortement votre architecture :
- Concurrence non réservée : partagée entre fonctions d’un compte/région.
- Concurrence réservée : plafond dédié à une fonction (et réserve garantie). Utile pour protéger une base de données ou garantir une capacité minimale.
- Provisioned Concurrency : environnements préchauffés pour réduire les cold starts (souvent avec API critiques).
1.3 Timeout, mémoire, CPU et coût
Le coût dépend principalement :
- Durée d’exécution (ms)
- Mémoire allouée (qui influence aussi le CPU et souvent le débit réseau)
- Nombre d’invocations
Augmenter la mémoire peut réduire la durée, donc parfois réduire le coût total. Il faut mesurer.
2) Prérequis et configuration locale
2.1 Installer AWS CLI et configurer un profil
Installez AWS CLI v2, puis configurez vos identifiants.
aws --version
aws configure
Vous pouvez aussi utiliser des profils :
aws configure --profile dev
export AWS_PROFILE=dev
aws sts get-caller-identity
2.2 Choisir une région
export AWS_REGION=eu-west-3
aws configure set region "$AWS_REGION"
3) Créer une fonction Lambda de zéro (CLI) + rôle IAM minimal
3.1 Créer un rôle d’exécution
Une Lambda a besoin d’un rôle IAM (trust policy) permettant au service Lambda d’assumer ce rôle, et de permissions pour écrire des logs, accéder à d’autres services, etc.
Créez un fichier trust-policy.json :
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
Créez le rôle :
aws iam create-role \
--role-name lambda-demo-role \
--assume-role-policy-document file://trust-policy.json
Attachez la politique gérée pour CloudWatch Logs :
aws iam attach-role-policy \
--role-name lambda-demo-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Récupérez l’ARN du rôle :
ROLE_ARN=$(aws iam get-role --role-name lambda-demo-role --query 'Role.Arn' --output text)
echo "$ROLE_ARN"
3.2 Écrire le code et packager
Exemple Python lambda_function.py :
import json
import os
import time
def handler(event, context):
return {
"statusCode": 200,
"headers": {"content-type": "application/json"},
"body": json.dumps({
"message": "Bonjour depuis Lambda",
"region": os.environ.get("AWS_REGION"),
"requestId": context.aws_request_id,
"input": event
})
}
Zippez le fichier :
zip function.zip lambda_function.py
3.3 Créer la fonction
aws lambda create-function \
--function-name lambda-demo \
--runtime python3.12 \
--handler lambda_function.handler \
--zip-file fileb://function.zip \
--role "$ROLE_ARN" \
--timeout 10 \
--memory-size 256
3.4 Invoquer la fonction
aws lambda invoke \
--function-name lambda-demo \
--payload '{"source":"cli","action":"test"}' \
response.json
cat response.json
Afficher les logs dans CloudWatch (via AWS CLI) :
aws logs describe-log-groups --log-group-name-prefix /aws/lambda/lambda-demo
aws logs tail /aws/lambda/lambda-demo --follow
4) Variables d’environnement, configuration et secrets
4.1 Variables d’environnement
aws lambda update-function-configuration \
--function-name lambda-demo \
--environment "Variables={APP_ENV=dev,FEATURE_X=true}"
Dans le code, lisez os.environ (Python) ou process.env (Node.js).
4.2 Secrets : éviter de stocker des mots de passe en clair
Bonnes options :
- AWS Systems Manager Parameter Store (paramètres, SecureString)
- AWS Secrets Manager (rotation, intégration)
Exemple : lire un paramètre sécurisé depuis SSM (Python, avec boto3) nécessite d’ajouter des permissions IAM (ex. ssm:GetParameter). Politique minimale (exemple) :
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOneParameter",
"Effect": "Allow",
"Action": ["ssm:GetParameter"],
"Resource": "arn:aws:ssm:eu-west-3:123456789012:parameter/monapp/db_password"
}
]
}
Attacher une politique inline :
aws iam put-role-policy \
--role-name lambda-demo-role \
--policy-name lambda-ssm-read \
--policy-document file://ssm-policy.json
5) Déclencheurs courants et implications d’architecture
5.1 API Gateway (synchrone)
Cas d’usage : API HTTP. Vous devez gérer :
- format d’entrée (payload v1/v2)
- codes HTTP
- CORS
- latence (cold starts)
Pour un flux synchrone, votre Lambda doit répondre rapidement. Si vous avez des traitements longs, préférez :
- mise en file (SQS)
- orchestration (Step Functions)
- traitement asynchrone
5.2 SQS (asynchrone, robuste)
SQS + Lambda est un pattern très utilisé. Lambda lit des messages par batch, et gère les retries.
Points importants :
- Batch size : plus grand = meilleur débit, mais attention aux messages “poison”.
- Visibility timeout : doit être > durée max de traitement.
- DLQ (Dead Letter Queue) : pour isoler les messages qui échouent après plusieurs tentatives.
- Partial batch response : possibilité de ne renvoyer que les messages en échec (selon runtime et configuration), pour éviter de rejouer tout le batch.
5.3 EventBridge (événements métier)
EventBridge est idéal pour un bus d’événements. Vous publiez des événements structurés et déclenchez des règles.
Exemple d’envoi d’événement :
aws events put-events --entries '[
{
"Source":"monapp.commandes",
"DetailType":"CommandeCreee",
"Detail":"{\"commandeId\":\"c-123\",\"montant\":42.5}",
"EventBusName":"default"
}
]'
6) Packaging avancé : dépendances, couches et images conteneur
6.1 Zip + dépendances (Python)
Pour Python, si vous avez des dépendances, vous devez les inclure dans le zip.
mkdir -p build/python
pip install -r requirements.txt -t build/
cp lambda_function.py build/
cd build && zip -r ../function.zip .
cd ..
Attention aux dépendances natives : elles doivent être compilées pour l’environnement compatible Lambda (Amazon Linux). Souvent, on utilise Docker pour builder.
6.2 Lambda Layers (couches)
Les layers permettent de partager des bibliothèques entre plusieurs fonctions ou de séparer le code applicatif des dépendances.
Créer un layer Python :
mkdir -p layer/python
pip install requests -t layer/python
cd layer && zip -r ../requests-layer.zip .
cd ..
aws lambda publish-layer-version \
--layer-name requests-layer \
--zip-file fileb://requests-layer.zip \
--compatible-runtimes python3.12
Attacher le layer à la fonction :
LAYER_ARN=$(aws lambda list-layer-versions --layer-name requests-layer --query 'LayerVersions[0].LayerVersionArn' --output text)
aws lambda update-function-configuration \
--function-name lambda-demo \
--layers "$LAYER_ARN"
6.3 Images conteneur
Les images conteneur sont utiles si :
- vous avez des dépendances natives complexes
- vous voulez un contrôle fin de l’environnement
- vous avez déjà une chaîne CI Docker
Flux typique :
- construire une image conforme Lambda
- pousser sur ECR
- créer/mettre à jour la Lambda avec l’image
Créer un dépôt ECR :
aws ecr create-repository --repository-name lambda-demo-image
Connexion Docker à ECR :
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
aws ecr get-login-password --region "$AWS_REGION" \
| docker login --username AWS --password-stdin "$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
7) Observabilité : logs, métriques, traces
7.1 CloudWatch Logs : structurer vos logs
Loggez en JSON pour faciliter la recherche. En Python :
import json, time
def log(level, msg, **fields):
print(json.dumps({
"level": level,
"message": msg,
"ts": int(time.time() * 1000),
**fields
}))
Puis :
log("INFO", "Traitement démarré", requestId=context.aws_request_id)
7.2 Métriques et alarmes
Lambda expose des métriques : Invocations, Errors, Duration, Throttles. Créez une alarme sur les erreurs :
aws cloudwatch put-metric-alarm \
--alarm-name lambda-demo-errors \
--metric-name Errors \
--namespace AWS/Lambda \
--statistic Sum \
--period 60 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 1 \
--dimensions Name=FunctionName,Value=lambda-demo \
--treat-missing-data notBreaching
7.3 Traces avec AWS X-Ray
X-Ray aide à comprendre la latence (cold start, appels externes). Activez le tracing :
aws lambda update-function-configuration \
--function-name lambda-demo \
--tracing-config Mode=Active
8) Sécurité : IAM, réseau, chiffrement, moindre privilège
8.1 IAM : permissions minimales
Évitez les politiques trop larges (*). Donnez :
- actions minimales (
dynamodb:GetItem,s3:GetObject, etc.) - ressources ciblées (ARN précis)
- conditions (par exemple sur des préfixes S3)
8.2 Accès réseau : VPC ou pas ?
Par défaut, Lambda accède à Internet si elle n’est pas dans un VPC. Si vous placez la Lambda dans un VPC pour accéder à une base privée (RDS, ElastiCache), vous devez gérer :
- subnets privés
- tables de routage
- NAT Gateway (si accès Internet sortant requis)
- endpoints VPC (pour accéder à S3/DynamoDB sans NAT)
Mettre une Lambda dans un VPC peut augmenter la latence et complexifier l’exploitation. Ne le faites que si nécessaire.
8.3 Chiffrement
- Variables d’environnement : chiffrées au repos (KMS). Vous pouvez spécifier une clé KMS dédiée.
- Données : chiffrement côté service (S3 SSE, DynamoDB, etc.) et chiffrement applicatif si besoin.
9) Performance : réduire la latence et maîtriser les coûts
9.1 Réduire les cold starts
Stratégies :
- minimiser le code d’initialisation
- réduire la taille du package
- éviter les imports lourds inutiles
- utiliser Provisioned Concurrency pour les endpoints critiques
- choisir un runtime adapté et des dépendances raisonnables
9.2 Réutiliser les connexions
Pour les bases de données, réutilisez les clients hors handler. Pour RDS, attention au nombre de connexions : le scaling de Lambda peut saturer la base. Solutions :
- RDS Proxy
- pooling côté application (avec prudence)
- architecture asynchrone (SQS)
9.3 Ajuster mémoire et timeout
Testez plusieurs tailles mémoire et mesurez Duration. Un réglage typique consiste à :
- augmenter la mémoire par paliers (256, 512, 1024…)
- mesurer la durée p95
- choisir le meilleur compromis coût/latence
10) Gestion des erreurs, retries et idempotence
10.1 Différence sync vs async
- Synchrone (API Gateway) : l’erreur est renvoyée au client. Pas de retry automatique côté Lambda (sauf côté client ou intégration).
- Asynchrone (EventBridge, S3, invocation async) : Lambda peut retenter automatiquement. Vous devez concevoir pour supporter les doublons.
10.2 Idempotence
Une fonction idempotente peut être appelée plusieurs fois avec le même événement sans effet de bord indésirable. Techniques :
- stocker un
eventIdtraité (DynamoDB avec conditionattribute_not_exists) - utiliser des clés de déduplication (SQS FIFO)
- appliquer des écritures conditionnelles
Exemple de stratégie DynamoDB : “traiter une seule fois” via PutItem conditionnel.
11) Déploiement automatisé avec AWS SAM (pratique et réaliste)
AWS SAM (Serverless Application Model) simplifie la définition et le déploiement. Même si vous pouvez tout faire en CLI, SAM apporte :
- packaging des artefacts
- gestion des permissions
- déploiement reproductible
11.1 Installer SAM CLI
Vérifiez :
sam --version
11.2 Initialiser un projet
sam init
Choisissez un runtime (par exemple Python) et un template “Hello World”, puis explorez la structure.
11.3 Construire et déployer
sam build
sam deploy --guided
Pendant --guided, vous définissez :
- nom de stack CloudFormation
- région
- paramètres
- autorisation de créer des rôles IAM
11.4 Tester localement
SAM peut émuler l’exécution via Docker :
sam local invoke
Ou lancer une API locale :
sam local start-api
curl -i http://127.0.0.1:3000/hello
12) Versioning, alias et déploiements progressifs
Lambda supporte :
- Versions immuables
- Alias pointant vers une version (ex.
prod,staging) - Traffic shifting (déploiement canari/linéaire) via CodeDeploy ou SAM
Publier une version :
aws lambda publish-version --function-name lambda-demo
Créer/mettre à jour un alias :
aws lambda create-alias \
--function-name lambda-demo \
--name prod \
--function-version 1
aws lambda update-alias \
--function-name lambda-demo \
--name prod \
--function-version 2
Cette approche est essentielle pour :
- rollback rapide
- séparation des environnements
- déploiements contrôlés
13) Bonnes pratiques de conception (retour d’expérience)
13.1 Fonctions petites, responsabilités claires
Évitez la “Lambda monolithe” qui fait tout. Préférez :
- une fonction par responsabilité
- des événements explicites (EventBridge)
- des contrats stables (schémas JSON)
13.2 Schémas et validation
Validez les entrées (API ou événements). Sans validation, les erreurs deviennent difficiles à diagnostiquer et les retries peuvent amplifier le problème.
13.3 Timeouts cohérents
- Timeout Lambda : un peu au-dessus du temps normal + marge.
- Timeouts clients HTTP : plus courts que le timeout Lambda pour éviter des requêtes pendantes.
- Pour SQS : visibility timeout > timeout Lambda + marge.
13.4 Limiter les dépendances
Chaque dépendance :
- augmente la taille du package
- augmente le temps d’import
- augmente la surface d’attaque
14) Nettoyage des ressources (éviter les coûts inutiles)
Supprimer la fonction :
aws lambda delete-function --function-name lambda-demo
Détacher la politique et supprimer le rôle (après suppression de la fonction) :
aws iam detach-role-policy \
--role-name lambda-demo-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam delete-role --role-name lambda-demo-role
15) Check-list finale pour une Lambda “production-ready”
- IAM : moindre privilège, ressources ciblées, pas de
*gratuit - Observabilité : logs structurés, alarmes sur
ErrorsetThrottles, tracing si utile - Performance : dépendances maîtrisées, init hors handler, mémoire dimensionnée
- Résilience : retries compris, DLQ si asynchrone, idempotence
- Déploiement : versions + alias, rollback, CI/CD (SAM/CloudFormation)
- Réseau : VPC uniquement si nécessaire, endpoints VPC si possible
- Secrets : Parameter Store / Secrets Manager, pas en clair dans le code
Conclusion
AWS Lambda est simple à démarrer mais riche en subtilités dès qu’on vise la production : concurrence, retries, idempotence, packaging, observabilité et sécurité. En appliquant les patterns présentés (rôles IAM minimaux, logs structurés, déclencheurs adaptés, versioning/alias, et déploiement automatisé), vous obtenez des fonctions robustes, économiques et faciles à faire évoluer.
Si vous voulez, je peux proposer une architecture complète (API Gateway + SQS + Lambda + DynamoDB) avec commandes de création, politiques IAM minimales et stratégie de déploiement progressive par alias.