Patientns

Intégration continue pour les nuls 25 septembre 2017

par Charles Stephan

A la fois note et article, voici en français, une vulgarisation et présentation de tout le process de déploiement d’un projet node | pm2 | mongo | Git etc, sur un vps ovh en intégration continue grâce à git (et bitbucket).
Thanks @mati and @lengstorf

Au sommaire :

  • Quel serveur ?
  • Installation de base d’un serveur
    • Sécurité
    • Apt
    • Node
    • Git
    • Pm2
    • Lets encrypt pour faire du "https"
    • Nginx
    • Webhook Bitbucket pour un intégration continue.
    • Mongo
  • Arrivé ici on (je) sera content !

Introduction

Cherchant à être les plus indépendants et généralistes, déployer ses applications sur des serveurs étaient quelque chose qui nous paraissaient technique mais qui s’est avéré être encore un abus dialectique.

Bref.
En fait un serveur dit dédié, c’est un serveur qu’un hébergeur vous loue.
Il vous le met à disposition avec un minimum de logiciels - pas d’OS (windows linux mac) - et on y touche via un terminal.

En effet il vous faudra accéder à votre serveur via cette interface très épuré, et qui fait hyper technique pour se la raconter en public et impressionner les impressionables...!

On tapera donc pas mal de choses ici. Et dans les Internets vous trouverez les ordres à taper toujours devant un $
Exemple :
$ ls
Listera les fichiers du dossier courant (celui où le terminal se trouve)

Ici "LesMoutonsSauvages" mon dossier mac racine 🏠

Quel serveur ?

Alors après avoir testé plusieurs hébergeurs, j’ai fini par - encore - préférer les vps OVH (encore une fois) non seulement car la disponibilité est là et que les prix sont moins chers que le numéro 2 très en vogue (digitalOcéan).

SSD OVH : 2,99 €/mois
Digital Ocean : 5$/mois
11 Septembre 2017

Sur ce serveur vous pourrez déposer vos applications et en héberger autant que l’espace le permettra.

Installation

Une fois contracté, OVH vous envoi un mail avec des identifiants de connexion à votre nouveau serveur : root + son mots de passe.
Root c’est l’accès BIG BOSS au serveur - un statut super utilisateur (SUDO)
C’est aussi l’identifiant avec lequel les méchants robots - qui sont là pour vous décourager et vous pourrir votre serveur - chercherons à overtester pour y faire correspondre votre mot de passe et pourrir la toile de penis enlarger & free viagra.

C’est pour cela que l’une des premières choses que nous ferons c’est d’en créer un autre à votre nom et d’interdire l’accès à via ce login de BIG BOSS.

Pour se connecter on utilise un logiciel "ssh", normalement déjà présent sur votre machine.
$ ssh root@ipRecu
Puis saisissez le mots de passe reçu, vous voici sur votre serveur.

APT
Apt est le gestionnaire de paquets de votre serveur.
Il nous permettra d’installer node et d’autres logiciels.

Première chose à faire c’est mettre à jour le serveur.

$ apt-get update
$ apt-get upgrade

SECURITÉ
$ adduser snoopy
Qui vous permettra donc snoopy@ipRecu
Puis Choisissez votre mots de passe.

Modifions notre nouvel utilisateur (user) pour lui donner le status BIG BOSS

$ usermod -aG sudo snoopy
* Snoopy devient (sudo:super user do) membre des BIG BOSS’s

$ exit
Quittez votre serveur et re-connectez y vous avec votre nouveau login.
$ ssh snoopy@ipRecu

Maintenant nous allons empecher la connection avec root@.
Il nous faut éditer un fichier de configuration des connexions ssh.
Pour éditer un fichier, on va utiliser un logiciel "nano" (ou "vim") suivi du chemin du fichier que l’on souhaite toucher.
$ sudo nano /etc/ssh/sshd_config

Vous entrez dans un éditeur assez rustre mais efficace rassurez vous.
Situer et changer 2 lignes :
- #PasswordAuthentication yes en PasswordAuthentication no
- PermitRootLogin yes en PermitRootLogin no
Pour sauvegarder il faut quitter (Ctrl + x) puis dire Y(es) ou N(o) et entré.

Et maintenant il nous faut redemarrer le service qui gère les connexions ssh.
$ sudo systemctl reload sshd
$ exit
En tentant de vous reconnecter en @root vous pourrez vérifier que votre config à fonctionné si votre connection échoue.

