Ancrer une application basée sur React, Express et MongoDB

L'auteur d'un article que nous traduisons aujourd'hui souhaite parler de la manière de conditionner les applications Web React, Express et MongoDB dans des conteneurs Docker. Nous examinerons ici les caractéristiques de la formation de la structure des fichiers et des dossiers de ces projets, la création de fichiers Dockerfileet l'utilisation de la technologie Docker Compose.



Début des travaux


Par souci de simplicité, je suppose que vous disposez déjà d'une application fonctionnelle, présentée par les parties client et serveur, connectée à la base de données.

Il est préférable que le code client et serveur se trouvent dans le même dossier. Le code peut être situé dans un référentiel, mais il peut être stocké dans différents référentiels. Dans ce cas, les projets doivent être combinés dans un dossier à l'aide de la commande git submodule. J'ai fait juste ça.


Arborescence des fichiers du référentiel parent

React Application


Ici, j'ai utilisé un projet créé à l'aide de l'application Create React et configuré pour prendre en charge TypeScript. Il s'agit d'un simple blog contenant plusieurs éléments visuels.

Créez d'abord un fichier Dockerfiledans le répertoire racine client. Pour ce faire, exécutez simplement la commande suivante:

$ touch Dockerfile

Ouvrez le fichier et entrez les commandes ci-dessous. Comme déjà mentionné, j'utilise dans mon application TypeScript, donc je dois d'abord le construire. Ensuite, vous devez prendre ce qui s'est passé et déployer le tout au format de ressources statiques. Pour ce faire, j'utilise le processus en deux étapes de création d'une image Docker.

La première étape consiste à utiliser Node.js pour créer l'application. J'utilise comme image de base une image alpine. Il s'agit d'une image très compacte qui affectera avantageusement la taille du conteneur.

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

Ainsi commence la nôtre Dockerfile. Vient d'abord l'équipe node:12-alpine as builder. Ensuite, nous définissons le répertoire de travail - dans notre cas, ceci /app. Pour cette raison, un nouveau dossier sera créé dans le conteneur. Dans ce dossier conteneur, copiez package.jsonet installez les dépendances. Ensuite, /appnous copions tout depuis le dossier /services/client. Le travail est complété par l'assemblage du projet.

Vous devez maintenant organiser l'hébergement de l'assembly nouvellement créé. Pour ce faire, utilisez NGINX. Et, encore une fois, ce sera la version alpine du système. Nous faisons cela, comme auparavant, pour économiser de l'espace.

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

Ici, les nginxrésultats de l'assemblage de projet obtenus à l'étape précédente sont copiés dans le dossier . Ouvrez ensuite le port 80. C'est sur ce port que le conteneur attendra les connexions. La dernière ligne du fichier est utilisée pour démarrer NGINX.

C'est tout ce qui est nécessaire pour ancrer la partie client de l'application. Le résultat Dockerfileressemblera à ceci:

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


Notre API Express est également assez simple. Ici, pour organiser les points de terminaison, la technologie RESTful est utilisée. Les points de terminaison sont utilisés pour créer des publications, pour prendre en charge l'autorisation et pour résoudre d'autres problèmes. Commençons par créer Dockerfiledans le répertoire racine api. Nous agirons comme avant.

Lors du développement côté serveur de l'application, j'ai utilisé les fonctionnalités ES6. Par conséquent, pour exécuter le code, je dois le compiler. J'ai décidé de traiter le code en utilisant Babel. Comme vous l'avez peut-être deviné, là encore, le processus d'assemblage en plusieurs étapes sera utilisé.

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

Tout ici est très similaire à celui que Dockerfilenous avons utilisé pour la partie client du projet, nous n'entrerons donc pas dans les détails. Cependant, il y a une caractéristique:

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

Avant de stocker des mots de passe dans la base de données, je les hache en utilisant bcrypt . C'est un package très populaire, mais il y a quelques problèmes avec son utilisation dans les images alpines. Ici, vous pouvez rencontrer quelque chose comme les messages d'erreur suivants:

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.

Il s'agit d'un problème largement connu. Sa solution consiste à installer des packages supplémentaires et Python avant d'installer des packages npm.

La prochaine étape dans la construction de l'image, comme dans le cas du client, consiste à prendre ce qui a été formé à l'étape précédente et à le démarrer à l'aide de 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"]

Il y a une autre fonctionnalité ici, qui consiste à installer uniquement les packages qui sont conçus pour que le projet fonctionne en production. Nous n'avons plus besoin de Babel - après tout, tout était déjà compilé dans la première étape de l'assemblage. Ensuite, nous ouvrons le port 8080sur lequel le côté serveur de l'application attendra l'arrivée des demandes et exécutons Node.js.

Voici le résumé 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 compose


La dernière phase de notre travail consiste à apporter les conteneurs apiet clientle conteneur contenant MongoDB. Pour ce faire, nous utiliserons le fichier docker-compose.ymlsitué dans le répertoire racine du référentiel parent. Cela est dû au fait qu'à partir de cet endroit, il y a accès aux fichiers Dockerfilepour les parties client et serveur du projet.

Créez un fichier docker-compose.yml:

$ touch docker-compose.yml

La structure du fichier de projet devrait maintenant ressembler à celle ci-dessous.


La structure finale des fichiers du projet

Nous allons maintenant ajouter auxdocker-compose.ymlcommandes suivantes:

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

Tout est arrangé très simplement. Nous avons trois services: client, apiet db. Il n'y a pas de sélection pour MongoDB Dockerfile- Docker téléchargera l'image appropriée à partir de son hub et créera un conteneur à partir de celle-ci. Cela signifie que notre base de données sera vide, mais pour commencer, cela nous conviendra.

Dans les sections apiet clientil y a une clé builddont la valeur contient le chemin d'accès aux fichiers des Dockerfileservices correspondants (aux répertoires racine apiet client). Les ports de conteneur attribués dans les fichiers Dockerfileseront ouverts sur le réseau hébergé par Docker Compose. Cela permettra aux applications d'interagir. Lors de la configuration du service api, en outre, la clé est utiliséedepends_on. Il indique à Docker qu'avant de démarrer ce service, vous devez attendre que le conteneur démarre complètement db. Grâce à cela, nous pouvons éviter les erreurs dans le conteneur api.

Et - voici une autre petite chose liée à MongoDB. Dans la base de code backend, vous devez mettre à jour la chaîne de connexion à la base de données. Il indique généralement localhost:

mongodb://localhost:27017/blog

Mais, en utilisant la technologie Docker Compose, nous devons faire pointer le nom du conteneur:

mongodb://blog-db:27017/blog

La dernière étape de notre travail consiste à démarrer tout cela en exécutant la docker-compose.ymlcommande suivante dans le dossier racine du projet (où se trouve le fichier ):

$ docker-compose up

Sommaire


Nous avons examiné une technique simple de conteneurisation d'applications basée sur React, Node.js et MongoDB. Nous pensons que si vous en avez besoin, vous pouvez facilement l'adapter à vos projets.

PS Nous avons lancé le marché sur le site Web de RUVDS. L'image Docker y est installée en un clic. Vous pouvez vérifier le fonctionnement des conteneurs sur le VPS . Les nouveaux clients bénéficient de 3 jours gratuits pour les tests.

Chers lecteurs! Utilisez-vous Docker Compose?


All Articles