Configuration de Parse Server et Parse Dashboard avec Docker

Dans cet article nous allons voir comment mettre en place Parse Server ainsi que Parse Dashboard avec Docker. Cet environnement pourra être utilisé en dev et en production.

Qu'est ce que Parse Server et Parse Dashboard

Parse Server est une version open source du BaaS (backend as a service) Parse.com. Parse Server permet de mettre en place rapidement un backend pour votre application web ou mobile. Parse Dashboard est quand à lui une interface qui permet entre autre de venir consulter/éditer les données en base,consulter les logs et effectuer certains tests sur l'api.

Parse Server amène un certain nombre de fonctionnalités :

  • Gestion des utilisateurs
  • Gestion des accès au données
  • Api Rest
  • Sdk pour différentes plateformes (JS, iOS, Android...)
  • Possibilité d'écrire ses propres fonctions pour des traitements plus complexes
  • ...

Ceci n'est qu'une liste non exhaustive des fonctionnalités disponnibles. Visitez le repo github pour en savoir plus sur l'étendu des possibilités.

Objectif de l'article

L'objectif de cet article est de configurer un environnement Parse Server avec Docker en respectant les contraintes suivantes :

  • Possibilité d'utiliser la syntaxe ES6 dans les fonctions Cloud
  • Utiliser cette environnement en dev sans avoir à rebuild l'image Docker

La finalité étant de pouvoir ce servir de cette environnement pour rapidement démarrer un nouveau projet et ne pas avoir à le modifier par la suite pour le mettre en production.

Pour cela nous allons utiliser les éléments suivants :

  • Babel
  • nodemon
  • Docker
  • Docker-compose

Mise en place de Parse Server et du dashboard

Pour commencer créez un dossier qui contiendra l'ensemble du projet et ensuite dans ce dossier créer un nouveau dossier nommé parse-server.

mkdir parse-server-sample && cd parse-server-sample
mkdir parse-server && cd parse-server

Ensuite nous ajoutons un fichier package.json qui contient les dépendances nécessaires :

{
  "name": "parse-server-sample",
  "version": "1.0.0",
  "description": "Basic Parse Server Sample",
  "dependencies": {
    "express": "^4.16.4",
    "parse-dashboard": "^1.2.0",
    "parse-server": "^3.1.3"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-env": "^1.7.0"
  }
}

Maintenant il faut ajouter les scripts npm qui vont nous permettre dans lancer le serveur.

  "scripts": {
    "clean": "rm -rf build && mkdir build",
    "build-server": "babel -d ./build ./server -s",
    "build": "npm run clean && npm run build-server",
    "start": "npm run build && node ./build/index.js",
    "dev": "babel-node ./server/index.js"
  }

Le principe de fonctionnement est le suivant :

Lorsqu'on est en dev on utilisera babel-node pour lancer le serveur. babel-node va transformer automatiquement notre code lorsque la commande sera exécutée.

Cependant en production nous n'allons pas utiliser babel-node pour lancer le serveur. Nous allons dans un premier temps utiliser babel pour transformer notre code puis ensuite lancer notre serveur normalement avec node en lui indiquant d'utiliser le code transformé par babel et qui se situe dans le dossier build.

Pour terminer nous ajoutons un fichier .babelrc dans notre dossier parse-server avec le code suivant :

{
  "presets": ["env"]
}

Cela indiquera à babel les presets à utiliser lors de la transformation du code.

Maintenant nous allons pouvoir ajouter le point d'entrée de notre server. Créez un dossier server et ajoutez dedans un fichier index.js

mkdir server && cd server
touch index.js

Dans ce fichier index.js nous allons configurer Parse Server et Parse Dashboard.

Tout d'abord nous ajoutons les dépendances nécessaires :

var express = require('express')
var ParseServer = require('parse-server').ParseServer
var ParseDashboard = require('parse-dashboard')

Ensuite nous définissons les options de notre server Parse à partir des variables d'environnements :