Mais restons sur notre lancé et configurons un firewall ufw (un process qui gère qui peut requêter votre serveur)

# Activer OpenSSH connections
$ sudo ufw allow OpenSSH
# Activer HTTP
$ sudo ufw allow http
# Activer HTTPS
$ sudo ufw allow https
# Activer ce firewall
$ sudo ufw enable

GIT
Installons git.
Git est (désormais) LE logiciel de gestion de version
Lorsque vous changer un bout de votre code, il note les diff (comme le vesionning de word) et les conserve pour assurer un code partageable en équipe et un suivi.
$ sudo apt-get install git

NODE.JS
$ sudo apt-get install nodejs

Normalement si vous ne vous êtes pas déplacé sur votre serveur vous êtes toujours dans le dossier /home, tant mieux c’est le meilleur endroit où mettre vos applications.
Pour les débutants, pas de panique, il s’agit ni plus ni moins qu’un dossier similaire au dossier de votre bureau d’ordinateur. On y met des fichiers, on en retire, etc...

Ajoutons donc votre projet que vous hébergez soit chez bitbucket ou github.

_ # Si vous vous êtes déplacé cette commande vous ramène normalement à home
$ cd ~

# Mk dir = make directory => créer son dossier
$ mkdir mes_apps

# Command direrctory = Rentrer dans le dossier
$ cd mes_apps/

# Cloner votre app depuis votre compte bitbucket ou git.
# Cette adresse est donnée précisément sur la page de votre projet.

$ git clone https://bitbucket.com/votrecompte/votreprojet.git

Installons maintenant un manager de processus - PM2

Un manager de processus est un outil qui vous permettra de veiller à ce que votre application tourne en permanence.
En effet pour plusieurs raison voter appli peut s’éteindre :

  • Votre application crash
  • Votre hebergeur fait des changements et provoque un redemarrage du serveur
  • Vous redemarrez votre serveur
  • On sait jamais

PM2 va donc s’occuper de tout cela.
Aussi vous pourriez utiliser des applications js genre forever mais vous verrez que pm2 est définitivement au top en ce moment
Pour l’installer

$ sudo npm install -g pm2
Bon : Pm2 s’instancie de cette maniere si vous êtes bien dans le dossier de votre app
Pour info : ../ permet de remonter un dossier, cd nom_du_dossier permet d’y rentrer.
Vous notterez que votre position dans les dossier est écrit à gauche du dollard <($)

$ pm2 start votreApp
Là votre pm2 doit être au vert.

Vous benéficiez aussi de pm2 start votreApp, pm2 stop votreApp, pm2 restart votreApp & pm2 logs votreApp —lines 200
plus d’info : http://pm2.keymetrics.io/docs/usage/quick-start/

Enfin on va ordonner à pm2 qu’il redémarre CETTE application.
$ pm2 startup
Pm2 va vous écrire une commande à copier coller et executer en "sudo" pour finaliser tout ceci

DONE !

Maintenant on va créer un certificat ssl pour faire du https et se la raconter devant des devs

$ sudo apt-get install bc
$ sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt

Puis

$ cd /opt/letsencrypt
./certbot-auto certonly --standalone

Répondez aux questions.

Là il faut qu’on s’assure que le certificat valable que 90 jours se renouvelle automatiquement : comme ca :

$ /opt/letsencrypt/certbot-auto renew
$ sudo crontab -e

Et choississer nano, l’éditeur vu plus haut
Copiez ces lignes enregistrez et fermez.

00 1 * * 1 /opt/letsencrypt/certbot-auto renew >> /var/log/letsencrypt-renewal.log
30 1 * * 1 /bin/systemctl reload nginx

NGINX - Pour gérer les domaines et routes vers nos applications

On garde le rythme et :
$ sudo apt-get install nginx

Et on édite les paramètres :
$ sudo nano /etc/nginx/sites-enabled/default

Et on va rediriger tout ce qui n’est pas https vers http.

server {
   listen 80;
   listen [::]:80 default_server ipv6only=on;
   return 301 https://$host$request_uri;
}

Comme on est des digues on va rajouter une couche de sécurité

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
        $ sudo nano /etc/nginx/snippets/ssl-params.conf

