Tutorial

Comment automatiser vos déploiements de production Node.js avec Shipit sur CentOS 7

CentOSNode.jsGitJavaScript

L'auteur a choisi Electronic Frontier Foundation pour recevoir un don dans le cadre du programme Write for DOnations.

Introduction

Shipit est un outil universel d'automatisation et de déploiement pour les développeurs Node.js. Il comporte un flux de tâches basé sur le célèbre package Orchestrator, des commandes de connexion et de SSH interactif via OpenSSH, et une API extensible.  Les développeurs peuvent utiliser Shipit pour automatiser les flux de construction et de déploiement d'un large éventail d'applications Node.js.

Le flux de travail Shipit permet aux développeurs non seulement de configurer les tâches, mais aussi de spécifier l'ordre dans lequel elles sont exécutées, si elles doivent être exécutées de manière synchrone ou asynchrone et sur quel environnement.

Dans ce tutoriel, vous installerez et configurerez Shipit pour déployer une application Node.js depuis votre environnement de développement local vers votre environnement de production. Vous utiliserez Shipit pour déployer votre application et configurer le serveur distant en :

  • transférant les fichiers de votre application Node.js de votre environnement local vers l'environnement de production (en utilisant rsync, git et ssh).
  • installant les dépendances de votre application (modules node).
  • configurant et en gérant les processus Node.js s'exécutant sur le serveur distant avec PM2.

Conditions préalables

Avant de commencer ce guide, vous aurez besoin des éléments suivants :

Remarque : les utilisateurs de Windows devront installer le sous-système Windows pour Linux pour exécuter les commandes de ce guide.

Étape 1 - Mise en place du référentiel distant

Shipit requiert un référentiel Git pour la synchronisation entre la machine de développement locale et le serveur distant. Dans cette étape, vous allez créer un référentiel distant sur Github.com. Bien que chaque fournisseur soit légèrement différent, les commandes sont en général assez similaires.

Pour créer un référentiel, ouvrez Github.com dans votre navigateur web et connectez-vous. Vous remarquerez que dans le coin supérieur droit de chaque page, se trouve un symbole +. Cliquez sur +, puis sur New repository (Nouveau référentiel).

Nouveau référentiel Github

Tapez un nom court et facile à retenir pour votre référentiel, par exemple, hello-world. Notez que le nom que vous choisissez ici sera reproduit comme le dossier du projet à partir duquel vous travaillerez sur votre machine locale.

Nom du référentiel Github

Vous pouvez si vous le souhaitez ajouter une description de votre référentiel.

Description du référentiel Github

Définissez le mode de visibilité de votre référentiel selon votre préférence, public ou privé.

Assurez-vous que le référentiel est initialisé avec un .gitignore, choisissez Node dans la liste déroulante Add .gitignore. Cette étape est importante pour éviter d'ajouter à votre référentiel des fichiers inutiles (comme le dossier node_modules).

Github-gitignore-node

Cliquez sur le bouton Create repository​​​ (​Créer un référentiel).

Le référentiel doit maintenant être cloné depuis Github.com sur votre machine locale.

Ouvrez votre terminal et naviguez à l'endroit où vous souhaitez stocker tous vos fichiers du projet Node.js. Notez que ce processus créera un sous-dossier dans le répertoire actuel. Pour cloner le référentiel sur votre machine locale, exécutez la commande suivante :

  • git clone https://github.com/your-github-username/your-github-repository-name.git

Vous devrez remplacer your-github-username et your-github-repository-name pour refléter votre nom d'utilisateur Github et le nom du référentiel précédemment fourni.

Remarque : si vous avez activé une authentification à deux facteurs (2FA) sur Github.com, vous devez utiliser un jeton d'accès personnel ou une clé SSH au lieu de votre mot de passe lors de l'accès à Github en ligne de commande. La page d'aide Github liée à 2FA fournit de plus amples informations.

Vous verrez un résultat semblable à :

Output
Cloning into 'your-github-repository-name'... remote: Enumerating objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3 Unpacking objects: 100% (3/3), done.

Déplacez-vous vers le référentiel en exécutant la commande suivante :

  • cd your-github-repository-name

À l'intérieur du référentiel se trouvent un seul fichier et un seul dossier, qui sont tous deux utilisés par Git pour gérer le référentiel. Vous pouvez le vérifier avec :

  • ls -la

Vous verrez une sortie semblable à ce qui suit :

