Tema 3 · 7 · DynamoDB: tabla Usuarios, CLI, Python y exportar/importar con S3
Presentación del Tema 3: «Creación de base de datos DynamoDB», «Acceso desde AWS CLI», «Ejemplo aplicaciones uso DynamoDB – Ejercicio 1» (Python: dynamodb-cli.py) y «Ejercicio 3» (exportar e importar con S3). Duración: unos 10 minutos con dynamodb-cli.py y unos 10 minutos más (casi todo espera) con S3: ~2,5 min la exportación y ~3 min la importación, incluso con 7 ítems (medido). Coste: con tablas pequeñas, céntimos; PITR cuesta 0,21 USD por GB-mes mientras esté activo.
¿Dudas con un script? Todos los scripts de esta carpeta traen su propia ayuda:
python3 dynamodb-cli.py --ayuda(también vale--helpo-h) explica los pasos y las opciones. EsteREADME.mdes el paso a paso de la actividad: tenlo a mano y consúltalo antes de preguntar.
Etiquetas de lo que creas. Todo recurso que crees a mano (máquina, volumen, bucket, base de datos, tabla, función...) ponle estas etiquetas, al crearlo (apartado Tags / Etiquetas) o después desde su pestaña de etiquetas:
curso=G214,universidad=CUNEFyactividad=03.07-dynamodbcli. Si algún día hay que borrar recursos a mano, se localizan todos de golpe conaws resourcegroupstaggingapi get-resources --region eu-north-1 --tag-filters Key=actividad,Values=03.07-dynamodbcli. Más detalle (cómo etiquetar con la CLI, cómo buscar y qué hacer en una emergencia): README principal, sección «Etiquetas».
Qué vas a hacer
Vas a trabajar con una base no relacional, Amazon DynamoDB: crear la tabla Usuarios (consola o CLI), leer y escribir ítems con la AWS CLI y con un script de Python (boto3) desde CloudShell, y por último exportar la tabla a S3 y reimportarla en una tabla nueva.
CloudShell ──aws dynamodb ... / dynamodb-cli.py──> tabla Usuarios (UserID, String)
tabla Usuarios ──export (PITR)──> S3 (AWSDynamoDB/<código>/data/*.json.gz) ──import──> tabla nueva
Qué se crea en AWS: la tabla Usuarios (modo on-demand), opcionalmente un bucket de S3, la exportación a S3 (carpeta AWSDynamoDB/), una tabla nueva al importar y un grupo de logs /aws-dynamodb/imports. dynamodb-cli.py en sí no crea nada: lee o escribe un ítem en una tabla que ya existe.
Qué contiene esta carpeta
| Fichero | Para qué sirve | En qué paso se usa |
|---|---|---|
dynamodb-cli.py |
Script de Python con boto3 para leer o escribir UN ítem en DynamoDB desde la terminal |
Pasos 4 a 6 |
README.md |
Esta guía (incluye los comandos de la AWS CLI y de la exportación/importación) | Siempre |
Antes de empezar
- [ ] Cuenta de AWS propia, región de la consola
eu-north-1elegida ANTES de abrir CloudShell (CloudShell trabaja en la región de la consola). - [ ] Sabes abrir AWS CloudShell (el icono
>_de la barra superior): terminal Linux en el navegador con la AWS CLI,unzip,nanoy Python 3. - [ ] La tabla
Usuarioscon clave de particiónUserID(String) eneu-north-1(el paso 1 la crea por CLI). Esta actividad no necesita la RDS ni Adminer.
Comprobación previa en CloudShell:
aws sts get-caller-identity
echo "$AWS_REGION"
Qué verás: un JSON con tu cuenta y eu-north-1. Si imprime otra región, cierra CloudShell, cambia la región de la consola a Estocolmo y ábrelo de nuevo.
Cómo llevar los ficheros a donde toque
Se hace en CloudShell, porque necesita credenciales de AWS.
- En tu PC, comprime esta carpeta (clic derecho sobre
03.07-dynamodbcli> Comprimir en archivo ZIP, o Enviar a > Carpeta comprimida en zip en Windows 10). Obtienes03.07-dynamodbcli.zip. - En la consola de AWS (región
eu-north-1) abre CloudShell, pulsa Actions > Upload file y sube el zip. - Descomprime y deja el script listo:
unzip -o 03.07-dynamodbcli.zip && cd 03.07-dynamodbcli && chmod -R u+rwX .
sed -i 's/\r$//' *.py
chmod +x *.py
ls
Si ya subiste
g214-materiales.zip(README principal), no necesitas este zip: entra concd ~/g214-materiales/tema3/03.07-dynamodbcliy, si algún fichero daPermission denied, ejecuta allíchmod -R u+rwX . && chmod +x *.py.
sed quita los finales de línea de Windows (si no, bash falla con bad interpreter o $'\r': command not found) y chmod +x da permiso de ejecución (un zip creado en Windows no lo conserva; sin él, ./dynamodb-cli.py da Permission denied). Qué verás: ls muestra README.md y dynamodb-cli.py.
Alternativa para subir solo el script: Actions > Upload file y elige dynamodb-cli.py, y luego sed -i 's/\r$//' dynamodb-cli.py && chmod +x dynamodb-cli.py. Si cierras CloudShell, al volver entra con cd 03.07-dynamodbcli (si no encuentras la carpeta, vuelve a subir el zip).
Paso a paso
Paso 1. Crear la tabla Usuarios. En la presentación se crea desde la consola. El mismo resultado por CLI, en CloudShell:
aws dynamodb create-table --table-name Usuarios \
--attribute-definitions AttributeName=UserID,AttributeType=S \
--key-schema AttributeName=UserID,KeyType=HASH \
--billing-mode PAY_PER_REQUEST --region eu-north-1
aws dynamodb wait table-exists --table-name Usuarios --region eu-north-1
Qué verás: TableStatus: CREATING y, tras wait (unos 25 s), la tabla ACTIVE en modo PAY_PER_REQUEST (on-demand). La consola, con Use default settings, puede elegir otro modo de capacidad; para el laboratorio da igual. Los tres ítems de la presentación (u001 a u003) se añaden con put-item o desde la consola. Modo de capacidad: aprovisionado (reservas lecturas y escrituras por segundo y las pagas aunque no las uses) o bajo demanda, PAY_PER_REQUEST (pagas solo por petición); para el laboratorio vale cualquiera.
Paso 2. Búsqueda en la consola. Resultado esperado del Scan con filtro UserID = u001 sobre los tres ítems: Items returned 1, Items scanned 3, RCUs consumed 2 y Efficiency 33,33 %; con Query solo se lee el ítem pedido.
Paso 3. Comandos aws dynamodb ... de la presentación. Resultados medidos: get-item de un ítem pequeño consume 0.5 unidades de lectura (1.0 con --consistent-read); query por clave, 0.5; scan de la tabla, 2.0 (también con 3 ó 7 ítems: cuesta 0,5 por cada partición de la tabla) y sin cambio con --projection-expression (la proyección reduce los datos devueltos, no el consumo). Límites que conviene saber: un ítem pesa como máximo 400 KB y batch-write-item admite 25 ítems por llamada. Dos consejos, porque esos comandos no llevan --region:
- Usan la región de tu CloudShell. Si tu tabla está en
eu-north-1y CloudShell en otra,list-tablessaldrá vacío o dará tabla no encontrada: compruebaecho "$AWS_REGION"o añade--region eu-north-1. - Para contar los ítems de una tabla no te fíes del contador del resumen de la consola (se actualiza cada varias horas; da 0 al principio). Cuenta con
aws dynamodb scan --table-name Usuarios --select COUNT --region eu-north-1: el campoCountde la respuesta es el número de ítems.
Paso 4. Comprobar boto3.
python3 -c "import boto3; print(boto3.__version__)"
Qué verás: un número de versión. Si sale ModuleNotFoundError: No module named 'boto3', instálalo con pip3 install --user boto3. Si en una máquina Amazon Linux 2023 limpia el sistema responde pip3: command not found, instala pip primero (sudo dnf install -y python3-pip) y repite pip3 install --user boto3. Un aviso PythonDeprecationWarning sobre Python 3.9 es normal y no impide que el script funcione (dynamodb-cli.py ya lo silencia). La presentación solo dicen «sube el fichero, chmod +x y ejecuta»: si falla con Falta la libreria boto3, es esto. En CloudShell no suele hacer falta nada de esto (no se ha podido comprobar en un CloudShell real: si algo falla, avisa).
Opciones de dynamodb-cli.py:
| Opción | Qué hace | Por defecto |
|---|---|---|
--mode get |
Lee un ítem por UserID (no interactivo) |
Sin --mode, el script pregunta qué hacer |
--mode put |
Crea o actualiza un ítem. Aun así te pregunta los datos por teclado | |
--userid U |
Valor de la clave a consultar en modo get (se llama --userid aunque tu clave tenga otro nombre) |
u001, que solo vale con clave de texto: con --key-type Number indica siempre el valor |
--table T |
Nombre de la tabla (distingue mayúsculas) | Usuarios |
--region R |
Región de la tabla | eu-north-1 (no la de CloudShell) |
--key-name N |
Nombre de la clave de partición de la tabla (distingue mayúsculas) | UserID |
--key-type String|Number |
Tipo de esa clave | String |
--quiet |
Quita los mensajes [INFO] |
Con mensajes |
-h, --help |
Muestra ayuda y «Uso rápido» |
Paso 5. Leer un ítem.
./dynamodb-cli.py --mode get --userid u001
Qué verás (en la salida real, las líneas de resultado llevan un icono delante y el orden de los atributos puede variar):
[INFO] Inicializando recurso DynamoDB en región eu-north-1…
[INFO] Consultando tabla 'Usuarios' con ConsistentRead=True…
[INFO] Key = {'UserID': 'u001'}
Se encontró el usuario con UserID='u001':
{
"UserID": "u001",
"Nombre": "Elena",
...
}
Si el UserID no existe: Conexión correcta, pero no existe UserID='...'. (código de salida 1). Si hay un error de AWS: Error al conectar o consultar DynamoDB: y el mensaje de AWS (código 2). Si no hay credenciales (por ejemplo, lo ejecutas en tu PC sin aws configure), el script dice No hay credenciales de AWS validas para este script y cómo arreglarlo (código 2). El código de salida se ve con echo $? justo después. Añade --quiet para ocultar las líneas [INFO].
Sin argumentos, ./dynamodb-cli.py pregunta: Seleccione modo: con 1) GET y 2) PUT (Opción [1/2, ENTER=1]); con GET pide UserID a consultar [ENTER = u001]. Con Enter en ambas preguntas lee u001.
Con una tabla de clave numérica (por ejemplo users con id numérica, la de la Práctica 2) hay que decírselo; si no, DynamoDB responde The provided key element does not match the schema:
./dynamodb-cli.py --mode get --userid 1002 --table users --key-name id --key-type Number
Qué verás: igual que arriba, con [INFO] Key = {'id': 1002} y Se encontró el usuario con id='1002': seguido del ítem. Si escribes algo que no es un número en --userid con --key-type Number, el script responde Clave no valida para el tipo Number: No es un número válido. (código de salida 2).
Paso 6. Escribir un ítem.
./dynamodb-cli.py --mode put
El script te guía: primero la clave (UserID por defecto; obligatoria y de tipo String, salvo que uses --key-type Number) y luego atributos, de uno en uno, con su nombre, su tipo (String, Number o Boolean) y su valor. Un Enter en Nombre atributo termina. Ejemplo con un usuario de prueba u900 (no es ninguno de los que te pide la presentación):
UserID (obligatorio, String): u900
Nombre atributo (ENTER para terminar): Nombre
Tipo [String/Number/Boolean]: String
Valor para 'Nombre' (String): Prueba
Nombre atributo (ENTER para terminar): Edad
Tipo [String/Number/Boolean]: Number
Valor para 'Edad' (Number): 30
Nombre atributo (ENTER para terminar):
Qué verás al terminar: Petición que se va a ejecutar (CLI): seguido del comando equivalente de la AWS CLI, por ejemplo:
aws dynamodb put-item --table-name Usuarios --region eu-north-1 --item '{"UserID": {"S": "u900"}, "Nombre": {"S": "Prueba"}, "Edad": {"N": "30"}}'
y después [INFO] con Enviando put_item a 'Usuarios'… y Item creado/actualizado correctamente. Fíjate en cómo viaja cada tipo (S, N, BOOL): es lo que explica la presentación.
Reglas del script:
- Cada ejecución crea o actualiza UN solo ítem. Para varios usuarios, ejecútalo varias veces.
- Si el
UserIDya existe,put_itemreemplaza el ítem entero: los atributos que no vuelvas a escribir se pierden (no se fusionan). - El tipo hay que escribirlo tal cual:
String,NumberoBoolean(da igual mayúsculas o minúsculas).Numberusa punto decimal (1.5, no1,5).Booleanaceptatrue,false,1,0,si,sí,no,y,n. UnStringno puede estar vacío. No se puede repetir el nombre de la clave como atributo. - Otra tabla o región:
./dynamodb-cli.py --mode get --userid u001 --table <NombreTabla> --region eu-north-1. Si la clave de partición de esa tabla no esUserIDde tipo String, añade--key-name <nombre>y--key-type StringoNumbersegún su tipo.
Paso 7. Comprobar con la AWS CLI y borrar la prueba.
aws dynamodb get-item --table-name Usuarios --key '{"UserID":{"S":"u900"}}' --region eu-north-1
aws dynamodb delete-item --table-name Usuarios --key '{"UserID":{"S":"u900"}}' --region eu-north-1
Qué verás: el primer comando devuelve un JSON con Item y cada valor con su tipo; el segundo no imprime nada. Si solo querías probar el script, borra así tu ítem de prueba. También puedes verlo en la consola de DynamoDB (tabla > Explore table items) o en el visor de 03.08.
Paso 8. Exportar e importar con S3 (ejercicio 3 de DynamoDB). Se hace en la consola (la presentación tiene el paso a paso); aquí tienes lo que no cuentan las diapositivas. En la presentación, el ejercicio 2 (visor web, actividad 03.08) va antes que este: si quieres seguir ese orden exacto, haz 03.08 antes de este paso (si no, el Count será 7 en vez de 8; ver «Comprobar»).
- Bucket: necesitas uno en la misma región que la tabla (
eu-north-1). Si no lo tienes, créalo (por ejemploaws s3 mb s3://<nombre-unico> --region eu-north-1). - PITR: la exportación completa necesita Point-in-time recovery activado en la tabla (pestaña Backups); sin él, la consola o la CLI responden
PointInTimeRecoveryUnavailableException. Activarlo tarda segundos, cuesta 0,21 USD por GB-mes y queda activo mientras exista la tabla (o hasta desactivarlo, ver Limpieza). - Tiempos medidos: la exportación tarda unos 2,5 minutos y la importación unos 3, incluso con 7 ítems.
- Resultado: en el bucket aparece
AWSDynamoDB/<código>/data/con un fichero.json.gzpor partición de la tabla (en una tabla pequeña son 4, y alguno está vacío; no es un error) más los ficherosmanifest-*. La importación (carpetadata/, compresiónGZIP, formatoDynamoDB JSON, partition keyUserIDde tipo String) crea una tabla nueva con los mismos ítems; importar sobre una tabla existente daTable already exists. - Comprobar:
aws dynamodb scan --table-name <tabla-nueva> --select COUNT --region eu-north-1debe dar el mismoCountque la original en ese momento: compáralo conaws dynamodb scan --table-name Usuarios --select COUNT --region eu-north-1. Si has seguido las diapositivas en orden son 8 ítems: 3 (u001 a u003) + 1 (u020) + 3 (u010 a u012) + 1 (el registro que añades en el ejercicio 2, con el visor de 03.08) = 8; serían 7 si no añadiste el del ejercicio 2. No es una pérdida de datos de la importación si coincide con elCountdeUsuarios. No uses elItemCountde la consola: tarda horas en actualizarse (da 0 al principio). - Por CLI (si prefieres no usar la consola; sustituye
<bucket>y<código>; el ARN de la tabla lo daaws dynamodb describe-table --table-name Usuarios --query Table.TableArn --output text --region eu-north-1):
aws dynamodb update-continuous-backups --table-name Usuarios --region eu-north-1 --point-in-time-recovery-specification PointInTimeRecoveryEnabled=true
aws dynamodb export-table-to-point-in-time --table-arn <ARN-de-Usuarios> --s3-bucket <bucket> --export-format DYNAMODB_JSON --region eu-north-1
aws dynamodb list-exports --region eu-north-1 # ExportStatus COMPLETED al cabo de ~2,5 min
aws s3 ls s3://<bucket>/AWSDynamoDB/ --recursive # el código de la carpeta
aws dynamodb import-table --region eu-north-1 --s3-bucket-source S3Bucket=<bucket>,S3KeyPrefix=AWSDynamoDB/<código>/data/ --input-format DYNAMODB_JSON --input-compression-type GZIP --table-creation-parameters '{"TableName":"Usuarios-copia","AttributeDefinitions":[{"AttributeName":"UserID","AttributeType":"S"}],"KeySchema":[{"AttributeName":"UserID","KeyType":"HASH"}],"BillingMode":"PAY_PER_REQUEST"}'
aws dynamodb list-imports --region eu-north-1 # ImportStatus COMPLETED al cabo de ~3 min
Son los mismos pasos que la consola. import-table crea siempre una tabla nueva; si ImportStatus queda en FAILED, mira ItemValidationError y borra la tabla vacía que queda.
- Si la importación falla (por ejemplo, por escribir mal el nombre de la partition key): el estado queda en
FAILEDconItemValidationError, el detalle está en CloudWatch Logs (grupo/aws-dynamodb/imports,Missing the key ... in the item) y la tabla nueva queda creada y vacía: bórrala.
Errores frecuentes
| Síntoma | Causa | Solución |
|---|---|---|
Permission denied al lanzar ./dynamodb-cli.py |
El script no tiene permiso de ejecución | chmod +x dynamodb-cli.py (o python3 dynamodb-cli.py ...) |
bad interpreter o $'\r': command not found |
Finales de línea de Windows | sed -i 's/\r$//' *.py y repite |
ModuleNotFoundError: No module named 'boto3' (o el mensaje Falta la libreria boto3) |
Falta la librería | pip3 install --user boto3 |
pip3: command not found (Amazon Linux 2023 limpia) |
AL2023 no trae pip | sudo dnf install -y python3-pip y repite pip3 install --user boto3; un PythonDeprecationWarning sobre Python 3.9 es normal |
Error al conectar o consultar DynamoDB: con un mensaje de recurso no encontrado |
La tabla no existe con ese nombre (distingue mayúsculas) o está en otra región. El script usa eu-north-1, no la de CloudShell |
Revisa aws dynamodb list-tables --region eu-north-1 y usa --table y --region |
El mismo error con The provided key element does not match the schema |
La clave de partición de la tabla no se llama UserID o no es String, y no se lo has dicho al script |
Añade --key-name <nombre> y --key-type String o Number, por ejemplo --key-name id --key-type Number |
No hay credenciales de AWS validas para este script |
No hay credenciales: no estás en CloudShell y no has hecho aws configure |
Usa CloudShell, o configura la AWS CLI en tu PC |
list-tables sale vacío con los comandos de la presentación |
Esos comandos no llevan --region y CloudShell está en otra región |
echo "$AWS_REGION" o añade --region eu-north-1 |
En la consola, ItemCount de la tabla marca 0 aunque hayas cargado ítems |
DynamoDB actualiza ese contador cada varias horas | Cuenta con aws dynamodb scan --table-name <tabla> --select COUNT --region eu-north-1 |
scan consume 2.0 y get-item 0.5 con tablas de 3 ítems |
No es un error: el scan cuesta 0,5 por cada partición de la tabla |
Nada que arreglar; es el argumento de coste de la presentación |
PointInTimeRecoveryUnavailableException al exportar |
La tabla no tiene PITR activado | Actívalo (pestaña Backups o update-continuous-backups) y repite |
Table already exists al importar |
Importaste sobre un nombre de tabla que ya existe | Usa un nombre de tabla nuevo |
La importación desde S3 queda en FAILED (ItemValidationError) y aparece una tabla nueva vacía |
El nombre de la partition key de la tabla nueva no es el de los datos exportados (UserID) |
Borra la tabla vacía y repite con UserID; el detalle está en CloudWatch Logs, grupo /aws-dynamodb/imports |
Limpieza
Hazla al terminar el ejercicio (y, en el caso de Usuarios, después de terminar 03.08, que la usa para el visor).
1. Tablas de DynamoDB: Usuarios y la tabla que creaste al importar desde S3 (Usuarios-copia si usaste la CLI).
aws dynamodb list-tables --region eu-north-1
aws dynamodb delete-table --table-name Usuarios --region eu-north-1
Repite delete-table con cada nombre. Si usas la consola y te ofrece crear una copia de seguridad antes de borrar, desmárcala. Si activaste PITR, se desactiva al borrar la tabla; si prefieres conservar la tabla, desactívalo antes: aws dynamodb update-continuous-backups --table-name Usuarios --point-in-time-recovery-specification PointInTimeRecoveryEnabled=false --region eu-north-1 (PITR cuesta 0,21 USD por GB-mes). Una importación fallida deja además una tabla nueva vacía: bórrala también.
2. Logs de la importación (la importación crea un grupo de logs que nadie borra):
aws logs delete-log-group --log-group-name /aws-dynamodb/imports --region eu-north-1
3. S3 de la exportación: en tu bucket, borra la carpeta AWSDynamoDB/ que creó la exportación (consola de S3 > marca la carpeta > Delete, o aws s3 rm s3://<tu-bucket>/AWSDynamoDB/ --recursive). Si creaste el bucket solo para esto, vacíalo y bórralo (aws s3 rb s3://<tu-bucket> --force).
4. Verificación:
aws dynamodb list-tables --region eu-north-1
aws logs describe-log-groups --log-group-name-prefix /aws-dynamodb --region eu-north-1 --query "logGroups[].logGroupName"
Qué debes ver: list-tables sin tus tablas de este tema y ningún grupo de logs /aws-dynamodb/imports.
Cómo sabes que has terminado
- [ ] La tabla
Usuariosexiste con claveUserID(String) y tiene tus ítems. - [ ]
dynamodb-cli.pylee (--mode get) y escribe (--mode put) ítems deUsuarios, y los has comprobado conaws dynamodb get-item. - [ ] Has exportado la tabla a S3, importado en una tabla nueva y el
Countde las dos coincide (8 ítems si seguiste las diapositivas en orden). - [ ] Has hecho la limpieza: tablas, grupo de logs y carpeta
AWSDynamoDB/ya no existen (y PITR no queda activo).
Anterior: 03.06 · ACID y rigidez de esquema · Siguiente: 03.08 · Visor web de DynamoDB