Exécuter DynamoDB Local avec Docker : le guide complet
DynamoDB Local est l'émulation téléchargeable de DynamoDB par AWS, dans un seul processus — même API, pas de compte AWS, pas de réseau, pas de facture par requête. Utilise-le pour le développement local et les tests d'intégration, puis pointe le même code vers le cloud en production. Il ignore le débit provisionné et ne ralentit jamais, il ne peut donc pas remplacer un test de charge ou de limites.
Comment exécuter DynamoDB Local avec Docker ?
Exécute docker run -p 8000:8000 amazon/dynamodb-local pour démarrer l'image officielle,
qui expose le moteur DynamoDB sur http://localhost:8000. Pointe ton SDK AWS
ou ta CLI vers cet endpoint avec n'importe quelles fausses informations d'identification, puis crée des tables et exécute des
requêtes exactement comme tu le ferais avec le cloud. Ajoute -sharedDb et un volume
-dbPath monté pour conserver les données entre les redémarrages.
Démarrer le conteneur
docker run -p 8000:8000 amazon/dynamodb-localCela expose le moteur sur http://localhost:8000.
docker-compose
La plupart des projets l'épinglent dans docker-compose.yml pour que toute l'équipe obtienne le même
endpoint :
services:
dynamodb:
image: amazon/dynamodb-local
user: root
command: '-jar DynamoDBLocal.jar -sharedDb -dbPath /data'
ports:
- '8000:8000'
volumes:
- dynamodb-data:/data
volumes:
dynamodb-data:L'image s'exécute sous l'utilisateur non-root dynamodblocal, qui ne peut pas ouvrir un
fichier de base de données à l'intérieur du volume nommé appartenant à root — sans user: root, tu tombes sur
SQLiteException [14] unable to open database file et chaque appel se bloque.
Persistance
Par défaut, DynamoDB Local est en mémoire — chaque table disparaît à l'arrêt du conteneur. Deux options la rendent durable :
-sharedDbmaintient tous les clients sur un seul fichier de base de données partagé (sans elle, chaque jeu d'informations d'identification/région obtient sa propre base isolée — une surprise fréquente du type « où est passée ma table ? »).-dbPath /data+ un volume monté écrit ce fichier sur le disque, pour que les données survivent àdocker compose down.
Pointer le SDK vers lui
Seul l'endpoint change — les informations d'identification peuvent être n'importe quelles fausses valeurs :
import {DynamoDBClient} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({
endpoint: 'http://localhost:8000',
region: 'local',
credentials: {accessKeyId: 'x', secretAccessKey: 'x'}
});Créer une table
aws dynamodb create-table \
--endpoint-url http://localhost:8000 \
--table-name AppData \
--attribute-definitions AttributeName=PK,AttributeType=S AttributeName=SK,AttributeType=S \
--key-schema AttributeName=PK,KeyType=HASH AttributeName=SK,KeyType=RANGE \
--billing-mode PAY_PER_REQUESTUn schéma PK/SK single-table comme celui-ci est une bonne
valeur par défaut. Quand tu charges des fixtures, convertis du JSON brut au format wire avec le
convertisseur DynamoDB-JSON.
Vérifie que le conteneur est en marche et que la table a bien été créée :
aws dynamodb list-tables --endpoint-url http://localhost:8000Parcourir avec une interface graphique
Les appels CLI deviennent vite fastidieux. Les options habituelles sont l'interface web open source dynamodb-admin
ou un client de bureau. DynoTable se connecte directement à
localhost:8000 (ou à n'importe quel endpoint LocalStack — voir
se connecter à DynamoDB Local et LocalStack)
et te permet de parcourir, d'interroger avec le et d'éditer des tables locales avec la
même interface que celle que tu utilises pour les tables cloud — sans allers-retours avec la CLI aws.
Ce que Local n'émule pas
Traite Local comme une couche de compatibilité API, pas un simulateur de capacité. Il ignore le débit provisionné, ne renvoie jamais
ProvisionedThroughputExceededException,
et ne modélise pas le comportement de burst on-demand. Un test de charge contre Local ne te dit rien sur les limites de partition ou la capacité adaptative dans AWS.
D'autres écarts apparaissent dans les tests d'intégration si tu ne les anticipes pas :
| Comportement | DynamoDB Local | AWS DynamoDB |
|---|---|---|
| Facturation / RCU / WCU | Aucune | Mesurée par requête |
| Throttling | Jamais | Oui, aux limites table/index |
| Timing de suppression TTL | Best-effort, pas lié à un SLA | Balayages d'arrière-plan selon le planning AWS |
| Livraison DynamoDB Streams | Simplifiée | Sémantique stream complète + câblage Lambda |
| Transactions cross-tables | Supportées dans les builds récents | ACID complet avec limites documentées |
| Global Tables / PITR | Non disponibles | Fonctionnalités de production |
Si ton test affirme du throttling, l'expiration TTL en quelques secondes, ou le fan-out de streams, lance au moins une suite contre une table cloud jetable ou LocalStack avec les fonctionnalités dont tu as besoin activées.
Un workflow local pratique
La plupart des équipes câblent Local en trois couches :
- Tests unitaires — lance le conteneur en CI, crée les tables dans
beforeAll, démonte dansafterAll. Garde les fixtures petites ; marshalle le JSON ordinaire via le convertisseur DynamoDB JSON quand les tests collent des maps d'attributs à la main. - Tests d'intégration — exerce la même factory de client SDK que ton app utilise, en ne swapant que
endpointet credentials. Affirme sur la forme d'item et les écritures conditionnelles, pas sur la capacité consommée (Local ne renvoie pas deConsumedCapacitysignificatif pour budgéter). - Exploration manuelle — connecte DynoTable avec un profil Local, prépare des éditions, et lance des requêtes PartiQL ou à condition de clé avant de déployer des changements de schéma.
Quand tu dépasses un seul processus — plusieurs services, triggers S3, ou routage façon IAM — passe à LocalStack ou un compte de dev. Local reste la boucle la plus rapide pour « mon mode d'accès compile-t-il ? ».
Seeder des données sans marshalling à la main
Charger dix items de fixture depuis un fichier JSON est plus rapide quand tu ne tags pas chaque valeur toi-même. Colle le tableau dans le
convertisseur DynamoDB JSON, copie la sortie marshallée, et batch-write avec BatchWriteItem contre --endpoint-url http://localhost:8000. Pour des fixtures riches en updates, assemble l'UpdateExpression dans le
DynamoDB expression builder et colle les maps d'attributs générées dans ton harness de test.
L'éditeur d'item de DynoTable fait le même marshalling au commit — utile quand un échec de test te laisse regarder des blobs bruts {"S":...} dans la CLI.
Quand quitter Local
Passe à une vraie table quand tu as besoin de l'un des éléments suivants mesuré sur AWS lui-même :
- Planification de capacité — un item de 1 Ko interrogé 1 000 fois par seconde consomme environ 250 RCU/s à cohérence à terme en facturation on-demand ; Local rapporte zéro. Modélise ça avec le calculateur de tarifs en utilisant les tailles du calculateur de taille d'item.
- Lag de propagation d'index — les lectures GSI sont à cohérence à terme en production ; Local renvoie les lignes d'index assez vite pour que les bugs de lecture périmée se cachent jusqu'au déploiement.
- IAM cross-compte — les rôles scopés aux ressources et les clés de condition n'existent que dans le cloud.
Garde Local pour le feedback rapide sur le schéma et la syntaxe d'expression ; valide les hypothèses de coût et de cohérence contre une table de staging avant le trafic de production.
Pièges à scripter autour
-sharedDboublié — chaque paire de credentials unique obtient une base isolée ; la CI et ton laptop ont l'air d'univers différents.- Volume appartenant à root sans
user: root— le backend SQLite échoue en silence jusqu'à ce que tu ajoutes l'override compose de la section ci-dessus. - Supposer la parité Streams — les Lambdas activées sur stream ont besoin d'une cible cloud ou LocalStack ; Local seul n'exercera pas le fan-out.
- Clés en chaîne vide — autorisées sur les attributs non-clés depuis 2020, toujours rejetées sur les clés ; valide les fixtures comme tu le ferais dans AWS.
Télécharge DynoTable, ajoute un profil pointé sur http://localhost:8000, et parcours les tables que tu viens de créer — la même grille, le même constructeur de filtres et le SQL Workbench que tu utilises en production, avec zéro dépense AWS sur la boucle.