const mountPath = process.env.PARSE_MOUNT || '/parse'
const port = process.env.PORT || 1337
const databaseURI = process.env.DATABASE_URI || 'mongodb://localhost:27017/dev'
const cloudPath = __dirname + '/cloud/main.js'
const appId = process.env.APP_ID || 'myAppId'
const masterKey = process.env.MASTER_KEY || ''
const serverURL = process.env.SERVER_URL || 'http://localhost:1337/parse'
const logLevel = process.env.LOG_LEVEL || 'info'
const allowInsecureHTTP = process.env.ALLOW_INSECURE_HTTP_DASHBOARD
const appName = process.env.APP_NAME
const dashboard_user = process.env.DASHBOARD_USER
const dashboard_password = process.env.DASHBOARD_PASSWORD

Puis on instancie Parse Server et Parse Dashboard avec les options précédentes :

var api = new ParseServer({
  databaseURI: databaseURI,
  cloud: cloudPath,
  appId: appId,
  masterKey: masterKey,
  serverURL: serverURL,
  logLevel: logLevel,
})

var dashboard = new ParseDashboard(
  {
    apps: [
      {
        serverURL: serverURL,
        appId: appId,
        masterKey: masterKey,
        appName: appName,
      },
    ],
    users: [
      {
        user: dashboard_user,
        pass: dashboard_password,
        apps: [{ appId: appId }],
      },
    ],
  },
  //options
  { allowInsecureHTTP: allowInsecureHTTP }
)

Enfin on définit sur quelles routes le serveur et le dashboard seront accessibles et on lance le serveur.

var app = express()
app.use(mountPath, api)
app.use('/dashboard', dashboard)

var httpServer = require('http').createServer(app)
httpServer.listen(port, function() {
  console.log('parse-server running on port ' + port + '.')
})

A ce niveau-là de l'installation nous pourrions utiliser les fonctionnalités de bases de Parse Server. Cependant nous avons vu dans l'intro que Parse nous permet d'écrire nos propres fonctions pour éffectuer des traitements plus complexes. Ces fonctions sont utilisées dans ce qu'on appelle Cloud Code.

Dans la configuration de Parse nous avons indiqué que le Cloud Code se situait par défault dans le fichier main.js du dossier cloud.

const cloudPath = __dirname + '/cloud/main.js'

Nous avons juste à créer ce dossier et ajouter ce fichier :

mkdir cloud && cd cloud
touch main.js

Afin de tester que notre serveur fonctionne correctement nous allons ajouter une simple fonction dans notre Cloud Code que nous utiliserons dans la suite de l'article.

Parse.Cloud.define('test', (request, response) => {
  return { hello: 'world' }
})

Voila notre serveur et notre dashboard sont prêt, il ne reste plus qu'à configurer Docker et Docker Compose.

Création du fichier Dockerfile

Premièrement nous allons créer le fichier Dockerfile qui nous permettra de construire l'image de notre serveur Parse.

Dans le dossier parse-server ajoutez le fichier Dockerfile :

FROM node:8
RUN npm install -g nodemon
RUN mkdir parse
ADD . /parse
WORKDIR /parse
RUN npm install
EXPOSE 1337
CMD [ "npm", "start" ]

Ici rien de bien compliqué on part de l'image de base node:8, ensuite on installe nodemon nous allons voir son utilité juste après.

Puis on copie le contenu du dossier parse-server dans notre container.

Enfin on indique à Docker de démarrer le build du serveur puis de le lancer via la commande npm start.

Création du fichier docker-compose.yml

Pour terminer la configuration de l'environnement il ne nous reste plus qu'à créer le fichier docker-compose.yml à la racine de notre projet :

version: '2'
services:
  mongo:
    image: 'bitnami/mongodb:latest'
    container_name: 'dwa-studio-mongo-db'
    restart: always
    ports:
      - '27017:27017'
    environment:
      MONGODB_ROOT_PASSWORD: 'MONGODB_ROOT_PASSWORD'
      MONGODB_USERNAME: 'user'
      MONGODB_PASSWORD: 'MONGODB_PASSWORD'
      MONGODB_DATABASE: 'db_name'
    volumes:
      - ./mongo:/bitnami
  api:
    build: ./parse-server
    image: dwa-studio/parse-server
    container_name: 'dwa-studio-parse-server'
    restart: always
    ports:
      - '1337:1337'
    environment:
      PARSE_MOUNT: '/parse'
      PORT: 1337
      DATABASE_URI: mongodb://user:MONGODB_PASSWORD@mongo:27017/db_name
      APP_ID: 'APP_ID'
      MASTER_KEY: 'MASTER'
      SERVER_URL: 'http://localhost:1337/parse'
      LOG_LEVEL: 'error'
      ALLOW_INSECURE_HTTP_DASHBOARD: 'true'
      APP_NAME: 'Parse Server Sample'
      DASHBOARD_USER: 'User'
      DASHBOARD_PASSWORD: 'password'
    depends_on:
      - mongo