Output
total 8 0 drwxr-xr-x 4 asciant staff 128 22 Apr 07:16 . 0 drwxr-xr-x 5 asciant staff 160 22 Apr 07:16 .. 0 drwxr-xr-x 13 asciant staff 416 22 Apr 07:16 .git 8 -rw-r--r-- 1 asciant staff 914 22 Apr 07:16 .gitignore

Maintenant que vous avez configuré un référentiel git fonctionnel, vous allez créer le fichier shipit.js qui gère votre processus de déploiement.

Étape 2 - Intégration de Shipit dans un projet Node.js

Dans cette étape, vous allez créer un exemple de projet Node.js, puis ajouter les packages Shipit. Ce tutoriel fournit un exemple d'application : le serveur web Node.js qui accepte les requêtes HTTP et répond avec Hello World en texte clair. Pour créer l'application, exécutez la commande suivante :

  • nano hello.js

Ajoutez l'exemple de code d'application suivant à hello.js (en mettant à jour la variable APP_PRIVATE_IP_ADDRESS à l'adresse IP du réseau privé de votre serveur app) :

hello.js
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8080, 'APP_PRIVATE_IP_ADDRESS');
console.log('Server running at http://APP_PRIVATE_IP_ADDRESS:8080/');

Maintenant, créez votre fichier package.json pour votre application :

  • npm init -y

Cette commande crée un fichier package.json, que vous utiliserez pour configurer votre application Node.js. Dans l'étape suivante, vous ajouterez des dépendances à ce fichier avec l'interface de ligne de commande npm.

Output
Wrote to ~/hello-world/package.json: { "name": "hello-world", "version": "1.0.0", "description": "", "main": index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

Ensuite, installez les packages npm nécessaires avec la commande suivante :

  • npm install --save-dev shipit-cli shipit-deploy shipit-shared

Vous utilisez l'indicateur --save-dev ici puisque les packages Shipit ne sont requis que sur votre machine locale. Vous verrez une sortie semblable à ce qui suit :

Output
+ shipit-shared@4.4.2 + shipit-cli@4.2.0 + shipit-deploy@4.1.4 updated 4 packages and audited 21356 packages in 11.671s found 62 low severity vulnerabilities run `npm audit fix` to fix them, or `npm audit` for details

Cela a également ajouté les trois packages à votre fichier package.json en tant que dépendances de développement :

package.json
. . .
  "devDependencies": {
    "shipit-cli": "^4.2.0",
    "shipit-deploy": "^4.1.4",
    "shipit-shared": "^4.4.2"
  },
. . .

Votre environnement local étant configuré, vous pouvez maintenant passer à la préparation du serveur app distant pour les déploiements basés sur Shipit.

Étape 3 - Préparation du serveur app distant

Dans cette étape, vous utiliserez ssh pour vous connecter à votre serveur app et installer votre dépendance à distance rsync. Rsync est un utilitaire permettant de transférer et de synchroniser efficacement des fichiers entre des lecteurs d'ordinateurs locaux et entre des ordinateurs en réseau, en comparant les heures de modification et les tailles des fichiers.

Shipit utilise rsync pour transférer et synchroniser des fichiers entre votre ordinateur local et le serveur app distant. Vous ne délivrerez pas directement de commandes à rsync, Shipit gérera cela pour vous.

Remaque : en suivant le tutoriel Comment mettre en place une application Node.js pour la production sur CentOS 7, vous avez créé deux serveurs app et web. Ces commandes doivent être exécutées uniquement sur app.

Connectez-vous à votre serveur app distant via ssh :

  • ssh deployer@your_app_server_ip

Installez rsync sur votre serveur en exécutant la commande suivante :

  • sudo yum install rsync

Vérifiez l'installation avec :

  • rsync --version

Vous verrez une ligne similaire dans la sortie de cette commande :

Output
rsync version 3.1.2 protocol version 31 . . .

Vous pouvez mettre fin à votre session ssh en entrant exit.

Maintenant que rsync est installé et disponible sur la ligne de commande, vous pouvez passer aux tâches de déploiement et à leur relation avec les événements.

Étape 4 - Configuration et exécution des tâches de déploiement

Les événements et les tâches sont des éléments clés des déploiements Shipit et il est important de comprendre comment ils complètent le déploiement de votre application. Les événements déclenchés par Shipit représentent des points spécifiques du cycle de vie du déploiement. Vos tâches seront exécutées en réponse à ces événements, en fonction de la séquence du cycle de vie de Shipit.

Un exemple courant de l'utilité de ce système de tâches/événements dans une application Node.js est l'installation des dépendances de l'application (node_modules) sur le serveur distant. Plus tard dans cette étape, vous demanderez à Shipit d'écouter l'événement updated (qui est émis après le transfert des fichiers de l'application) et d'exécuter une tâche pour installer les dépendances de l'application (npm install) sur le serveur distant.

