lección 2
Instalar LocalStack y levantar Step Functions en local
Configura LocalStack con Docker para emular AWS Step Functions en tu máquina sin coste ni cuenta de AWS.
⏱ 55 min
### ¿Por qué necesitamos LocalStack?
AWS Step Functions es un servicio de Amazon Web Services que cuesta dinero real usar en la nube. Cada transición de estado cuesta $0.025 por cada 1.000 transiciones. Hay un nivel gratuito de 4.000 transiciones al mes — el Hello World de esta lección son 3 transiciones, así que en AWS de verdad también sería gratis. Pero el motivo bueno para LocalStack no es el céntimo: es no necesitar cuenta de AWS, ni tarjeta, ni acordarse de apagar nada.
LocalStack es una herramienta open source que emula los servicios de AWS en tu máquina local usando Docker. Es como tener un "mini AWS" en tu portátil. Puedes crear máquinas de estado, buckets S3, funciones Lambda — todo gratis, todo local, todo desechable. Si la lías, solo tienes que parar y reiniciar el contenedor.
LocalStack es la herramienta que me habría ahorrado cientos de euros cuando empecé con AWS. En mis primeros meses dejé un cluster EMR corriendo un fin de semana y el lunes tenía una factura de $200. Con LocalStack practicas sin riesgo financiero alguno.
### Paso 1: Levantar la pila de LocalStack
En la sección anterior (Cloud AWS, lección 2) ya montaste un docker-compose.yml con LocalStack y configuraste el AWS CLI. Vamos a reutilizar esa misma pila — ya tiene Step Functions habilitado. Entra en la carpeta donde la creaste y levántala:
1# Entra en la carpeta de la seccion anterior2cd aws-localstack-lab34# Levanta la pila (si no esta ya corriendo)5docker compose up -d67# Verifica que el contenedor esta arrancado8docker ps | grep localstack
Si ya la tenias levantada, docker compose up -d no hace nada (es idempotente)
1# En PowerShell (Windows):2cd aws-localstack-lab3docker compose up -d4docker ps | Select-String localstack
Equivalente en PowerShell — Select-String sustituye a grep
La imagen esta clavada en localstack/localstack:3.5 a proposito, y no es solo higiene. Desde la version 2026.03.0 (23 de marzo de 2026) LocalStack no arranca sin una cuenta y un token (LOCALSTACK_AUTH_TOKEN). El token del plan Hobby es gratis para uso no comercial, pero exige registrarse. Las etiquetas anteriores a esa fecha — como la 3.5 — siguen descargandose sin cuenta. Por eso usamos esa y no :latest.
### Paso 2: Verificar que Step Functions responde
El contenedor tarda 15-30 segundos en arrancar todos los servicios. Antes de seguir, comprueba que Step Functions esta operativo:
1# Comprobar que el servicio responde (espera 15-30s tras docker compose up)2aws stepfunctions list-state-machines \3 --endpoint-url http://localhost:456645# Respuesta esperada (lista vacia, porque aun no has creado nada):6# {7# "stateMachines": []8# }
Si ves {"stateMachines": []}, Step Functions esta funcionando
### Troubleshooting: los tres errores que vas a ver
- 01."Could not connect to the endpoint URL: http://localhost:4566/" — el contenedor aun esta arrancando (tarda 15-30s). Espera y repite. Si sigue despues de un minuto, comprueba con docker ps que el contenedor existe.
- 02."Bind for 0.0.0.0:4566 failed: port is already allocated" — tienes otra instancia de LocalStack (o algo mas) ocupando el puerto. Busca con docker ps y baja la otra pila con docker compose down en su carpeta.
- 03."Unable to locate credentials" — no has configurado el AWS CLI. Ejecuta aws configure con las credenciales dummy (test/test, region eu-west-1) como hiciste en la S14 L02.
### Amazon States Language (ASL): el lenguaje de las maquinas de estado
Las maquinas de estado de Step Functions se definen en un lenguaje con nombre propio: Amazon States Language (ASL). Es un JSON con una estructura fija: un campo StartAt que dice por donde empieza, y un objeto States con los estados. Lo que vas a escribir a continuacion — StartAt, States, Type, Next, End — es ASL, y es el mismo tanto en AWS como en LocalStack. Lo que aprendes aqui es portable.
### Paso 3: Tu primera maquina de estado (Hello World)
Vamos a crear la maquina de estado mas simple posible: un solo paso que devuelve un mensaje. Esto confirma que todo el flujo funciona — crear, ejecutar, ver resultado.
1# Crear archivo hello-world.json con la definicion2cat > hello-world.json << 'EOF'3{4 "Comment": "Mi primera maquina de estado",5 "StartAt": "Saludar",6 "States": {7 "Saludar": {8 "Type": "Pass",9 "Result": {"mensaje": "Hola desde Step Functions en local"},10 "End": true11 }12 }13}14EOF
Un unico estado tipo Pass — no ejecuta codigo, solo devuelve un resultado fijo
1# En PowerShell (Windows), no hay heredoc. Escribe el JSON con Set-Content:2Set-Content hello-world.json '{3 "Comment": "Mi primera maquina de estado",4 "StartAt": "Saludar",5 "States": {6 "Saludar": {7 "Type": "Pass",8 "Result": {"mensaje": "Hola desde Step Functions en local"},9 "End": true10 }11 }12}'
Equivalente en PowerShell — Set-Content sustituye al heredoc
1# Crear la maquina de estado en LocalStack y guardar el ARN2SM_ARN=$(aws stepfunctions create-state-machine \3 --name "HelloWorldMachine" \4 --definition file://hello-world.json \5 --role-arn "arn:aws:iam::000000000000:role/DummyRole" \6 --endpoint-url http://localhost:4566 \7 --query 'stateMachineArn' --output text)89echo "ARN de la maquina: $SM_ARN"10# -> arn:aws:states:eu-west-1:000000000000:stateMachine:HelloWorldMachine
El role-arn es ficticio — LocalStack no valida permisos IAM en el plan Hobby
1# En PowerShell:2$SM_ARN = (aws stepfunctions create-state-machine `3 --name "HelloWorldMachine" `4 --definition file://hello-world.json `5 --role-arn "arn:aws:iam::000000000000:role/DummyRole" `6 --endpoint-url http://localhost:4566 `7 --query 'stateMachineArn' --output text)89Write-Host "ARN de la maquina: $SM_ARN"
En PowerShell el backtick sustituye a la barra invertida para partir lineas
### Paso 4: Ejecutar y ver el resultado
1# Ejecutar la maquina de estado2EXEC_ARN=$(aws stepfunctions start-execution \3 --state-machine-arn "$SM_ARN" \4 --input '{"nombre": "Alumno"}' \5 --endpoint-url http://localhost:4566 \6 --query 'executionArn' --output text)78echo "ARN de la ejecucion: $EXEC_ARN"
start-execution lanza la maquina y devuelve un ARN de ejecucion unico
1# Ver el resultado de la ejecucion2aws stepfunctions describe-execution \3 --execution-arn "$EXEC_ARN" \4 --endpoint-url http://localhost:4566 \5 --query '[status, output]' --output text67# Resultado esperado:8# SUCCEEDED {"mensaje":"Hola desde Step Functions en local"}
--query extrae solo status y output, sin el JSON completo
Si perdiste el ARN de la ejecucion, recuperalo con list-executions:
1# Listar ejecuciones de una maquina2aws stepfunctions list-executions \3 --state-machine-arn "$SM_ARN" \4 --endpoint-url http://localhost:4566
Devuelve todas las ejecuciones con su ARN, estado y fecha
### Paso 5: El historial — ver que hizo cada estado
describe-execution te da el resultado final, pero no te dice que paso por dentro. Para eso esta get-execution-history: lista cada evento de la ejecucion, estado por estado.
1# Ver el historial evento por evento2aws stepfunctions get-execution-history \3 --execution-arn "$EXEC_ARN" \4 --endpoint-url http://localhost:4566 \5 --query 'events[].[id, type, stateEnteredEventDetails.name]' \6 --output table
El historial es tu herramienta de debugging principal para Step Functions
### La regla de Result: machaca la entrada
Una cosa que no es obvia y que te va a morder: cuando un estado Pass tiene un campo Result, ese resultado SUSTITUYE lo que recibia como entrada. No se mezcla, no se aniade — se machaca. En el Hello World no importa porque solo hay un estado. Pero en cuanto encadenes dos estados (como en el ejercicio de abajo), el segundo no va a ver lo que hizo el primero: solo ve su propio Result.
Cuando necesites que un estado ANADA su resultado a la entrada sin machacarla, usaras ResultPath — un campo que dice "pon mi resultado aqui dentro del JSON de entrada, en vez de sustituirlo". Lo veras en la siguiente leccion.
### Persistencia: por que tu maquina desaparece al reiniciar
Si haces docker compose down y vuelves a hacer docker compose up, tu HelloWorldMachine ya no estara. Eso es normal: la persistencia entre reinicios es una funcion de pago de LocalStack (plan Base, $39/mes). En el plan gratuito (Hobby), cada reinicio empieza de cero.
No es un problema: es la costumbre correcta. Ten un script que vuelva a crear lo que necesites:
1# crear-maquinas.sh — recrea la infraestructura de cero2set -e3aws stepfunctions create-state-machine \4 --name HelloWorldMachine \5 --definition file://hello-world.json \6 --role-arn "arn:aws:iam::000000000000:role/DummyRole" \7 --endpoint-url http://localhost:45668echo "Maquinas creadas"
Infraestructura como codigo: si se puede recrear con un script, no necesita guardarse
### Resumen: que acabas de hacer
- Levantaste la pila de LocalStack que montaste en la seccion anterior (reutilizas, no duplicas).
- Verificaste que Step Functions responde con list-state-machines.
- Creaste tu primera maquina de estado con un Pass que devuelve un mensaje.
- La ejecutaste y viste el resultado con describe-execution y --query.
- Aprendiste a consultar el historial con get-execution-history.
- Entendiste que Result machaca la entrada y que la persistencia es de pago.
A partir de ahora, cada vez que quieras practicar solo necesitas docker compose up -d en la carpeta de la S14 y ya tienes Step Functions disponible. Cuando termines, docker compose down para liberar recursos.
Guarda los ARN en variables de entorno. Un ARN copiado a mano es un ARN que un dia copiaras mal. export SM_ARN="..." despues de cada create, y $SM_ARN en cada comando posterior.
## ejercicios
Verificar que LocalStack esta funcionando
Escribe los comandos para verificar que LocalStack esta arrancado y que Step Functions responde. Verifica en tres niveles: contenedor, servicio y API.
Crear una maquina de estado con dos pasos
Crea un archivo JSON que defina una maquina de estado con dos estados Pass encadenados: "Inicio" que pasa al estado "Fin". Luego creala en LocalStack y ejecutala.
Escribir un docker-compose.yml de LocalStack de memoria
Sin mirar la leccion, escribe un docker-compose.yml que levante LocalStack con los servicios stepfunctions y s3 habilitados. Solo lo que necesitas, nada mas.
Hacer que la maquina de dos pasos devuelva AMBOS resultados
Tu maquina de dos pasos (Inicio -> Fin) devuelve solo {"paso": 2}. El {"paso": 1} de Inicio se pierde porque Result machaca. Modifica la definicion para que el resultado final contenga los dos: {"primero": {"paso": 1}, "segundo": {"paso": 2}}.
Regístrate para guardar tu progreso.
## comentarios
Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.
Inicia sesión para comentar y responder.
cargando comentarios...