romulusFR / lifap5-backend-2018-2019

Backend pour le projet de LIFAP5 en L2 informatique UCBL

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

header-includes lang pagetitle
<meta name="keywords" content="LIFAP5, programmation fonctionnelle,Javascript" /> <meta name="description" content="Projet de l'UE LIFAP5 - 2018-2019 - UCBL - FST - Informatique" /> <meta charset="UTF-8">
fr
LIFAP5 - Projet - documentation backend

ARCHIVE - LIFAP5 - Projet 2018-2019 : documentation backend

Ce document est le guide de développement et de référence du serveur du projet 2018-2019 de l'unité d'enseignement LIFAP5 "Programmation fonctionnelle pour le WEB" en licence 2 informatique UCBL.

Ce document d'écrit la réalisation d'un serveur REST devant une base Mongo écrit en Node/Express/Mongoose. Un point websocket est aussi offert pour que le client puisse recevoir à la volée les modifications effectuées par les autres utilisateurs.

Site LIFAP5

Dépôt de code

sudo apt install subversion
svn checkout --username rthion https://subversion.renater.fr/lifap5/trunk/Projet

TODO prochaine version

Documentations de référence

Mongooose

Boostrap

Node/Express

WebSockets

Bonnes pratiques js/node/express

Installation environnement de développement

Ci dessous, la création pas-à-pas du projet. Le fichier ./backend/package.json contient déjà toutes les dépendences. Une fois Mongo d'installé, installer les dépendances et exécuter le serveur ainsi :

# création de la base mongodb
cd backend
npm install
npm start # lancé en mode développement par défaut
curl http://localhost:3000/topics/ # doit afficher une liste de topics avec leur créateur
npm test  # lance les tests automatisés avec newman : les 178 assertions doivent être OK

Installation Nodejs

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -  
sudo apt-get install -y nodejs  

npm install -g npm-check-updates
npm install -g nodemon  
npm install -g newman
npm install -g pm2

nodejs --version
> v10.15.3
nodemon  --version
> 1.18.10
ncu --version
> 3.1.2
newman --version
> 4.4.1
pm2 --version
> 3.4.1

Installation Mongodb

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --keyserver-options http-proxy=http://proxy.univ-lyon1.fr:3128 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4

echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list

sudo apt-get update
sudo apt-get install -y mongodb-org

sudo service mongod start

mongo --version
> MongoDB shell version v4.0.7
mongod --version
> db version v4.0.7

Initialisation du replica set

Pour permettre de suivre en live les màj sur le serveur avec les websockets. Voir :

Dans /etc/mongod.conf

replication:
  replSetName: "replica-local"
> rs.initiate()
{
  "info2" : "no configuration specified. Using a default configuration for the set",
  "me" : "127.0.0.1:27017",
  "ok" : 1,
  "operationTime" : Timestamp(1554897388, 1),
  "$clusterTime" : {
    "clusterTime" : Timestamp(1554897388, 1),
    "signature" : {
      "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
      "keyId" : NumberLong(0)
    }
  }
}

Scaffolding initial express

Bibliothèques utilisées

Installation lib node

Dans dossier ./backend

npm init

npm install --save mongoose

npm install --save express
npm install --save body-parser
npm install --save cors
npm install --save helmet
npm install --save serve-favicon
npm install --save ws

npm install --save debug
npm install --save make-promises-safe

npm install --save-dev eslint-plugin-security
npm install --save-dev eslint-plugin-node
npm install --save-dev eslint-config-eslint


npm audit fix

Création de la base mongodb

Initialisation

Les tests suivants devraient renvoyer des extraits de la collection

mongo lifap5-backend --eval "db.users.findOne()"
mongo lifap5-backend --eval "db.users.find({login : 'test'})"
mongo lifap5-backend --eval "db.topics.findOne()"

Pour exporter/importer manuellement

mongoexport --db=lifap5-backend --collection=topics --pretty --jsonArray  > Projet-2019-topics.json