Pour écouter les événements et exécuter les tâches, Shipit a besoin d'un fichier de configuration qui contient des informations sur votre serveur distant (le serveur app) et enregistre les auditeurs d'événements et les commandes à exécuter par ces tâches. Ce fichier vit sur votre ordinateur de développement local, à l'intérieur du répertoire de votre application Node.js.

Pour commencer, créez ce fichier, en y incluant des informations sur votre serveur distant, les auditeurs d'événements auxquels vous voulez vous abonner, et quelques définitions de vos tâches. Créez shipitfile.js dans le répertoire racine de votre application sur votre machine locale en exécutant la commande suivante :

  • nano shipitfile.js

Maintenant que vous avez créé un fichier, il doit être alimenté avec les informations initiales sur l'environnement dont Shipit a besoin. C'est principalement la localisation de votre référentiel Git distant et, plus important encore, l'adresse IP publique de votre serveur app et votre compte utilisateur SSH.

Ajoutez cette configuration initiale et mettez à jour les lignes surlignées pour qu'elles correspondent à votre environnement :

shipitfile.js
module.exports = shipit => {
  require('shipit-deploy')(shipit);
  require('shipit-shared')(shipit);

  const appName = 'hello';

  shipit.initConfig({
    default: {
      deployTo: '/home/sammy/your-domain',
      repositoryUrl: 'https://git-provider.tld/YOUR_GIT_USERNAME/YOUR_GIT_REPO_NAME.git',
      keepReleases: 5,
      shared: {
        overwrite: true,
        dirs: ['node_modules']
      }
    },
    production: {
      servers: 'sammy@YOUR_APP_SERVER_PUBLIC_IP'
    }
  });

  const path = require('path');
  const ecosystemFilePath = path.join(
    shipit.config.deployTo,
    'shared',
    'ecosystem.config.js'
  );

  // Our listeners and tasks will go here

};

La mise à jour des variables dans votre méthode shipit.initConfig fournit à Shipit une configuration spécifique pour votre déploiement. Elles représentent ce qui suit pour Shipit :

  • deployTo: est le répertoire où Shipit déploiera le code de votre application sur le serveur distant. Ici, vous utilisez le dossier /home/ pour un utilisateur non root avec des privilèges sudo (/home/sammy) car il est sécurisé et évitera les problèmes de permission. Le composant /your-domain est une convention d'appellation permettant de distinguer le dossier des autres dans le dossier personnel de l'utilisateur.
  • repositoryUrl: est l'URL pour le référentiel Git complet. Shipit utilisera cette URL pour s'assurer que les fichiers du projet sont synchronisés avant le déploiement.
  • keepReleases:​​​​ est le nombre de versions à garder sur le serveur distant. Une release (version mise en production) est un dossier daté contenant les fichiers de votre application au moment de la release. Cela peut être utile pour le rollback (annulation) d'un déploiement.
  • shared: est une configuration qui correspond aux keepReleases et qui permet à des répertoires d'être shared (partagés) entre des releases. Dans le cas présent, nous avons un seul dossier node_modules qui est partagé entre toutes les releases.
  • production: représente un serveur distant sur lequel déployer votre application. Dans ce cas, vous avez un seul serveur (serveur app) que vous nommez production, avec la configuration servers: correspondant à vos variables user SSH et public ip address. Le nom production, correspond à la commande Shipit deploy utilisée vers la fin de ce tutoriel (npx shipit server name deploy ou dans votre cas npx shipit production deploy).

De plus amples informations sur l'objet Shipit Deploy Configuration peuvent être trouvées dans le référentiel Github Shipit.

Avant de continuer à mettre à jour votre shipitfile.js, examinons l'exemple de code suivant pour comprendre les tâches de Shipit :

Example event listener
shipit.on('deploy', () => { shipit.start('say-hello'); }); shipit.blTask('say-hello', async () => { shipit.local('echo "hello from your local computer"') });

C'est un exemple de tâche qui utilise la méthode shipit.on pour souscrire à l'événement deploy. Cette tâche attend que l'événement deploy soit émis par le cycle de vie de Shipit, puis lorsque l'événement est reçu, la tâche exécute la méthode shipit.start qui indique à Shipit de start (lancer) la tâche say- hello.

La méthode shipit.on prend deux paramètres, le nom de l'événement à écouter et la fonction de rappel à exécuter lorsque l'événement est reçu.

