Test LocalStack sur une VM Docker ECloud
Cette page décrit les premiers tests réalisés avec LocalStack sur une VM Docker sur ECloud.
L’objectif est de tester ce qu’on peut faire avec l’outil et comment peut-on le transformer en une ressources pédagogiques.
LocalStack est un émulateur des APIs AWS, Azure et SnowFlake qui permet de gérer des services cloud AWS émulés.
L’émulateur fonctionne principalement dans un conteneur Docker.
L’outil permet d’émuler localement des services AWS comme EC2, S3, Lambda, etc., sans utiliser directement le véritable cloud AWS.
L’utilisation de cet outil offre un gain de temps lors des tests de déploiement. Et puisque les ressources ne sont pas vraiment allouées sur le cloud d’AWS, cela réduit le coût des tests de l’infrastructure avant son déploiement réel.
L’interaction avec les services AWS émulés est possible via une approche Infrastructure as Code. Cela permet d’enseigner des technologies tels que Terraform ou OpenTofu sans dépendre d’AWS.
La page est structurée comme suit :
- Contexte de test
- Installation de Localstack dans un environnement Python virtuel
- Différence entre les Clis (command line interfaces )
- Aide et autocomplétion
Les services AWS emulés:
1. Contexte de test
Test réalisé sur ECloud avec une VM Docker disposant des ressources suivantes :
- 4 vCPU
- 8 Go de RAM
- 32 Go de disque
- LocalStack lancé en mode Docker
- Ecrit en Python et installé dans un environnement virtuel nommé
localstack.
Versions LocalStack:
Runtime version : 2026.3.1.dev4943
LocalStack CLI : 2026.3.0
Profile : default
App : https://app.localstack.cloud
Licence : Hobby / Free
Fonctionnalités disponible dans l’offre Free (Hobby) :
- LocalStack for AWS Emulator
- 30+ services émulés :
ec2,s3,route53,rds,opensearch,dynamodb,cloudwatch, … etc. - Les services AWS disponibles sont accessibles à travers les ports ouverts sur ce container.
2. Installation de Localstack dans un environnement Python virtuel
sudo apt install python3.11-venv terraform
python3 -m venv ~/localstack
. ~/localstack/bin/activate
pip install localstack awscli-local wheel terraform-local awscli-local boto3
# Il faut créer un compte sur Localstack et récupérer un token.
# Aller sur https://app.localstack.cloud/sign-in
localstack auth set-token $TOKEN
# Démarrage du container docker Localstack
localstack start -d
docker container ls --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"
# localstack-main 127.0.0.1:443->443/tcp, 127.0.0.1:4510-4560->4510-4560/tcp, 53/tcp, 5678/tcp, 127.0.0.1:4566->4566/tcp
3. Différence entre les Clis (command line interfaces)
1. aws et awslocal
Sur la VM, les deux commandes existent dans l’environnement virtuel Python :
which aws # /home/master/localstack/bin/aws
# aws est la CLI officielle AWS. Par défaut, elle essaie de parler au **vrai AWS**.
# Exemple :
# Sans configuration spéciale, cette commande cherche à contacter AWS réel.
aws s3 ls # Unable to locate credentials. You can configure credentials by running "aws configure".
which awslocal # /home/master/localstack/bin/awslocal
# awslocal est un wrapper fourni pour LocalStack. Il appelle la commande aws, mais ajoute automatiquement l'endpoint LocalStack.
# Exemple :
awslocal s3 ls # 2026-04-24 10:09:37 demo-localstack-bucket
# Cette commande est équivalente à :
AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 \
aws --endpoint-url=http://localhost:4566 s3 ls
awslocal au lieu de répéter --endpoint-url=http://localhost:4566 à chaque commande.
2. Terraform et tflocal
Le même principe est appliqué sur Terraform.
4. Aide et autocomplétion
Afficher l’aide générale
aws help
awslocal help
Afficher l’aide d’un service
aws s3 help
awslocal s3 help
aws lambda help
awslocal lambda help
Afficher l’aide d’une sous-commande
aws s3 ls help
aws s3 cp help
awslocal s3 ls help
awslocal s3 cp help
Activer l’autocomplétion temporairement
complete -C "$(which aws_completer)" aws
complete -C "$(which aws_completer)" awslocal
Après cela, on peut tester :
awslocal s3 <TAB><TAB> # cp ls mb mv presign rb rm sync website
Rendre l’autocomplétion permanente
Ajouter dans ~/.bashrc :
if command -v aws_completer >/dev/null 2>&1; then
complete -C "$(command -v aws_completer)" aws
complete -C "$(command -v aws_completer)" awslocal
fi
Puis recharger le shell :
source ~/.bashrc
Les services AWS emulés
Pour rappel, ces services ne font qu’une imitation du comportement des veritables services émulés.
1. Amazon Simple Storage Service: S3
Amazon S3 est un service de stockage d’objets. Dans LocalStack, on peut utiliser les API S3 localement pour créer des buckets, envoyer des objets, les lister, les télécharger, tester des URLs présignées ou configurer certains paramètres comme CORS. Il représente des avantages Cloud comme la capacité de mise à l’échelle, la disponibilité ..etc.
On peut le représenter ainsi :
S3
└── bucket
├── objet 1
├── objet 2
└── objet 3
Vocabulaire :
- bucket : conteneur logique
- object : objet stocké, souvent créé à partir d’un fichier
- key : nom ou chemin logique de l’objet
- metadata : informations associées à l’objet, par exemple taille, type de contenu, ETag
Exemple :
s3://demo-localstack-bucket/images/photo.png
On peut voir S3 comme un service de stockage accessible par API HTTP.
S3 ressemble à un système de fichiers parce qu’on écrit des chemins comme : s3://demo-localstack-bucket/images/photo.png
Mais S3 n’est pas un disque monté et ce n’est pas un dossier Linux.
Avec S3, on ne manipule pas des fichiers locaux mais des objets stockés dans un service.
Le / dans images/photo.png ne crée pas forcément un vrai dossier. C’est surtout une convention dans le nom de l’objet.
Les interfaces AWS l’affichent comme un dossier pour faciliter la lecture, mais techniquement S3 stocke des objets avec des clés.
# On ne peut pas faire:
cd s3://demo-localstack-bucket
# Mais on utilise des commandes API :
awslocal s3 ls s3://demo-localstack-bucket/
Il existe des outils comme s3fs qui permettent de monter un bucket S3 comme s’il ressemblait à un dossier local, mais ce n’est qu’une couche d’adaptation. S3 reste un service de stockage objet, avec un comportement différent d’un vrai système de fichiers.
Créer un bucket
Deux styles de commandes sont possibles avec la CLI AWS :
awslocal s3: commandes haut niveau, pratiques pour manipuler des fichiersawslocal s3api: commandes proches de l’API AWS S3, plus précises et plus explicites
Exemple avec la commande haut niveau :
awslocal s3 mb s3://demo-localstack-bucket
Exemple avec l’API S3 :
awslocal s3api create-bucket --bucket demo-localstack-bucket
Dans LocalStack, la région par défaut est généralement us-east-1. Pour un TP, il est utile de garder cette région partout afin d’éviter les différences de comportement entre commandes, SDK et Terraform.
Lister les buckets
awslocal s3 ls
awslocal s3api list-buckets
Exemple de sortie :
2026-04-24 10:09:37 demo-localstack-bucket
2026-04-24 01:42:40 localstack-thumbnails-app-images
2026-04-24 01:42:42 localstack-thumbnails-app-resized
Envoyer et lister des objets
La commande cp prend une source et une destination. Pour copier plusieurs fichiers, il faut lancer plusieurs commandes ou utiliser --recursive pour copier un répertoire.
awslocal s3 cp function.zip s3://demo-localstack-bucket/
awslocal s3 cp code.tf s3://demo-localstack-bucket/
awslocal s3 cp output.txt s3://demo-localstack-bucket/
Pour copier tout le dossier courant :
awslocal s3 cp . s3://demo-localstack-bucket/ --recursive
# Avec des filtres
awslocal s3 cp . s3://demo-localstack-bucket/ \
--recursive \
--exclude "*" \
--include "*.tf" \
--include "*.zip"
La commande s3api put-object permet de voir plus directement l’appel API sous-jacent :
awslocal s3api put-object \
--bucket demo-localstack-bucket \
--key docs/code.tf \
--body code.tf
Lister les objets :
awslocal s3 ls s3://demo-localstack-bucket/
awslocal s3api list-objects --bucket demo-localstack-bucket
Synchroniser un répertoire
sync copie récursivement les fichiers nouveaux ou modifiés entre un dossier local et S3. L’option --dryrun permet de vérifier ce qui serait copié sans modifier le bucket.
awslocal s3 sync /tmp s3://demo-localstack-bucket/tmp/ --dryrun
awslocal s3 sync /tmp s3://demo-localstack-bucket/tmp/
Lister le contenu du bucket :
awslocal s3 ls s3://demo-localstack-bucket/
Générer une URL présignée
Une URL présignée permet de donner un accès temporaire en HTTP à un objet. LocalStack permet de tester ce comportement localement.
awslocal s3 cp fichier.txt s3://demo-localstack-bucket/fichier.txt
awslocal s3 presign s3://demo-localstack-bucket/fichier.txt
La commande renvoie une URL que l’on peut tester avec curl :
curl "http://localhost:4566/demo-localstack-bucket/fichier.txt?..."
Ce qui se passe dans le conteneur LocalStack avec S3
Quand on crée un bucket S3 avec LocalStack, par exemple avec :
awslocal s3 mb s3://demo-bucket
LocalStack ne crée pas un vrai bucket dans AWS. Il reçoit l’appel API S3 sur son endpoint local, puis il enregistre cette ressource dans son état interne. Le bucket devient donc une ressource émulée connue par LocalStack. On peut ensuite la retrouver avec :
awslocal s3 ls
Le bucket est seulement un conteneur logique. Il ne correspond pas à un dossier Linux classique. Quand on envoie un fichier dans ce bucket :
awslocal s3 cp fichier.txt s3://demo-bucket/fichier.txt
la CLI AWS lit le fichier local fichier.txt, l’envoie à l’API S3 de LocalStack, puis LocalStack stocke son contenu comme un objet S3.
L’objet est identifié par :
- le nom du bucket :
demo-bucket - la clé de l’objet :
fichier.txt - des métadonnées : taille, type de contenu, date de modification, etag, etc.
Dans LocalStack, le stockage physique dépend de la configuration du conteneur. Par défaut, les données vivent dans l’état du conteneur LocalStack. Si le conteneur est supprimé sans volume persistant, les ressources peuvent être perdues. Avec une configuration de persistance ou un volume Docker, LocalStack peut conserver son état entre deux démarrages.
2. Amazon Elastic Compute Cloud EC2 avec LocalStack
Dans AWS, EC2 correspond à des machines virtuelles.
Dans LocalStack, EC2 est principalement une instance de simulation d’API qui imite une instance EC2.
Cela signifie que l’on peut tester des appels AWS ou des fichiers Terraform, mais cela ne crée pas une vraie VM complète comme dans AWS réel.
Terraform avec LocalStack
Terraform permet de décrire de l’infrastructure sous forme de code.
Avec LocalStack, on peut tester cette infrastructure localement.
L'architecture du répértoire:
tf-ec2-localstack/
├── provider.tf
├── main.tf
└── outputs.tf # optionnel
# Exemple de provider AWS pour LocalStack provider.tf
```hcl
provider "aws" {
access_key = "test"
secret_key = "test"
region = "us-east-1"
skip_credentials_validation = true
skip_metadata_api_check = true
skip_requesting_account_id = true
endpoints {
ec2 = "http://localhost:4566"
}
}
# Exemple d'instance EC2 simulée main.tf
```hcl
resource "aws_instance" "demo" {
ami = "ami-12345678"
instance_type = "t2.micro"
tags = {
Name = "localstack-demo-ec2"
}
}
# Commandes Terraform locales pour Localstack
tflocal init
tflocal plan
tflocal apply
# Voir l'état Terraform
tflocal state list
tflocal show
# Voir les instances côté LocalStack
awslocal ec2 describe-instances
#Compter les instances simulées :
awslocal ec2 describe-instances \
--query "length(Reservations[].Instances[])" \
--output text
# Détruire les ressources
tflocal destroy
3. Lambda
Lambda est un service qui permet d’exécuter une fonction à la demande, sans gérer de serveur directement.
Une fonction Lambda fonctionne globalement ainsi :
événement → fonction handler → réponse
On déploie du code, puis on invoque la fonction.
Exemple Lambda avec un runtime en Python
mkdir -p ~/lambda-python # Créer un dossier :
cd ~/lambda-python
Créer le fichier lambda_function.py :
import json
def handler(event, context):
body = json.loads(event["body"])
num1 = body["num1"]
num2 = body["num2"]
product = num1 * num2
return {
"statusCode": 200,
"body": f"The product of {num1} and {num2} is {product}"
}
Créer le zip :
zip function.zip lambda_function.py
Créer la fonction Lambda :
awslocal lambda create-function \
--function-name lambda-python-product \
--runtime python3.12 \
--zip-file fileb://function.zip \
--handler lambda_function.handler \
--role arn:aws:iam::000000000000:role/lambda-role
Invoquer la fonction :
awslocal lambda invoke \
--function-name lambda-python-product \
--payload '{"body":"{\"num1\":6,\"num2\":7}"}' \
response.json
cat response.json
Exemple Lambda en JavaScript / Node.js
Créer index.js :
exports.handler = async (event) => {
let body = JSON.parse(event.body);
const product = body.num1 * body.num2;
return {
statusCode: 200,
body: "The product of " + body.num1 + " and " + body.num2 + " is " + product,
};
};
Créer le zip :
zip function.zip index.js
Créer la fonction :
awslocal lambda create-function \
--function-name localstack-lambda-url-example \
--runtime nodejs22.x \
--zip-file fileb://function.zip \
--handler index.handler \
--role arn:aws:iam::000000000000:role/lambda-role
Exemple de fonction Lambda Word Counter en Python
On crée un bucket d’entrée pour déposer les fichiers, puis un bucket de sortie pour stocker les résultats.
L’objectif sera de déclencher la fonction lorsqu’un fichier texte sera téléversé dans le bucket d’entrée. La fonction compte le nombre de lignes et de caractéres dans le fichier puis le stocke en fichier json dans le bucket de sortie.
import boto3 # SDK pour Python pour manipuler des services AWS comme S3 et EC2.
import json
import os
import re
from urllib.parse import unquote_plus
s3 = boto3.client("s3")
OUTPUT_BUCKET = os.environ.get("OUTPUT_BUCKET", "results-bucket")
def handler(event, context):
print("Lambda déclenchée par S3")
results = []
for record in event.get("Records", []):
source_bucket = record["s3"]["bucket"]["name"]
key = unquote_plus(record["s3"]["object"]["key"]) # key est le nom du fichier.txt
print(f"Lecture du fichier : s3://{source_bucket}/{key}")
obj = s3.get_object(Bucket=source_bucket, Key=key)
content = obj["Body"].read().decode("utf-8")
lines = content.splitlines()
words = re.findall(r"\b[\w'-]+\b", content)
chars = len(content)
result = {
"source_bucket": source_bucket,
"source_key": key,
"line_count": len(lines),
"word_count": len(words),
"character_count": chars,
}
output_key = key + ".wordcount.json"
s3.put_object(
Bucket=OUTPUT_BUCKET,
Key=output_key,
Body=json.dumps(result, indent=2, ensure_ascii=False).encode("utf-8"),
ContentType="application/json"
)
print(f"Rapport créé : s3://{OUTPUT_BUCKET}/{output_key}")
print(json.dumps(result, indent=2, ensure_ascii=False))
results.append(result)
return {
"ok": True,
"processed": len(results),
"results": results
}
En suite, on rée l’archive ZIP de la fonction :
zip -r function.zip lambda_function.py
On crée la fonction Lambda dans LocalStack
awslocal lambda create-function \
--function-name word-counter \
--runtime python3.12 \
--handler lambda_function.handler \
--zip-file fileb://function.zip \
--role arn:aws:iam::000000000000:role/lambda-role \
--environment Variables="{OUTPUT_BUCKET=results-bucket}"
On peut vérifier que la fonction existe :
awslocal lambda list-functions
Tester manuellement l’invocation de la fonction :
awslocal lambda invoke \
--function-name word-counter \
--payload '{"Records":[]}' \
response.json
cat response.json
A ce stade, il faut autoriser S3 à invoquer la fonction Lambda pour que S3 puisse déclencher la fonction, il faut donc ajouter une permission d’invocation :
awslocal lambda add-permission \
--function-name word-counter \
--statement-id s3invoke \
--action lambda:InvokeFunction \
--principal s3.amazonaws.com \
--source-arn arn:aws:s3:::demo-bucket
On note bien qu’on a ajouté l’autorisation pour le bucket demo-bucket.
On configure le bucket demo-bucket pour déclencher la fonction Lambda à chaque création d’objet :
awslocal s3api put-bucket-notification-configuration \
--bucket demo-bucket \
--notification-configuration '{
"LambdaFunctionConfigurations": [
{
"LambdaFunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:word-counter",
"Events": ["s3:ObjectCreated:*"]
}
]
}'
On vérifie la configuration du déclencheur :
awslocal s3api get-bucket-notification-configuration \
--bucket demo-bucket
On crée un fichier texte de test avec le contenu suivant:
Bonjour IM2AG.
Ceci est un test avec S3 et Lambda.
La fonction compte les mots, les lignes et les caractères.
Envoyer le fichier dans le bucket S3 d’entrée :
awslocal s3 cp texte.txt s3://demo-bucket/texte.txt
À ce moment, S3 émet un événement ObjectCreated, et la fonction Lambda word-counter est déclenchée automatiquement.
On vérifie le résultat:
awslocal s3 ls s3://results-bucket
awslocal s3 cp s3://results-bucket/texte.txt.wordcount.json .
cat texte.txt.wordcount.json
Exemple de résultat attendu :
{
"source_bucket": "demo-bucket",
"source_key": "texte.txt",
"line_count": 3,
"word_count": 20,
"character_count": 110,
"preview": "Bonjour IM2AG.\nCeci est un test avec S3 et Lambda.\nLa fonction compte les mots, les lignes et les caractères.\n"
}
L’ensemble des services émulés créent leur ressources dans le repertoire /tmp dans le conteneur.
On peut trouver notre fonction lambda dans /tmp/lambda/awslambda-us-east-1-tasks/word-counter-b1596488-6103-46f1-8eb7-0f613232d082/code/lambda_function.py
Résumé et remarques
LocalStack permet de découvrir les principaux concepts du cloud AWS sans créer de ressources réelles sur AWS.
L’outil reproduit localement de nombreux services et constitue un environnement simple de tests pour les travaux pratiques, les démonstrations en cours et l’apprentissage de l’Infrastructure as Code avec Terraform ou OpenTofu.
Bien que LocalStack soit principalement utilisé pour l’apprentissage de l’écosystème AWS, l’outil propose également des fonctionnalités permettant de simuler certains services d’autres fournisseurs cloud comme Azure et Snowflake.