mongoexport --db=lifap5-backend --collection=users --pretty --jsonArray > Projet-2019-users-full.json
mongoexport --db=lifap5-backend --collection=users --pretty --jsonArray --fields=login,_id,joined_on > Projet-2019-users.json

Dockerisation

Voir fichiers

sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Commandes de base

docker images
docker system df
docker-compose build


docker exec -it projet_mongo_1 mongo -u root -p 'lifap5-backend-2018' --authenticationDatabase admin lifap5-backend
docker exec -it projet_mongo_1 pwd

Test automatisés et debug

Mode debug

  • DEBUG=lifap5:* pour activer le module debug
  • Le flag active aussi le debug de mongoose
  • Mis dans les scripts dev de package.json qui utilise nodemon
npm run start:dev

Postman

Dans dossier ./tests

  • plan de test lifap5-backend.postman_collection.json
  • variables d'environnement lifap5-backend-env.postman_environment.json
  • script de lancement avec https://github.com/postmanlabs/newman dans la target test de ./backend/package.json

Références

JMeter

Dans dossier ./tests

Creating summariser <summary>
Created the tree successfully using ./lifap5-jmeter-testplan.jmx
Starting the test @ Tue Apr 02 14:39:29 CEST 2019 (1554208769052)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
summary +      1 in 00:00:01 =    1.1/s Avg:   462 Min:   462 Max:   462 Err:     0 (0.00%) Active: 15 Started: 15 Finished: 0
summary +   6573 in 00:00:30 =  218.6/s Avg:   338 Min:    49 Max:  2048 Err:    37 (0.56%) Active: 54 Started: 80 Finished: 26
summary +   4681 in 00:00:30 =  156.8/s Avg:   262 Min:    32 Max:  1205 Err:    24 (0.51%) Active: 39 Started: 80 Finished: 41
summary =  11255 in 00:01:01 =  185.0/s Avg:   307 Min:    32 Max:  2048 Err:    61 (0.54%)
summary +   4463 in 00:00:30 =  148.5/s Avg:   206 Min:    14 Max:  1404 Err:    16 (0.36%) Active: 13 Started: 80 Finished: 67
summary +    484 in 00:00:03 =  188.6/s Avg:    44 Min:     2 Max:   325 Err:     0 (0.00%) Active: 0 Started: 80 Finished: 80
summary =  16202 in 00:01:33 =  173.4/s Avg:   271 Min:     2 Max:  2048 Err:    77 (0.48%)
Tidying up ...    @ Tue Apr 02 14:41:02 CEST 2019 (1554208862638)

Références

https://octoperf.com/blog/2018/03/29/jmeter-tutorial/#random-behavior

Déploiement du serveur / prod

Cette partie est pour déployer un reverse-proxy nginx devant le serveur node et mettre en place quelques outils de monitoring.

Au cas où :

sudo chown -R $USER:$(id -gn $USER) /home/ubuntu/.config

Vérification du filtrage

Depuis une IP du campus

nmap -P0 -p22,80,443,8080,8443,27017-27019,3389,3000 lifap5.univ-lyon1.fr