Dans la déclaration de la méthode shipit.on, la tâche est définie avec la méthode shipit.blTask. Cela crée une nouvelle tâche Shipit qui bloque d'autres tâches pendant son exécution (il s'agit d'une tâche synchrone). La méthode shipit.blTask prend également deux paramètres, le nom de la tâche qu'elle définit et une fonction de rappel à exécuter lorsque la tâche est déclenchée par shipit.start.

Dans la fonction de rappel de cet exemple de tâche (say-hello), la méthode shipit.local exécute une commande sur la machine locale. La commande locale envoie un message "hello from your local computer" (bonjour de votre ordinateur local) à la sortie du terminal.

Si vous vouliez exécuter une commande sur le serveur distant, vous devriez utiliser la méthode shipit.remote. Les deux méthodes, shipit.local et shipit.remote, fournissent une API pour délivrer des commandes locales, ou à distance dans le cadre d'un déploiement.

Mettez maintenant à jour le shipitfile.js afin d'inclure les auditeurs des événements devant souscrire au cycle de vie de Shipit avec shipit.on. Ajoutez les auditeurs des événements à votre shipitfile.js, en les insérant à la suite de l'espace réservé de commentaire de la configuration initiale // Our tasks will go here (Nos tâches iront ici) :

shipitfile.js
. . .
  shipit.on('updated', () => {
    shipit.start('npm-install', 'copy-config');
  });

  shipit.on('published', () => {
    shipit.start('pm2-server');
  });

Ces deux méthodes sont à l'écoute des événements updated (mis à jour) et published (publiés) qui sont émis dans le cadre du cycle de vie du déploiement de Shipit. Lorsque l'événement est reçu, elles lanceront chacune des tâches en utilisant la méthode shipit.start, de la même manière que la tâche exemple.

Maintenant que vous avez programmé les auditeurs, vous allez ajouter la tâche correspondante. Ajoutez la tâche suivante à votre shipitfile.js, en l'insérant après vos auditeurs d'événements :

shipitfile.js
. . .
shipit.blTask('copy-config', async () => {

const fs = require('fs');

const ecosystem = `
module.exports = {
apps: [
  {
    name: '${appName}',
    script: '${shipit.releasePath}/hello.js',
    watch: true,
    autorestart: true,
    restart_delay: 1000,
    env: {
      NODE_ENV: 'development'
    },
    env_production: {
      NODE_ENV: 'production'
    }
  }
]
};`;

  fs.writeFileSync('ecosystem.config.js', ecosystem, function(err) {
    if (err) throw err;
    console.log('File created successfully.');
  });

  await shipit.copyToRemote('ecosystem.config.js', ecosystemFilePath);
});

Vous devez d'abord déclarer une tâche appelée copy-config. Cette tâche crée un fichier local appelé ecosystem.config.js puis copie ce fichier sur votre serveur app distant. PM2 utilise ce fichier pour gérer votre application Node.js. Cela fournit à PM2 les informations nécessaires sur le chemin d'accès aux fichiers afin de s'assurer qu'il exécute vos derniers fichiers déployés. Plus tard dans le processus de construction, vous créerez une tâche qui exécute PM2 avec ecosystem.config.js comme configuration.

Si votre application a besoin de variables d'environnement (comme une chaîne de connexion à une base de données), vous pouvez les déclarer soit localement dans env: soit sur le serveur distant dans env_production:, de la même manière que vous définissez la variable NODE_ENV dans ces objets.

Ajoutez la tâche suivante à votre shipitfile.js après la tâche copy-config :

shipitfile.js
. . .
shipit.blTask('npm-install', async () => {
  shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
});

Ensuite, vous déclarez une tâche appelée npm-install. Cette tâche utilise un terminal bash distant (via shipit.remote) pour installer les dépendances de l'application (packages npm).

Ajoutez la dernière tâche à votre shipitfile.js après la tâche npm-install :

shipitfile.js
. . .
shipit.blTask('pm2-server', async () => {
  await shipit.remote(`pm2 delete -s ${appName} || :`);
  await shipit.remote(
    `pm2 start ${ecosystemFilePath} --env production --watch true`
  );
});

Enfin, vous déclarez une tâche appelée pm2-server. Cette tâche utilise également un terminal bash distant pour d'abord empêcher PM2 de gérer votre déploiement précédent par la commande delete et ensuite démarrer une nouvelle instance de votre serveur Node.js en fournissant le fichier ecosystem.config.js comme variable. Vous donnez également pour instruction à PM2 d'utiliser les variables d'environnement du bloc production dans votre configuration initiale et demandez à PM2 de surveiller l'application, en la redémarrant si elle plante.