Ici on utilise l'image mongo-db fourni par Bitnami pour notre service de base de données et ensuite pour notre serveur Parse on indique à Docker de construire l'image à partir du Dockerfile se trouvant dans le dossier parse-server.

Nous définissons aussi les variables d'environnements utilisées dans le fichier index.js de notre serveur Parse.

Maintenant vous pouvez lancer les services via la commande :

docker-compose up

Allez sur l'url http://localhost:1337/parse vous devriez voir le message suivant :

{"error":"unauthorized"}

Ensuite si vous vous rendez sur l'url http://localhost:1337/dashboard/login vous devriez voir l'interface de login du dashboard.

Connectez-vous avec les identifiants suivants : User / password ou ceux définis dans le fichier docker-compose.yml si vous les avez modifiés.

Pour tester que notre Cloud Code fonctionne correctement nous allons nous rendre dans la partie API Console. Saisissez les mêmes informations que ci-dessous :

test-cloud-code

Si tout fonctionne correctement vous devriez obtenir le même résultat que sur l'image précédente.

Et pour le dev alors ?

Actuellement si on fait une modification dans la fonction de notre Cloud Code ou bien dans le fichier index.js ces modifications ne sont pas prises en compte. C'est tous à fait normale puisque le code que nous modifions sur notre poste n'est pas celui qui est dans le container Docker.

Le Dockerfile de base copie le code de notre machine et ensuite lance la commande npm-start qui va transformer le code et ensuite indiqué à node js de lancer le serveur depuis le dossier build.

Le seul moyen que les modifications soient prises en compte est de relancer la commande docker-compose up avec l'option --build qui va reconstruire l'image de notre serveur.

Heureusement pour nous allons pouvoir modifier ce fonctionnement très simplement. Rappelez-vous dans notre Dockerfile nous avons installé nodemon et c'est la que ce dernier rentre en jeux. nodemon va observer les fichiers de notre serveur et redémarrer ce dernier automatiquement lorsque des modifications sont détectées.

Grace à docker-compose nous pouvons changer la commande qui est exécuter par notre container au démarrage pour ce faire il faut ajouter l'option suivante dans le service api de notre fichier docker-compose.yml

command: nodemon --exec npm run dev

Dans ce cas la lorsque notre container sera lancer on utilisera nodemon pour lancer le script npm dev qui utilise babel-node.

Enfin pour que les modifications que l'on fait sur notre poste soit aussi dans le container nous devons rajouter le volume suivant :

volumes:
  - ./parse-server/server/:/parse/server

Voila maintenant toutes les modifications que vous faites dans le dossier server sont prises en comptes.

Vous pouvez donc utilisé cette environnement pour développer et ensuite une fois que vous souhaitez déployer vous n'avez plus qu'à retirer le volume et la commande pour que votre environnement puisse être utilisé en production.

Dernières recommandations

Si vous utilisez cette configuration en production veillez à bien remplacer les variables d'environnements notamment celles des accès au dashboard et à la base avec des valeurs sécurisées.

Rendez le dashboard inacessible en http avec la variable ALLOW_INSECURE_HTTP_DASHBOARD à faux. Cela rendra le dashboard accessible uniquement via https, vous devrez donc rajouter un reverse-proxy avec un domaine et un certificat ssl dans votre configuration (nous verrons comment faire cela dans un autre article).

Si vous le souhaitez lors du déploiement en production vous pouvez supprimer l'installation de nodemon dans le Dockerfile.

Vous pouvez récupérer l'intégralité du code de cet article en vous inscrivant ici.

Si vous avez des questions vous pouvez me contacter par le chat.