Starting Nmap 7.60 ( https://nmap.org ) at 2019-04-04 14:06 CEST
Nmap scan report for lifap5.univ-lyon1.fr (192.168.74.8)
Host is up (0.00078s latency).

PORT      STATE    SERVICE
22/tcp    open     ssh
80/tcp    open     http
443/tcp   open     https
3000/tcp  filtered ppp
3389/tcp  closed   ms-wbt-server
8080/tcp  closed   http-proxy
8443/tcp  closed   https-alt
27017/tcp filtered mongod
27018/tcp filtered mongod
27019/tcp filtered mongod

Configuration spécifique (proxy svn)

edit ~/.subversion/servers
> [global]
> http-proxy-host = proxy.univ-lyon1.fr
> http-proxy-port = 3128

Crontab pour remise à zéro de la base

Ajouter avec crontab -e

crontab -l

> 42 * * * * mongoimport --uri mongodb://localhost:27017/lifap5-backend --collection topics --drop --jsonArray --type json --file /home/ubuntu/lifap5-projet/mongodb/Projet-2019-topics.json

Front Nginx / TLS

Certificats

Certificat auto-signé

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365

Certificat https://letsencrypt.org/ avec certbot

sudo addgroup nodecert
sudo adduser ubuntu nodecert
sudo adduser root nodecert

sudo chgrp -R nodecert /etc/letsencrypt/live
sudo chgrp -R nodecert /etc/letsencrypt/archive

sudo chmod 710 /etc/letsencrypt/live
sudo chmod 710 /etc/letsencrypt/archive

sudo chmod 640 /etc/letsencrypt/archive/lifap5.univ-lyon1.fr/privkey1.pem

Backup des certificats

tar zcvf /tmp/letsencrypt_backup_$(date +'%Y-%m-%d_%H%M').tar.gz /etc/letsencrypt

Reverse proxy nginx

Configuration nginx TLS

nginx -v
> nginx version: nginx/1.15.10

sudo adduser nginx nodecert

sudo nginx -T

Voir les résultats sur

Configuration nginx websocket

location /stream/ {
    include /etc/nginx/conf.d/proxy_set_header.inc;
    proxy_pass http://nodejs;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Visualisation de logs

Scalabilité et performance

Lancer

pm2 start --env local
pm2 ls

┌─────────────┬────┬─────────┬─────────┬───────┬────────┬─────────┬────────┬──────┬───────────┬────────┬──────────┐
│ App name    │ id │ version │ mode    │ pid   │ status │ restart │ uptime │ cpu  │ mem       │ user   │ watching │
├─────────────┼────┼─────────┼─────────┼───────┼────────┼─────────┼────────┼──────┼───────────┼────────┼──────────┤
│ lifap5-prod │ 0  │ 1.0.2   │ cluster │ 13687 │ online │ 2       │ 2h     │ 0.4% │ 64.8 MB   │ ubuntu │ disabled │
│ lifap5-prod │ 1  │ 1.0.2   │ cluster │ 13700 │ online │ 2       │ 2h     │ 0.4% │ 63.8 MB   │ ubuntu │ disabled │
└─────────────┴────┴─────────┴─────────┴───────┴────────┴─────────┴────────┴──────┴───────────┴────────┴──────────┘

pm2 logs
pm2 monit

Références

Introduction to Load Balancing Using Node.js

Une série de posts sur PM2 https://pm2.io/doc/

  1. https://www.acuriousanimal.com/2017/08/12/understanding-the-nodejs-cluster-module
  2. https://www.acuriousanimal.com/2017/08/18/using-cluster-module-with-http-servers
  3. https://www.acuriousanimal.com/2017/08/20/using-pm2-to-manage-cluster.html
  4. https://www.acuriousanimal.com/2017/08/27/graceful-shutdown-node-processes

Cache pour mongoose

A priori, pas vraiment utile ici

Expertise extérieure

Générales

Chiffrage (tests unitaires inclus)

  • Setup tooling/esling : 2 j.h.
  • Fonctionnel :
    • authentification : 1 j.h
    • crud post/topics : 2 j.h
  • Montage/infra (mongo, nginx) : 3 j.h

Sur les tests

  • Framework de tests
  • Test postman : plus haut niveau que unitaires : intégration
    • Définition du type de test : si "pas besoin de bouchon", alors c'est un test d'intégration
    • Si on ne sait pas comment tester, c'est que le génie logiciel est mal organisé

Génie logiciel

  • Le contrôleur ne devrait pas dépendre de la couche de routage http
    • ne devrait donc pas avoir (req, res, next) en paramètre, juste le métier
    • typiquement, le métier est intestable au niveau unitaire
    • introduire une indirection entre la route express et le métier
  • Pagination : "standard" pour une application pro

About

Backend pour le projet de LIFAP5 en L2 informatique UCBL

License:GNU Lesser General Public License v3.0


Languages

Language:JavaScript 69.5%Language:Shell 19.3%Language:HTML 5.8%Language:Python 4.6%Language:Makefile 0.9%