Le fichier shipitfile.js complet :

shipitfile.js
module.exports = shipit => {
  require('shipit-deploy')(shipit);
  require('shipit-shared')(shipit);

  const appName = 'hello';

  shipit.initConfig({
    default: {
      deployTo: '/home/deployer/example.com',
      repositoryUrl: 'https://git-provider.tld/YOUR_GIT_USERNAME/YOUR_GIT_REPO_NAME.git',
      keepReleases: 5,
      shared: {
        overwrite: true,
        dirs: ['node_modules']
      }
    },
    production: {
      servers: 'deployer@YOUR_APP_SERVER_PUBLIC_IP'
    }
  });

  const path = require('path');
  const ecosystemFilePath = path.join(
    shipit.config.deployTo,
    'shared',
    'ecosystem.config.js'
  );

  // Our listeners and tasks will go here
  shipit.on('updated', async () => {
    shipit.start('npm-install', 'copy-config');
  });

  shipit.on('published', async () => {
    shipit.start('pm2-server');
  });

  shipit.blTask('copy-config', async () => {
    const fs = require('fs');
    const ecosystem = `
module.exports = {
  apps: [
    {
      name: '${appName}',
      script: '${shipit.releasePath}/hello.js',
      watch: true,
      autorestart: true,
      restart_delay: 1000,
      env: {
        NODE_ENV: 'development'
      },
      env_production: {
        NODE_ENV: 'production'
      }
    }
  ]
};`;

    fs.writeFileSync('ecosystem.config.js', ecosystem, function(err) {
      if (err) throw err;
      console.log('File created successfully.');
    });

    await shipit.copyToRemote('ecosystem.config.js', ecosystemFilePath);
  });

  shipit.blTask('npm-install', async () => {
    shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
  });

  shipit.blTask('pm2-server', async () => {
    await shipit.remote(`pm2 delete -s ${appName} || :`);
    await shipit.remote(
      `pm2 start ${ecosystemFilePath} --env production --watch true`
    );
  });
};

Enregistrez et quittez le fichier lorsque vous êtes prêt.

Une fois votre shipitfile.js configuré, les auditeurs d'événements définis et les tâches associées finalisées, vous pouvez passer au déploiement sur le serveur app.

Étape 5 - Déploiement de votre application

Au cours de cette étape, vous déploierez votre application à distance et vérifierez que le déploiement a mis votre application à disposition sur Internet.

Comme Shipit clone les fichiers du projet à partir du référentiel Git distant, vous devez pousser les fichiers d'application Node.js de votre machine locale vers Github. Naviguez jusqu'au répertoire d'application de votre projet Node.js (où se trouvent vos fichiers hello.js et shiptitfile.js) et exécutez la commande suivante :

  • git status

La commande git status affiche l'état du répertoire de travail et de la zone de transit. Cela vous permet de voir quels changements ont été mis en place, lesquels ne l'ont pas été et quels fichiers ne sont pas suivis par Git. Vos fichiers ne sont pas tracés et apparaissent en rouge dans la sortie :

Output
On branch master Your branch is up to date with 'origin/master'. Untracked files: (use "git add <file>..." to include in what will be committed) hello.js package-lock.json package.json shipitfile.js nothing added to commit but untracked files present (use "git add" to track)

Vous pouvez ajouter ces fichiers à votre référentiel avec la commande suivante :

  • git add --all

Cette commande ne produit aucune sortie, bien que si vous deviez exécuter à nouveau git status, les fichiers apparaîtraient en vert avec une note indiquant qu'il y a des modifications à commiter.

Vous pouvez créer un commit en exécutant la commande suivante :

  • git commit -m "Our first commit"

La sortie de cette commande fournit des informations spécifiques à Git sur les fichiers.

Output
[master c64ea03] Our first commit 4 files changed, 1948 insertions(+) create mode 100644 hello.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 shipitfile.js

Il ne reste plus qu'à pousser votre commit vers le référentiel distant pour que Shipit le clone sur votre serveur app pendant le déploiement. Exécutez la commande suivante :

  • git push origin master

La sortie comprend des informations sur la synchronisation avec le référentiel distant :

Output
Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 8 threads Compressing objects: 100% (6/6), done. Writing objects: 100% (6/6), 15.27 KiB | 7.64 MiB/s, done. Total 6 (delta 0), reused 0 (delta 0) To github.com:Asciant/hello-world.git e274312..c64ea03 master -> master

Pour déployer votre application, exécutez la commande suivante :

  • npx shipit production deploy

