# Desarrolla y prueba aplicaciones AWS Cloud usando LocalStack y Docker


En el desarrollo de aplicaciones moderno, probar las aplicaciones en la nube localmente antes de desplegarlas en un entorno de producción te ayuda a realizar lanzamientos más rápido y con mayor confianza. Este enfoque implica simular servicios de forma local, identificar y corregir problemas de manera temprana y realizar iteraciones rápidas sin incurrir en costos ni enfrentarte a las complejidades de un entorno de nube completo. Herramientas como [LocalStack](https://www.localstack.cloud/) se han vuelto invaluables en este proceso, ya que facilitan la emulación de servicios de AWS y la contenedorización de aplicaciones para entornos de prueba coherentes y aislados. 

En esta guía, aprenderás a:

- Usar Docker para iniciar un contenedor de LocalStack
- Conectarte a LocalStack desde una aplicación no contenedorizada
- Conectarte a LocalStack desde una aplicación contenedorizada

## ¿Qué es LocalStack?

LocalStack es un emulador de servicios en la nube que se ejecuta en un solo contenedor en tu computadora. Proporciona una forma potente, flexible y económica de probar y desarrollar aplicaciones basadas en AWS de forma local. 

## ¿Por qué usar LocalStack?

Simular los servicios de AWS localmente te ayuda a probar cómo interactúa tu aplicación con servicios como S3, Lambda y DynamoDB sin necesidad de conectarte a la nube real de AWS. Puedes realizar iteraciones rápidas en tu desarrollo, evitando el costo y la complejidad de desplegar en la nube durante esta fase.

Al imitar el comportamiento de estos servicios de forma local, LocalStack propicia ciclos de retroalimentación más rápidos. Tu aplicación puede interactuar con APIs externas, pero todo se ejecuta localmente, eliminando la necesidad de lidiar con el aprovisionamiento en la nube o la latencia de red.

Esto facilita la validación de integraciones y la prueba de escenarios basados en la nube sin necesidad de configurar roles o políticas de IAM en un entorno real. Puedes simular arquitecturas de nube complejas localmente y enviar tus cambios a AWS solo cuando estés listo.

## Uso de LocalStack con Docker

La [imagen oficial de Docker para LocalStack](https://hub.docker.com/r/localstack/localstack) proporciona una manera conveniente de ejecutar LocalStack en tu máquina de desarrollo. Es de uso gratuito y no requiere ninguna clave de API para ejecutarse. Incluso puedes usar la [extensión de LocalStack para Docker](https://www.docker.com/blog/develop-your-cloud-app-locally-with-the-localstack-extension/) para interactuar con LocalStack mediante una interfaz gráfica de usuario.

## Requisitos previos

Se requieren los siguientes requisitos previos para seguir esta guía práctica:

- [Docker Desktop](https://www.docker.com/products/docker-desktop/) 
- [Node.js](https://nodejs.org/en/download/package-manager)
- [Python y pip](https://www.python.org/downloads/)
- Conocimiento básico de Docker

## Iniciar LocalStack

Inicia una demostración rápida de LocalStack siguiendo estos pasos:

1. Comienza [clonando una aplicación de ejemplo](https://github.com/dockersamples/todo-list-localstack-docker). Abre la terminal y ejecuta el siguiente comando:

   ```console
   $ git clone https://github.com/dockersamples/todo-list-localstack-docker
   $ cd todo-list-localstack-docker
   ```

2. Iniciar LocalStack

   Ejecuta el siguiente comando para levantar LocalStack.   

   ```console
   $ docker compose -f compose-native.yml up -d
   ```

   Este archivo Compose también incluye especificaciones para una base de datos MongoDB requerida. Puedes verificar que los servicios estén en funcionamiento visitando el panel de Docker Desktop.

   ![Diagrama que muestra los contenedores de LocalStack y MongoDB en funcionamiento en Docker Desktop](/guides/images/launch-localstack.webp)

3. Verifica que LocalStack esté en funcionamiento seleccionando el contenedor y revisando los registros (logs).

   ![Diagrama que muestra los registros del contenedor de LocalStack](/guides/images/localstack-logs.webp)

4. Crear un bucket de Amazon S3 local

   Cuando creas un bucket de S3 local usando LocalStack, básicamente estás simulando la creación de un bucket de S3 en AWS. Esto te ayuda a probar y desarrollar aplicaciones que interactúan con S3 sin necesidad de tener una cuenta de AWS real.

   Para crear un bucket de Amazon S3 local, instala la [`awscli-local` CLI](https://github.com/localstack/awscli-local) en tu sistema. El comando `awslocal` es un envoltorio ligero sobre la interfaz de línea de comandos de AWS para usar con LocalStack. Te ayuda a realizar pruebas y desarrollo en un entorno simulado en tu máquina local sin necesidad de acceder a los servicios reales de AWS.

     ```console
     $ pip install awscli-local
     ```

     Crea un nuevo bucket de S3 dentro del entorno de LocalStack con el siguiente comando:

     ```console
     $ awslocal s3 mb s3://mysamplebucket
     ```

     El comando `s3 mb s3://mysamplebucket` le indica a la CLI de AWS que cree un nuevo bucket de S3 (mb significa `make bucket`) llamado `mysamplebucket`.

     Puedes verificar si el bucket de S3 se ha creado seleccionando el contenedor de LocalStack en el panel de Docker Desktop y viendo los registros. Los registros indicarán que tu entorno de LocalStack está configurado correctamente y que ahora puedes usar `mysamplebucket` para almacenar y recuperar objetos.

     ![Diagrama que muestra los registros de LocalStack que destacan la creación exitosa del bucket de S3](/guides/images/localstack-s3put.webp)

## Uso de LocalStack en el desarrollo

Una vez que te hayas familiarizado con LocalStack, es hora de verlo en acción. En esta demostración, utilizarás una aplicación de ejemplo con un frontend en React y un backend en Node.js. Esta pila de aplicaciones utiliza los siguientes componentes:

- React: Un frontend intuitivo para acceder a la aplicación de lista de tareas (todo-list)
- Node.js: Un backend responsable de manejar las solicitudes HTTP
- MongoDB: Una base de datos para almacenar todos los datos de la lista de tareas
- LocalStack: Emula el servicio Amazon S3 para almacenar y recuperar imágenes

![Diagrama que muestra la pila tecnológica de la aplicación de lista de tareas de ejemplo que incluye LocalStack, servicios de frontend y backend](/guides/localstack/images/localstack-arch.webp)


## Conectarse a LocalStack desde una aplicación no contenedorizada

Es hora de conectar tu aplicación a LocalStack. El archivo `index.js`, ubicado en el directorio backend/, sirve como el punto de entrada principal para la aplicación backend.

El código interactúa con el servicio S3 de LocalStack, al cual se accede a través del endpoint definido por la variable de entorno `S3_ENDPOINT_URL`, típicamente establecida en `http://localhost:4566` para el desarrollo local.

El `S3Client` del SDK de AWS está configurado para usar este endpoint de LocalStack, junto con credenciales de prueba (`AWS_ACCESS_KEY_ID` y `AWS_SECRET_ACCESS_KEY`) que también se obtienen de las variables de entorno. Esta configuración permite que la aplicación realice operaciones en el servicio S3 simulado localmente como si estuviera interactuando con el S3 real de AWS, aportando flexibilidad al código para diferentes entornos.

El código utiliza `multer` y `multer-s3` para manejar las subidas de archivos. Cuando un usuario sube una imagen a través de la ruta /upload, el archivo se almacena directamente en el bucket de S3 simulado por LocalStack. El nombre del bucket se recupera de la variable de entorno `S3_BUCKET_NAME`. A cada archivo subido se le asigna un nombre único agregando la marca de tiempo actual al nombre de archivo original. Luego, la ruta devuelve la URL del archivo subido dentro del servicio S3 local, haciéndolo accesible de la misma manera que si estuviera alojado en un bucket de S3 real de AWS.

Veámoslo en acción. Comienza iniciando el servicio backend de Node.js.

1. Cambia al directorio backend/

   ```console
   $ cd backend/
   ```

2. Instala las dependencias requeridas:
  
   ```console
   $ npm install
   ```

3. Configuración de variables de entorno de AWS

   El archivo `.env` ubicado en el directorio backend/ ya contiene credenciales de marcador de posición (placeholders) y valores de configuración que LocalStack utiliza para emular los servicios de AWS. Las variables `AWS_ACCESS_KEY_ID` y `AWS_SECRET_ACCESS_KEY` son credenciales de marcador de posición, mientras que `S3_BUCKET_NAME` y `S3_ENDPOINT_URL` son configuraciones. No se necesitan cambios, ya que estos valores ya están configurados correctamente para LocalStack.

   > [!TIP]
   >
   > Dado que estás ejecutando MongoDB en un contenedor Docker y la aplicación backend de Node se está ejecutando de forma nativa en tu host, asegúrate de que `MONGODB_URI=mongodb://localhost:27017/todos` esté configurada en tu archivo `.env`.

   ```plaintext
   MONGODB_URI=mongodb://localhost:27017/todos
   AWS_ACCESS_KEY_ID=test
   AWS_SECRET_ACCESS_KEY=test
   S3_BUCKET_NAME=mysamplebucket
   S3_ENDPOINT_URL=http://localhost:4566
   AWS_REGION=us-east-1
   ```

   Aunque el SDK de AWS normalmente podría usar variables de entorno que comiencen con `AWS_`, esta aplicación específica hace referencia directa a las siguientes variables `S3_*` en el archivo index.js (dentro del directorio `backend/`) para configurar `S3Client`. 

   ```js
   const s3 = new S3Client({
     endpoint: process.env.S3_ENDPOINT_URL, // Utiliza el endpoint proporcionado o recurre a los valores predeterminados
     credentials: {
       accessKeyId: process.env.AWS_ACCESS_KEY_ID || 'default_access_key', // Valores predeterminados para el desarrollo
       secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || 'default_secret_key',  
     },
   });
   ```

4. Inicia el servidor backend:

   ```console
   $ node index.js
   ```

     Verás el mensaje de que el servicio backend se ha iniciado correctamente en el puerto 5000.

## Iniciar el servicio frontend

Para iniciar el servicio frontend, abre una nueva terminal y sigue estos pasos:

1. Dirígete al directorio `frontend`:

   ```console
   $ cd frontend
   ```

2. Instala las dependencias requeridas
  
   ```console
   $ npm install
   ```

3. Inicia el servicio frontend

   ```console
   $ npm run dev
   ```
   
   Para este momento, deberías ver el siguiente mensaje:

   ```console
   VITE v5.4.2  ready in 110 ms
   ➜  Local: http://localhost:5173/
   ➜  Network: use --host to expose
   ➜  press h + enter to show help
   ```

   Ahora puedes acceder a la aplicación a través de [http://localhost:5173](http://localhost:5173). Adelante, sube una imagen seleccionando un archivo de imagen y luego el botón **Upload**.

   ![Diagrama que muestra una aplicación de lista de tareas en funcionamiento](/guides/localstack/images/localstack-todolist.webp)

   Puedes verificar que la imagen se haya subido al bucket de S3 revisando los registros del contenedor de LocalStack:

   ![Diagrama que muestra los registros de LocalStack que destacan la imagen subida al bucket de S3 emulado](/guides/localstack/images/localstack-todolist-s3put.webp)

   El código de estado `200` significa que la operación `putObject`, que implica subir un objeto al bucket de S3, se ejecutó con éxito dentro del entorno de LocalStack. LocalStack registra esta entrada para proporcionar visibilidad de las operaciones que se realizan. Esto ayuda a depurar y confirmar que tu aplicación está interactuando correctamente con los servicios emulados de AWS. 


   Dado que LocalStack está diseñado para simular servicios de AWS localmente, esta entrada de registro muestra que tu aplicación está funcionando como se espera al realizar operaciones en la nube en un entorno de sandbox local.

## Conectarse a LocalStack desde una aplicación Node contenedorizada

Una vez que has aprendido a conectar una aplicación Node.js no contenedorizada a LocalStack, es hora de explorar los cambios necesarios para ejecutar toda la pila de aplicaciones en un entorno contenedorizado. Para lograr esto, crearás un archivo Compose especificando todos los servicios requeridos: frontend, backend, base de datos y LocalStack.

1. Examina el archivo Docker Compose. 

   El siguiente archivo Docker Compose define cuatro servicios: `backend`, `frontend`, `mongodb` y `localstack`. Los servicios `backend` y `frontend` son tus aplicaciones Node.js, mientras que `mongodb` proporciona una base de datos y `localstack` simula servicios de AWS como S3.

   El servicio `backend` depende de los servicios `localstack` y `mongodb`, asegurando que estén en funcionamiento antes de que este se inicie. También utiliza un archivo .env para las variables de entorno. El servicio frontend depende del backend y establece la URL de la API. El servicio `mongodb` utiliza un volumen persistente para el almacenamiento de datos, y `localstack` está configurado para ejecutar el servicio S3. Esta configuración te ayuda a desarrollar y probar tu aplicación localmente con servicios similares a los de AWS.

   ```yaml
   services:
     backend:
       build:
         context: ./backend
         dockerfile: Dockerfile
       ports:
         - 5000:5000
       depends_on:
         - localstack
         - mongodb
       env_file:
         - backend/.env

     frontend:
       build:
         context: ./frontend
         dockerfile: Dockerfile
       ports:
         - 5173:5173
       depends_on:
         - backend
       environment:
         - REACT_APP_API_URL=http://backend:5000/api

     mongodb:
       image: mongo
       container_name: mongodb
       volumes:
         - mongodbdata:/data/db
       ports:
         - 27017:27017

     localstack:
       image: localstack/localstack
       container_name: localstack
       ports:
         - 4566:4566
       environment:
         - SERVICES=s3
         - GATEWAY_LISTEN=0.0.0.0:4566
       volumes:
         - ./localstack:/docker-entrypoint-initaws.d

   volumes:
     mongodbdata:
   ```

2. Modifica el archivo `.env` bajo el directorio `backend/` para que los recursos se conecten usando los nombres de red internos.

   > [!TIP]
   > Según el archivo Compose anterior, la aplicación se conectaría a LocalStack usando el nombre de host `localstack`, mientras que MongoDB se conectaría usando el nombre de host `mongodb`.
 
   ```plaintext
   MONGODB_URI=mongodb://mongodb:27017/todos
   AWS_ACCESS_KEY_ID=test
   AWS_SECRET_ACCESS_KEY=test
   S3_BUCKET_NAME=mysamplebucket
   S3_ENDPOINT_URL=http://localstack:4566
   AWS_REGION=us-east-1
   ```

3. Detener los servicios en ejecución

   Asegúrate de detener los servicios de Node frontend y backend del paso anterior presionando “Ctrl+C” en la terminal. También deberás detener los contenedores de LocalStack y MongoDB seleccionándolos en el panel de Docker Desktop y eligiendo el botón "Delete". 


4. Inicia la pila de la aplicación ejecutando el siguiente comando en la raíz del directorio del proyecto clonado:

   ```console
   $ docker compose -f compose.yml up -d --build
   ```

   Después de unos momentos, la aplicación estará en funcionamiento.

5. Crear un bucket de S3 manualmente

   El bucket de AWS S3 no se crea de antemano mediante el archivo Compose. Ejecuta el siguiente comando para crear un nuevo bucket dentro del entorno de LocalStack:


   ```console
   $ awslocal s3 mb s3://mysamplebucket
   ```

   El comando crea un bucket de S3 llamado `mysamplebucket`.

   Abre [http://localhost:5173](http://localhost:5173) para acceder a la aplicación completa de lista de tareas y comenzar a subir imágenes al bucket de Amazon S3. 

   > [!TIP]
   > Para optimizar el rendimiento y reducir los tiempos de subida durante el desarrollo, considera subir archivos de imagen más pequeños. Las imágenes más grandes pueden tardar más en procesarse y podrían afectar la capacidad de respuesta general de la aplicación.


## Resumen

Esta guía te ha llevado a través de la configuración de un entorno de desarrollo local utilizando LocalStack y Docker. Has aprendido a probar aplicaciones basadas en AWS de forma local, reduciendo costos y aumentando la eficiencia de tu flujo de trabajo de desarrollo.

