Acoplamiento de una aplicación basada en React, Express y MongoDB

El autor de un artículo que estamos traduciendo hoy quiere hablar sobre cómo empacar aplicaciones web basadas en React, Express y MongoDB en contenedores Docker. Aquí consideraremos las características de formar la estructura de archivos y carpetas de dichos proyectos, crear archivos Dockerfiley usar la tecnología Docker Compose.



Comienzo de trabajo


En aras de la simplicidad, supongo que ya tiene una aplicación en funcionamiento, presentada por las partes del cliente y el servidor, conectada a la base de datos.

Es mejor si el código del cliente y el servidor se encuentran en la misma carpeta. El código puede ubicarse en un repositorio, pero puede almacenarse en diferentes repositorios. En este caso, los proyectos deben combinarse en una carpeta usando el comando git submodule. Yo solo hice eso.


Árbol de archivos del repositorio principal

Reaccionar solicitud


Aquí utilicé un proyecto creado con la aplicación Create React y configurado para admitir TypeScript. Este es un blog simple que contiene varios elementos visuales.

Primero, cree un archivo Dockerfileen el directorio raíz client. Para hacer esto, simplemente ejecute el siguiente comando:

$ touch Dockerfile

Abra el archivo e ingrese los comandos a continuación. Como ya se mencionó, lo uso en mi aplicación TypeScript, así que primero necesito compilarlo. Luego debe tomar lo que sucedió e implementarlo todo en el formato de recursos estáticos. Para lograr esto, utilizo el proceso de dos pasos para construir una imagen de Docker.

El primer paso es usar Node.js para compilar la aplicación. Yo uso, como imagen base, una imagen alpina. Esta es una imagen muy compacta, que afectará beneficiosamente el tamaño del contenedor.

FROM node:12-alpine as builder
WORKDIR /app
COPY package.json /app/package.json
RUN npm install --only=prod
COPY . /app
RUN npm run build

Así comienza el nuestro Dockerfile. Primero viene el equipo node:12-alpine as builder. Luego establecemos el directorio de trabajo, en nuestro caso, esto /app. Debido a esto, se creará una nueva carpeta en el contenedor. En esta carpeta contenedor, copie package.jsone instale las dependencias. Luego en /appcopiamos todo de la carpeta /services/client. El trabajo se completa con el montaje del proyecto.

Ahora necesita organizar el alojamiento para el ensamblado recién creado. Para hacer esto, use NGINX. Y, de nuevo, esta será la versión alpina del sistema. Estamos haciendo esto, como antes, para ahorrar espacio.

FROM nginx:1.16.0-alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Aquí, los nginxresultados del ensamblaje del proyecto obtenido en el paso anterior se copian en la carpeta . Luego abra el puerto 80. Es en este puerto que el contenedor esperará las conexiones. La última línea del archivo se usa para iniciar NGINX.

Esto es todo lo que se necesita para acoplar la parte cliente de la aplicación. El resultado Dockerfilese verá así:

FROM node:12-alpine as build
WORKDIR /app
COPY package.json /app/package.json
RUN npm install --only=prod
COPY . /app
RUN npm run build
FROM nginx:1.16.0-alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

API Express


Nuestra API Express también es bastante simple. Aquí, para organizar los puntos finales, se utiliza la tecnología RESTful. Los puntos finales se utilizan para crear publicaciones, respaldar la autorización y resolver otros problemas. Comencemos creando Dockerfileen el directorio raíz api. Actuaremos como antes.

Durante el desarrollo del lado del servidor de la aplicación, utilicé las capacidades de ES6. Por lo tanto, para ejecutar el código, necesito compilarlo. Decidí procesar el código usando Babel. Como habrás adivinado, aquí nuevamente se utilizará el proceso de ensamblaje de etapas múltiples.

FROM node:12-alpine as builder
WORKDIR /app
COPY package.json /app/package.json
RUN apk --no-cache add --virtual builds-deps build-base python
RUN npm install
COPY . /app
RUN npm run build

Todo aquí es muy similar al Dockerfileque usamos para la parte del proyecto del cliente, por lo que no entraremos en detalles. Sin embargo, hay una característica:

RUN apk --no-cache add --virtual builds-deps build-base python

Antes de almacenar las contraseñas en la base de datos, las hechizo usando bcrypt . Este es un paquete muy popular, pero hay algunos problemas con su uso en imágenes basadas en Alpine. Aquí puede encontrar algo como los siguientes mensajes de error:

node-pre-gyp WARN Pre-built binaries not found for bcrypt@3.0.8 and node@12.16.1 (node-v72 ABI, musl) (falling back to source compile with node-gyp)
npm ERR! Failed at the bcrypt@3.0.8 install script.

Este es un problema ampliamente conocido. Su solución es instalar paquetes adicionales y Python antes de instalar paquetes npm.

El siguiente paso en la construcción de la imagen, como en el caso del cliente, es tomar lo que se formó en el paso anterior y comenzar a usar Node.js.

FROM node:12-alpine
WORKDIR /app
COPY --from=builder /app/dist /app
COPY package.json /app/package.json
RUN apk --no-cache add --virtual builds-deps build-base python
RUN npm install --only=prod
EXPOSE 8080 
USER node
CMD ["node", "index.js"]

Aquí hay otra característica, que consiste en instalar solo aquellos paquetes diseñados para que el proyecto funcione en producción. Ya no necesitamos a Babel; después de todo, todo ya estaba compilado en el primer paso del ensamblaje. A continuación, abrimos el puerto 8080en el que el lado del servidor de la aplicación esperará a que lleguen las solicitudes y ejecutamos Node.js.

Aquí está el resumen Dockerfile:

FROM node:12-alpine as builder
WORKDIR /app
COPY package.json /app/package.json
RUN apk --no-cache add --virtual builds-deps build-base python
RUN npm install
COPY . /app
RUN npm run build
FROM node:12-alpine
WORKDIR /app
COPY --from=builder /app/dist /app
COPY package.json /app/package.json
RUN apk --no-cache add --virtual builds-deps build-base python
RUN npm install --only=prod
EXPOSE 8080 
USER node
CMD ["node", "index.js"]

Docker componer


La última fase de nuestro trabajo es llevar los contenedores apiy clientel contenedor que contiene MongoDB. Para hacer esto, utilizaremos el archivo docker-compose.ymlubicado en el directorio raíz del repositorio principal. Esto se hace debido al hecho de que desde este lugar hay acceso a los archivos Dockerfilepara el cliente y el servidor del proyecto.

Crea un archivo docker-compose.yml:

$ touch docker-compose.yml

La estructura del archivo del proyecto ahora debería verse como la siguiente.


La estructura final de los archivos del proyecto

Ahora agregaremos a losdocker-compose.ymlsiguientes comandos:

version: "3"
services:
  api:
    build: ./services/api
    ports:
      - "8080:8080"
    depends_on:
      - db
    container_name: blog-api
  client:
    build: ./services/client
    ports:
      - "80:80"
    container_name: blog-client
  db:
    image: mongo
    ports:
      - "27017:27017"
    container_name: blog-db

Todo está organizado de manera muy simple. Tenemos tres servicios: client, apiy db. No hay una selección para MongoDB Dockerfile: Docker descargará la imagen adecuada de su concentrador y creará un contenedor a partir de ella. Esto significa que nuestra base de datos estará vacía, pero para empezar, esto nos conviene.

En las secciones apiy clienthay una clave buildcuyo valor contiene la ruta a los archivos de los Dockerfileservicios correspondientes (a los directorios raíz apiy client). Los puertos de contenedor asignados en los archivos Dockerfileestarán abiertos en la red alojada en Docker Compose. Esto permitirá que las aplicaciones interactúen. Al configurar el servicio api, además, se utiliza la clavedepends_on. Él le dice a Docker que antes de comenzar este servicio, debe esperar hasta que el contenedor se inicie por completo db. Gracias a esto, podemos evitar errores en el contenedor api.

Y aquí hay otra cosita relacionada con MongoDB. En la base del código de fondo, debe actualizar la cadena de conexión de la base de datos. Por lo general, indica localhost:

mongodb://localhost:27017/blog

Pero, usando la tecnología Docker Compose, tenemos que hacer que señale el nombre del contenedor:

mongodb://blog-db:27017/blog

El último paso de nuestro trabajo es comenzar todo esto ejecutando el docker-compose.ymlsiguiente comando en la carpeta raíz del proyecto (donde se encuentra el archivo ):

$ docker-compose up

Resumen


Analizamos una técnica simple para contener aplicaciones basadas en React, Node.js y MongoDB. Creemos que si lo necesita, puede adaptarlo fácilmente a sus proyectos.

PD: Lanzamos el mercado en el sitio web de RUVDS. La imagen de Docker allí se instala con un solo clic. Puede verificar el funcionamiento de los contenedores en el VPS . A los nuevos clientes se les otorgan 3 días sin cargo para las pruebas.

¡Queridos lectores! ¿Usas Docker Compose?


All Articles