Le résultat de cette commande (qui est trop volumineux pour être inclus dans son intégralité) fournit des détails sur les tâches exécutées et le résultat de la fonction spécifique. La sortie suivante pour la tâche pm2-server montre que l'application Node.js a été lancée :

Output
Running 'deploy:init' task... Finished 'deploy:init' after 432 μs . . . Running 'pm2-server' task... Running "pm2 delete -s hello || :" on host "centos-ap-app.asciant.com". Running "pm2 start /home/deployer/example.com/shared/ecosystem.config.js --env production --watch true" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com [PM2][WARN] Node 4 is deprecated, please upgrade to use pm2 to have all features @centos-ap-app.asciant.com [PM2][WARN] Applications hello not running, starting... @centos-ap-app.asciant.com [PM2] App [hello] launched (1 instances) @centos-ap-app.asciant.com ┌──────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬─────┬──────────┬──────────┬──────────┐ @centos-ap-app.asciant.com │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ @centos-ap-app.asciant.com ├──────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼─────┼──────────┼──────────┼──────────┤ @centos-ap-app.asciant.com │ hello │ 0 │ 1.0.0 │ fork │ 4177 │ online │ 0 │ 0s │ 0% │ 4.5 MB │ deployer │ enabled │ @centos-ap-app.asciant.com └──────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴─────┴──────────┴──────────┴──────────┘ @centos-ap-app.asciant.com Use `pm2 show <id|name>` to get more details about an app Finished 'pm2-server' after 5.27 s Running 'deploy:clean' task... Keeping "5" last releases, cleaning others Running "(ls -rd /home/deployer/example.com/releases/*|head -n 5;ls -d /home/deployer/example.com/releases/*)|sort|uniq -u|xargs rm -rf" on host "centos-ap-app.asciant.com". Finished 'deploy:clean' after 1.81 s Running 'deploy:finish' task... Finished 'deploy:finish' after 222 μs Finished 'deploy' [ deploy:init, deploy:fetch, deploy:update, deploy:publish, deploy:clean, deploy:finish ]

Pour visualiser votre application comme un utilisateur le ferait, vous pouvez saisir l'URL de votre site your-domain dans votre navigateur pour accéder à votre serveur web. Cela servira l'application Node.js, via le proxy inverse, sur le serveur app où vos fichiers ont été déployés.

Vous verrez un message d'accueil Hello World.

Remarque : après le premier déploiement, votre référentiel Git suivra un fichier nouvellement créé nommé ecosystem.config.js. Comme ce fichier sera reconstruit à chaque déploiement, et peut contenir des secrets d'application compilés, il doit être ajouté au fichier .gitignore dans le répertoire racine de l'application sur votre machine locale avant votre prochain commit git.

.gitignore
. . .
# ecosystem.config
ecosystem.config.js

Vous avez déployé votre application Node.js sur votre serveur app, qui fait référence à votre nouveau déploiement. Maintenant que tout est en place, vous pouvez passer à la surveillance de vos processus d'application.

Étape 6 - Surveillance de votre application

PM2 est un excellent outil pour gérer vos processus à distance, mais il offre également des fonctionnalités permettant de surveiller les performances de ces processus d'application.

Connectez-vous à votre serveur app distant via SSH avec cette commande :

  • ssh deployer@your_app_server_ip

Pour obtenir des informations spécifiques relatives à vos processus gérés par PM2, exécutez ce qui suit :

  • pm2 list

Vous verrez un résultat semblable à :

Output
┌─────────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬──────┬───────────┬──────────┬──────────┐ │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ ├─────────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼──────┼───────────┼──────────┼──────────┤ │ hello │ 0 │ 0.0.1 │ fork │ 3212 │ online │ 0 │ 62m │ 0.3% │ 45.2 MB │ deployer │ enabled │ └─────────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴──────┴───────────┴──────────┴──────────┘

Vous verrez un résumé des informations que PM2 a recueillies. Pour voir des informations détaillées, vous pouvez exécuter :

  • pm2 show hello

La sortie développe le résumé des informations fournies par la commande pm2 list. Elle fournit également des informations sur un certain nombre de commandes auxiliaires et indique l'emplacement des fichiers journaux :

