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 Dockerfile
y 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 principalReaccionar 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 Dockerfile
en 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.json
e instale las dependencias. Luego en /app
copiamos 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 nginx
resultados 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 Dockerfile
se 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 Dockerfile
en 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 Dockerfile
que 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 8080
en 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 api
y client
el contenedor que contiene MongoDB. Para hacer esto, utilizaremos el archivo docker-compose.yml
ubicado en el directorio raíz del repositorio principal. Esto se hace debido al hecho de que desde este lugar hay acceso a los archivos Dockerfile
para 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 proyectoAhora agregaremos a losdocker-compose.yml
siguientes 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
, api
y 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 api
y client
hay una clave build
cuyo valor contiene la ruta a los archivos de los Dockerfile
servicios correspondientes (a los directorios raíz api
y client
). Los puertos de contenedor asignados en los archivos Dockerfile
estará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.yml
siguiente 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?