et collez dedans

        # See https://cipherli.st/ for details on this configuration
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
        ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off; # Requires nginx >= 1.5.9
        ssl_stapling on; # Requires nginx >= 1.3.7
        ssl_stapling_verify on; # Requires nginx => 1.3.7
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 5s;
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        # Add our strong Diffie-Hellman group
        ssl_dhparam /etc/ssl/certs/dhparam.pem;

On enregistre.

Maintenant on va configurer notre nginx vers notre application toujours dans sites-enabled on édite à la suite
$ sudo nano /etc/nginx/sites-enabled/default

En remplacant app.example.com par votre domaine
A la ligne proxy_pass, faites bien attention à taper sur le port de votre app !

server {
   # Enable HTTP/2
   listen 443 ssl http2;
   listen [::]:443 ssl http2;
   server_name app.example.com;

   # Use the Let’s Encrypt certificates
   ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

   # Include the SSL configuration from cipherli.st
   include snippets/ssl-params.conf;

   location / {
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-NginX-Proxy true;
       proxy_pass http://localhost:5000/;
       proxy_ssl_session_reuse off;
       proxy_set_header Host $http_host;
       proxy_cache_bypass $http_upgrade;
       proxy_redirect off;
       # DECOMMANTEZ CES LIGNES SI VOUS UTILISEZ SOCKET.IO
       #proxy_http_version 1.1;
       #proxy_set_header Upgrade $http_upgrade;
       #proxy_set_header Connection "upgrade";
       #proxy_set_header Host $host;
   }
}

Apres avoir enregistrer, nginx vous propose une commande pour vérifier votre configuration :

        $ sudo nginx -t
        nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
        nginx: configuration file /etc/nginx/nginx.conf test is successful

Enfin on active Nginx

sudo systemctl start nginx

Vous pouvez visiter votre domaine et constater que votre applic tourne !

On est content ?

Faisons un point, nous avons notre appli sécurisée en https gérée par nginx qui tourne grace à pm2.
Mais me direz vous : - "Mais euh Mon appli a besoin de mongo !!"

Calmeuuuh toiiii !, on y va

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927
$ echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list

Et on met à jour la liste

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

Comme d’hab, on parametre avec nano :
$ sudo nano /etc/systemd/system/mongodb.service
Et on y insère ce schéma

[Unit]
Description=High-performance, schema-free document-oriented database
After=network.target

[Service]
User=mongodb
ExecStart=/usr/bin/mongod --quiet --config /etc/mongod.conf

[Install]
WantedBy=multi-user.target

On démarre :

        $ sudo systemctl start mongodb
        $ sudo systemctl status mongodb
        On doit voir du vert là !!

Enfin on demande à ce que mongodb soit activé à chaque fois que le système démarre.

        $ sudo systemctl enable mongodb

Wala on est pas bien là ?

Passons à la dernière étape pour vraiment se la raconter.

Webhook Bitbucket ou github - L’intégration continue

Là le but de l’opération est de créer une route dans votre application node qui permet de git puller et redemarrer l’application.

Exemple : J’ai fais une modif, je push, quand bitbucket recoit le push, il interroge une url de mon appli, qui ordonne à git de récupérer le code et de redemarrer l’application.

Un fichier .sh est un fichier qui contient une suite d’ordres (de commandes) tels que vous les avez tapés tout au long de ce tuto.
$ ls
$ fais ci
$ fais ca

Voici celui que je vous propose hyper con ! : deploy.sh à la racine de votre projet node.

git pull
npm install
pm2 restart npm

Ici je vous le propose en express js et en mode roublard :
Préalable : rajouter un fichier vide au nom de log à la racine de votre projet node.

const execute  =    require('child_process').exec
,    fs        =    require("fs")
,    log       =    'log'
,    script    =    'sh deploy.sh'

app.use('/deploy', function(req, res) {
   
   // Le non roublard checkerai ici la requête pour rejeter tout ce qui ne viendrais pas de bitbucket ou github

   execute([script, '>>', log, '2>&1'].join(' '));
   res.writeHead(200);
   return res.end('Okay');
})

app.use('/log', function(req, res) {
   res.writeHead(200);
   return fs.createReadStream(log).pipe(res);
})

Donc on comprend que si /deploy est interrogé, le sript s’éxecutera. Les logs seront projetés dans /log.

Passons à la config chez Bitbutcket (mon préféré)

Dans "parametres" de votre repo > Webhooks > Create

Entrez la route que nous venons de configurer : app.example.com/deploy

Et le tour est joué.!

Félicitations !

Références :

Remonter