Output
Describing process with id 0 - name hello ┌───────────────────┬─────────────────────────────────────────────────────────────┐ │ status │ online │ │ name │ hello │ │ version │ 1.0.0 │ │ restarts │ 0 │ │ uptime │ 82s │ │ script path │ /home/deployer/example.com/releases/20190531213027/hello.js │ │ script args │ N/A │ │ error log path │ /home/deployer/.pm2/logs/hello-error.log │ │ out log path │ /home/deployer/.pm2/logs/hello-out.log │ │ pid path │ /home/deployer/.pm2/pids/hello-0.pid │ │ interpreter │ node │ │ interpreter args │ N/A │ │ script id │ 0 │ │ exec cwd │ /home/deployer │ │ exec mode │ fork_mode │ │ node.js version │ 4.2.3 │ │ node env │ production │ │ watch & reload │ ✔ │ │ unstable restarts │ 0 │ │ created at │ 2019-05-31T21:30:48.334Z │ └───────────────────┴─────────────────────────────────────────────────────────────┘ Revision control metadata ┌──────────────────┬────────────────────────────────────────────────────┐ │ revision control │ git │ │ remote url │ N/A │ │ repository root │ /home/deployer/example.com/releases/20190531213027 │ │ last update │ 2019-05-31T21:30:48.559Z │ │ revision │ 62fba7c8c61c7769022484d0bfa46e756fac8099 │ │ comment │ Our first commit │ │ branch │ master │ └──────────────────┴────────────────────────────────────────────────────┘ Divergent env variables from local env ┌───────────────────────────┬───────────────────────────────────────┐ │ XDG_SESSION_ID │ 15 │ │ HOSTNAME │ N/A │ │ SELINUX_ROLE_REQUESTED │ │ │ TERM │ N/A │ │ HISTSIZE │ N/A │ │ SSH_CLIENT │ 44.222.77.111 58545 22 │ │ SELINUX_USE_CURRENT_RANGE │ │ │ SSH_TTY │ N/A │ │ LS_COLORS │ N/A │ │ MAIL │ /var/mail/deployer │ │ PATH │ /usr/local/bin:/usr/bin │ │ SELINUX_LEVEL_REQUESTED │ │ │ HISTCONTROL │ N/A │ │ SSH_CONNECTION │ 44.222.77.111 58545 209.97.167.252 22 │ └───────────────────────────┴───────────────────────────────────────┘ . . .

PM2 fournit également un outil de surveillance à l'intérieur du terminal, accessible avec :

  • pm2 monit

Le résultat de cette commande est un tableau de bord interactif, où pm2 fournit en temps réel des informations sur les processus, des journaux, des mesures et des métadonnées. Ce tableau de bord peut aider à surveiller les ressources et les journaux d'erreur :

