Cuando llegó el momento de implementar la aplicación, probé AWS, pero, sinceramente, me decepcionó un poco la cantidad de información y servicios que brindan y realmente quería ver mi aplicación en acción. Entonces me topé con Vercel. Además de eso, había estado aprendiendo sobre Docker y quería poner en práctica lo que había aprendido hasta ahora; esta era la oportunidad adecuada.
Vercel es bien conocido por su implementación de configuración cero. Con solo un par de clics, puede implementar su aplicación. También puede conectar su repositorio y Vercel compilará e implementará instantáneamente su proyecto después de cada confirmación. No podría ser más conveniente que eso 😀. Otra razón por la que elegí Vercel en lugar de AWS fue su función "sin servidor", que usé para renderizar los documentos de mi base de datos a través de una API Express. Para ser honesto, no puedo quejarme de su servicio. Nunca tuve ningún problema con mi proyecto. El problema aquí es que quería aprender más sobre el backend de mi aplicación y pensé que comprender la implementación podría ayudarme con eso. He visto a muchas personas elegir AWS en lugar de Vercel debido a su plan de precios. No se aplica a mi caso, ya que mi aplicación no tiene tanto tráfico y la uso principalmente para fines de estudio. Pero es bueno mencionar que Vercel tiene un "problema" con la escalada cuando se trata de precios.
La solicitud de la cesta de alimentos de Toronto se puede dividir en tres partes diferentes:
Rastreador web para recopilar información de una tienda de comestibles local
API expresa que organiza la información y puede realizar operaciones matemáticas para hacerlo.
Aplicación React que renderiza la aplicación y toda la información necesaria.
Por ahora, solo estoy implementando Webscraper en AWS, ya que aún necesito aprender más sobre servidores y rutas para implementar la API Express y la aplicación React. Para comenzar, lancé una instancia EC2 de AWS y configuré una alarma de presupuesto para que cada vez que el gasto en mi instancia supere los $0.01, reciba una notificación. Aprendí eso de la peor manera después de que me facturaran una instancia de DocumentDB que tenía ejecutándose en mi cuenta desde diciembre de 2023 y no tenía idea 😂. Amazon ofrece niveles gratuitos con 750 horas de t2.micro (o t3.micro en las regiones en las que t2.micro no está disponible), 30 Gib de almacenamiento EBS, 2 millones de IO, 1 GB de instantáneas y 100 GB de ancho de banda a Internet.
Mientras aprendía a implementar mi aplicación dockerizada en AWS, me di cuenta de que hay al menos dos enfoques diferentes; podría haber más:
Construya el contenedor Docker localmente y envíe solo el contenedor a AWS.
Enviar todo a AWS y construir mi contenedor de forma remota.
Elegí el segundo enfoque porque quería tener la experiencia de trabajar de forma completamente remota en mi aplicación si fuera necesario. No siempre estoy en mi propia computadora y tener mi aplicación en una instancia EC2 sería realmente útil en esas situaciones. Además, me vería obligado a trabajar con Vim, que es algo que quería hacer. Antes de enviar los archivos a mi instancia EC2, preparé mi entorno remoto instalando Node.js y Docker.
Para enviar los archivos a mi instancia EC2, utilicé el protocolo de copia segura (scp). El comando era similar a esto:
scp -i ubuntu.pem -r LOCAL_DIRECTORY [email protected]:/home/ubuntu/downloads/webscraperdockeraws
-i ubuntu.pem
: esta bandera especifica el archivo de identidad (clave privada) que se utilizará para la autenticación con clave pública. En este caso, ubuntu.pem
es el archivo de clave privada que se utiliza para autenticarse en el servidor remoto.-r
: Esta bandera indica que la operación debe ser recursiva, lo que significa que copiará directorios y sus contenidos recursivamente.[email protected]:/home/ubuntu/downloads/webscraperdockeraws
: esta es la especificación de destino. Incluye el nombre de usuario ( ubuntu
) y la dirección IP ( 35.183.21.127
) del servidor remoto, seguido de la ruta del directorio ( /home/ubuntu/downloads
) donde se copiarán los archivos.
Una vez que todos los archivos se transfirieron a mi instancia EC2, pude crear mi contenedor Docker. Y aquí empezaron los errores. ¡Genial! La biblioteca más importante de mi Webscraper es Puppeteer, que proporciona una API de alto nivel para controlar Chrome/Chromium a través del protocolo DevTools. Puppeteer se ejecuta en modo sin interfaz gráfica, lo que hace que su ejecución sea más rápida. Pero cuando intenté convertir mi aplicación en Docker, me encontré con algunos problemas:
De forma predeterminada, cuando se instala Puppeteer, se descarga Chrome para realizar pruebas y un binario chrome-headless-shell. El navegador se descarga en la carpeta $HOME/.cache/puppeteer. El problema es que AWS no incluye un $HOME/.cache en su instancia de Ubuntu. Descubrí este problema después de investigar un poco y, para resolverlo, todo lo que tuve que hacer fue mover la carpeta /.cache al directorio raíz; este problema está bien documentado en el portal npm de Puppeteers.
Una cosa obvia de la que no me había dado cuenta era que hasta ahora estaba ejecutando mi aplicación en sistemas operativos como Windows y MacOs... Pero ahora estaba lidiando con Ubuntu. Y como era una instancia vacía, no tenía ningún paquete/aplicación preinstalado, por eso instalé Node y Docker tan pronto como ejecuté la instancia por primera vez. Pero me estaba olvidando de una aplicación realmente importante para que mi Webscraper funcione: Google Chrome. ¿Recuerdas lo que dije sobre Puppeteer antes? Bueno, necesitaba asegurarme de tener la versión correcta de Chromium en mi instancia. Cada versión principal de Node.js está construida sobre una versión de Debian, y esa versión de Debian viene con una versión antigua de Chromium, que a veces no es compatible con la última versión de Puppeteer. Después de investigar un poco, descubrí que tenía que incluir una instrucción en mi Dockerfile para que se pudiera descargar la versión correcta de Chromium antes de que Docker instale todas las dependencias de mi aplicación y la ejecute. Mi archivo Docker se parecía a esto:
Después de solucionar el problema anterior, apareció otro. Ahora el mensaje de error dice: “No hay sandbox utilizable”. Para solucionarlo, todo lo que tuve que hacer fue cambiar mi código e incluir un argumento –no-sandbox en la función puppeteer.launch() para cada uno de mis productos comestibles.
Listo. Ahora mi Webscraper se ejecuta en un contenedor en mi instancia AWS EC2. Sin embargo, no raspará los 65 productos. Después del quinto producto, la aplicación se bloquea. Creo que tiene algo que ver con los recursos disponibles que tengo en esta instancia. Tenía el mismo problema al ejecutar el raspador con acciones de Github. De todos modos, mi objetivo era iniciar una instancia AWS EC2 y hacer que mi aplicación se ejecutara de forma remota, y lo hice. ¡Hay mucho por venir!