Output
┌─ Process list ────────────────┐┌─ Global Logs ─────────────────────────────────────────────────────────────┐ │[ 0] hello Mem: 22 MB ││ │ │ ││ │ │ ││ │ └───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘ ┌─ Custom metrics (http://bit.l─┐┌─ Metadata ────────────────────────────────────────────────────────────────┐ │ Heap Size 10.73 ││ App Name hello │ │ Heap Usage 66.14 ││ Version N/A │ │ Used Heap Size 7.10 ││ Restarts 0 │ │ Active requests 0 ││ Uptime 55s │ │ Active handles 4 ││ Script path /home/asciant/hello.js │ │ Event Loop Latency 0.70 ││ Script args N/A │ │ Event Loop Latency p95 ││ Interpreter node │ │ ││ Interpreter args N/A │ └───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘

En comprenant comment vous pouvez surveiller vos processus avec PM2, vous pouvez passer à la façon dont Shipit peut vous aider à revenir à un déploiement de travail antérieur.

Terminez votre session ssh sur votre serveur app en exécutant exit.

Étape 7 - Annulation d'un déploiement défaillant

Les déploiements entraînent parfois l'apparition de bugs imprévus ou de problèmes qui provoquent la défaillance de votre site. Les développeurs et les responsables de la maintenance de Shipit ont anticipé cette situation et vous ont donné la possibilité de revenir au déploiement précédent (fonctionnel) de votre application.

Pour vous assurer que votre configuration PM2 persiste, ajoutez un autre auditeur d'événement à shipitfile.js sur l'événement rollback :

shipitfile.js
. . .
  shipit.on('rollback', () => {
    shipit.start('npm-install', 'copy-config');
  });

Vous ajoutez un auditeur à l'événement rollback pour exécuter vos tâches npm-install et copy-config. Cela est nécessaire car, contrairement à l'événement published, l'événement updated n'est pas géré par le cycle de vie de Shipit lors de l'annulation d'un déploiement. L'ajout de cet auditeur d'événements permet à votre gestionnaire de processus PM2 de pointer vers le déploiement le plus récent, même en cas de retour en arrière.

Ce processus est similaire au déploiement, avec un petit changement de commande. Pour essayer de revenir à un déploiement précédent, vous pouvez exécuter ce qui suit :

  • npx shipit production rollback

Comme la commande deploy, rollback fournit des détails sur le processus de retour en arrière et les tâches en cours d'exécution :

Output
Running 'rollback:init' task... Get current release dirname. Running "if [ -h /home/deployer/example.com/current ]; then readlink /home/deployer/example.com/current; fi" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com releases/20190531213719 Current release dirname : 20190531213719. Getting dist releases. Running "ls -r1 /home/deployer/example.com/releases" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com 20190531213719 @centos-ap-app.asciant.com 20190531213519 @centos-ap-app.asciant.com 20190531213027 Dist releases : ["20190531213719","20190531213519","20190531213027"]. Will rollback to 20190531213519. Finished 'rollback:init' after 3.96 s Running 'deploy:publish' task... Publishing release "/home/deployer/example.com/releases/20190531213519" Running "cd /home/deployer/example.com && if [ -d current ] && [ ! -L current ]; then echo "ERR: could not make symlink"; else ln -nfs releases/20190531213519 current_tmp && mv -fT current_tmp current; fi" on host "centos-ap-app.asciant.com". Release published. Finished 'deploy:publish' after 1.8 s Running 'pm2-server' task... Running "pm2 delete -s hello || :" on host "centos-ap-app.asciant.com". Running "pm2 start /home/deployer/example.com/shared/ecosystem.config.js --env production --watch true" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com [PM2][WARN] Node 4 is deprecated, please upgrade to use pm2 to have all features @centos-ap-app.asciant.com [PM2][WARN] Applications hello not running, starting... @centos-ap-app.asciant.com [PM2] App [hello] launched (1 instances) @centos-ap-app.asciant.com ┌──────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬─────┬──────────┬──────────┬──────────┐ @centos-ap-app.asciant.com │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ @centos-ap-app.asciant.com ├──────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼─────┼──────────┼──────────┼──────────┤ @centos-ap-app.asciant.com │ hello │ 0 │ 1.0.0 │ fork │ 4289 │ online │ 0 │ 0s │ 0% │ 4.5 MB │ deployer │ enabled │ @centos-ap-app.asciant.com └──────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴─────┴──────────┴──────────┴──────────┘ @centos-ap-app.asciant.com Use `pm2 show <id|name>` to get more details about an app Finished 'pm2-server' after 5.55 s Running 'deploy:clean' task... Keeping "5" last releases, cleaning others Running "(ls -rd /home/deployer/example.com/releases/*|head -n 5;ls -d /home/deployer/example.com/releases/*)|sort|uniq -u|xargs rm -rf" on host "centos-ap-app.asciant.com". Finished 'deploy:clean' after 1.82 s Running 'rollback:finish' task... Finished 'rollback:finish' after 615 μs Finished 'rollback' [ rollback:init, deploy:publish, deploy:clean, rollback:finish ]

Vous avez configuré Shipit pour conserver 5 releases par le biais de la fonction keepReleases: 5 dans shipitfile.js. Shipit garde une trace de ces releases en interne pour s'assurer qu'il est capable de revenir en arrière si nécessaire. Shipit fournit également un moyen pratique d'identifier les sorties en créant un répertoire nommé sous forme d'horodatage (AAAAMMJJHHmmss - Exemple : /home/deployer/your-domain/releases/20190420210548).

Si vous souhaitez personnaliser davantage le processus de retour en arrière, vous pouvez écouter les événements spécifiques à l'opération de roll back. Vous pouvez ensuite utiliser ces événements pour exécuter les tâches qui complètent votre retour en arrière. Vous pouvez vous référer à la liste d'événements fournie dans la répartition du cycle de vie de Shipit et configurer les tâches/auditeurs dans votre shipitfile.js.

La possibilité de revenir en arrière signifie que vous pouvez toujours fournir une version fonctionnelle de votre application à vos utilisateurs, même si un déploiement introduit des problèmes ou des bugs inattendus.

Conclusion

Dans ce tutoriel, vous avez configuré un flux de travail qui vous permet de créer une alternative hautement personnalisable à une solution PaaS (Platform as a Service), le tout à partir de quelques serveurs. Ce flux de travail permet un déploiement et une configuration personnalisés, le suivi des processus avec PM2, la possibilité de faire évoluer le système et d'ajouter des services, serveurs ou environnements supplémentaires au déploiement si nécessaire.

Si vous souhaitez continuer à développer vos compétences sur Node.js, consultez le contenu Node.js de DigitalOcean ainsi que la série Comment coder en Node.js.

0 Comments

Creative Commons License