Tutorial

Cómo automatizar implementaciones de producción de Node.js con Shipit en CentOS 7

CentOSNode.jsGitJavaScript

El autor seleccionó la Electronic Frontier Foundation para recibir una donación como parte del programa Write for DOnations.

Introducción

Shipit es una herramienta universal de automatización e implementación para desarrolladores de Node.js. Incluye un flujo de tareas basado en el popular paquete Orchestrator, comandos de inicio de sesión y SSH interactivos a través de OpenSSH y una API extensible. Los desarrolladores pueden usar Shipit a fni de automatizar flujos de trabajo de compilación e implementación para una amplia variedad de aplicaciones de Node.js.

El flujo de trabajo de Shipit no solo permite a los desarrolladores configurar tareas, sino también especificar su orden de ejecución; si deben ejecutarse de forma sincrónica o asincrónica y en qué entorno.

En este tutorial, instalará y configurará Shipit para implementar una aplicación de Node.js de su entorno de desarrollo local en su entorno de producción. Usará Shipit para implementar su aplicación y configurar el servidor remoto haciendo lo siguiente:

  • transfiriendo los archivos de su aplicación de Node.js de su entorno local al entorno de producción (con rsync, git y ssh);
  • instando las dependencias de su aplicación (módulos de nodos);
  • configurando y administrando los procesos de Node.js que se ejecutan en el servidor remoto con PM2.

Requisitos previos

Antes de iniciar este tutorial, necesitará lo siguiente:

Nota: Los usuarios de Windows deberán instalar el subsistema de Windows para Linux para ejecutar los comandos de esta guía.

Paso 1: Configurar el repositorio remoto

En Shipit se requiere un repositorio de Git para la sincronía entre la máquina de desarrollo local y el servidor remoto. En este paso, creará un repositorio remoto en Github.com. Si bien cada proveedor es ligeramente diferente, los comandos pueden ser transferibles.

Para crear un repositorio, abra Github.com en su navegador web e inicie sesión. Verá un símbolo + en la esquina superior derecha de cualquier página. Haga clic en + y luego en New repository.

Github-new-repository

Ingrese un nombre corto y recordable para su repositorio; por ejemplo, hello-world. Tenga en cuenta que cualquier nombre que elija aquí se replicará como la carpeta del proyecto a partir de la que trabajará en su máquina local.

Github-repository-name

De manera opcional, puede añadir una descripción de su repositorio.

Github-repository-description

Según su preferencia, fije la visibilidad de su repositorio de modo que sea público o privado.

Asegúrese de que este se inicialice con .gitignore; seleccione Node en la lista desplegable Add .gitignore. Este paso es importante para evitar que se añadan archivos innecesarios (por ejemplo, la carpeta node_modules) a su repositorio.

Github-gitignore-node

Haga clic en el botón Create repository.

Ahora, el repositorio debe clonarse de Github.com y enviarse a su equipo local.

Abra su terminal y diríjase a la ubicación en la que desee almacenar todos los archivos de su proyecto de Node.js. Tenga en cuenta que en este proceso se creará una subcarpeta dentro del directorio actual. Para clonar el repositorio en su máquina local, ejecute el siguiente comando:

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

Deberá sustituir your-github-username y your-github-repository-name para reflejar su nombre de usuario de Github y el nombre del repositorio previamente suministrado.

Nota: Si habilitó la autenticación de dos factores (2FA) en Github.com, debe usar un token de acceso personal o una clave SSH en lugar de su contraseña cuando acceda a Github en la línea de comandos. En la página de ayuda de Github relacionada con 2FA se proporciona más información.

Verá un resultado similar a lo siguiente:

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.

Diríjase al repositorio ejecutando el siguiente comando:

  • cd your-github-repository-name

En el repositorio se encuentra un solo archivo y una carpeta, ambos son archivos que Git utiliza para administrar el repositorio. Puede verificar esto con lo siguiente:

  • ls -la

Visualizará un resultado similar al siguiente:

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

Ahora que configuró un repositorio git funcional, creará el archivo shipit.js que administra su proceso de implementación.

Paso 2: Integrar Shipit a un proyecto de Node.js

En este paso, creará un proyecto de ejemplo de Node.js y luego agregará los paquetes de Shipit. En este tutorial se ofrece una aplicación de ejemplo: el servidor web Node.js que acepta solicitudes HTTP y responde con Hello World en texto simple. Para crear la aplicación, ejecute el siguiente comando:

  • nano hello.js

Añada el siguiente código de aplicación de ejemplo a hello.js (actualizando la variable APP_PRIVATE_IP_ADDRESS de modo que sea la dirección IP privada de su servidor 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/');

Ahora, cree el archivo package.json para su aplicación:

  • npm init -y

Con este comando se crea un archivo package.json, que usará para configurar su aplicación Node.js. En el siguiente paso, agregará dependencias a este archivo con la interfaz de línea de comandos 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" }

A continuación, instale los paquetes npm necesarios con el siguiente comando:

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

Aquí se utiliza el indicador --save-dev, ya que los paquetes de Shipit solo son necesarios en su equipo local. Visualizará un resultado similar al siguiente:

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

Con esto también se añadieron los tres paquetes a su archivo package.json como dependencias de desarrollo:

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

Ahora que configuró su entorno local, podrá proceder a preparar el servidor app remoto para las implementaciones basadas en Shipit.

Paso 3: Preparar el servidor app remoto

En este paso, usará ssh para establecer conexión con el servidor app e instalará la dependencia remota rsync. Rsync es una utilidad que permite transferir y sincronizar de manera eficiente archivos entre unidades de máquinas locales y en computadoras en red mediante la comparación de fechas de modificación y tamaños de archivos.

En Shipit se utiliza rsync para transferir y sincronizar archivos entre su equipo local y el servidor app remoto. No emitirá comandos para rsync de forma directa; Shipit lo hará por usted.

Nota: A través de Cómo configurar una aplicación de Node.js para la producción en CentOS 7, obtuvo dos servidores app y web. Estos comandos deben ejecutarse únicamente en app.

Establezca conexión con su servidor app remoto a través de ssh:

  • ssh deployer@your_app_server_ip

Instale rsync en su servidor ejecutando el siguiente comando:

  • sudo yum install rsync

Confirme la instalación con lo siguiente:

  • rsync --version

Verá una línea similar en el resultado de este comando:

Output
rsync version 3.1.2 protocol version 31 . . .

Puede cerrar su sesión ssh escribiendo exit.

Con rsync instalado y disponible en la línea de comandos, puede proceder con las tareas de implementación y su relación con los eventos.

Paso 4: Configurar y ejecutar tareas de implementación

Tanto los eventos como las tareas son componentes claves de las implementaciones de Shipit y es importante comprender la forma en que complementan la implementación de su aplicación. Los eventos desencadenados por Shipit representan puntos específicos en el ciclo de vida de la implementación. Sus tareas se ejecutarán en respuesta a estos eventos, según la secuencia del ciclo de vida de Shipit.

Un ejemplo común de la utilidad de este sistema de tareas y eventos en una aplicación de Node.js se encuentra en la instalación de las dependencias de la aplicación (node_modules) en el servidor remoto. Más adelante en este paso, hará que en Shipit se escuche el evento updated (emitido después de que los archivos de la aplicación se transfieren) y ejecutará una tarea para instalar las dependencias de la aplicación (npm install) en el servidor remoto.

Para escuchar los eventos y ejecutar tareas, Shipit necesita un archivo de configuración que contenga información sobre su servidor remoto (app) y registre las escuchas de eventos y los comandos que estas tareas ejecutarán. Este archivo reside en su máquina de desarrollo local, dentro del directorio de su aplicación de Node.js.

Para comenzar, cree este archivo; incluyea información sobre su servidor remoto, las escuchas de eventos a las que desee suscribirse y algunas definiciones de sus tareas. Cree shipitfile.js dentro del directorio root de su aplicación, en su máquina local, ejecutando el siguiente comando:

  • nano shipitfile.js

Ahora que creó un archivo, este debe completarse con la información inicial de entorno que Shipit requiere. Esta consiste principalmente en la ubicación de su repositorio Git remoto y, lo que es más importante, la dirección IP pública y la cuenta de usuario SSH de su servidor app.

Añada esta configuración inicial y actualice las líneas resaltadas para que coincidan con su entorno:

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 actualización de las variables en su método shipit.initConfig proporciona a Shipit la configuración específica para su implementación. Estas representan lo siguiente para Shipit:

  • deployTo: es el directorio en el que Shipit implementará el código de su aplicación en el servidor remoto. En este caso, se utiliza la carpeta /home/ para un usuario no root con privilegios sudo (/home/sammy) debido a que es segura y evitará problemas con los permisos. El componente /your-domain es una convención de nomenclatura para distinguir la carpeta de otras dentro de la carpeta de inicio del usuario.
  • repositoryUrl: es la URL para el repositorio completo de Git; en Shipit se utilizará esta URL para garantizar que los archivos del proyecto se encuentren en sincronización antes de la implementación.
  • keepReleases: es el número de versiones que se deben mantener en el servidor remoto. release es una carpeta fechada que contiene los archivos de su aplicación en el momento de su lanzamiento. Puede ser útil para un rollback de una implementación.
  • shared: es la configuración que se corresponde con keepReleases y permite que los directorios sean shared entre las versiones. En este caso, tenemos una sola carpeta node_modules que comparten todas las versiones.
  • production: representa un servidor remoto para la implementación de su aplicación. En este caso, tiene un único servidor (app) al que asignó el nombre production y la configuración los servers: coincide con su public ip address y user de SSH. El nombre production se corresponde con el comando de implementación de Shipit utilizado al final de este tutorial (npx shipit server name deploy o, en su caso, npx shipit production deploy).

Se puede encontrar más información sobre el objeto de configuración de implementación de Shipit en el repositorio Shipit de Github.

Antes de continuar con la actualización de su shipitfile.js, revisaremos el siguiente fragmento de código de ejemplo para entender las tareas 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"') });

Esta es una tarea de ejemplo que utiliza el método shipit.on para suscribirse al evento deploy. Esta tarea se esperará que el ciclo de vida de Shipit emita el evento deploy; luego, cuando se reciba el evento, en la tarea se ejecutará el método shipit.start que indica a Shipit que aplique start a la tarea say-hello.

En el método shipit.on se toman dos parámetros: el nombre del evento que se escuchará y la función de devolución de llamada que se ejecutará cuando se reciba el evento.

En la declaración del método shipit.on, la tarea se define con el método shipit.blTask. Esto crea una nueva tarea Shipit que bloqueará otras tareas durante su ejecución (es una tarea sincrónica). En el método shipit.blTask también se toman dos parámetros: el nombre de la tarea que define y una función de devolución de llamada que se ejecutará una vez que shipit.start active la tarea.

En la función de devolución de llamada de este ejemplo (say-hello), método shipit.local ejecuta un comando en la máquina local. En el comando local se emite “hello from your local computer” en el resultado de la terminal.

Si quisiera ejecutar un comando en el servidor remoto, usaría el método shipit.remote. Los dos métodos, shipit.local y shipit.remote, proporcionan una API para emitir comandos de forma local o remota como parte de una implementación.

Ahora, actualice shipitfile.js para incluir las escuchas de eventos a fin de suscribirse al ciclo de vida de Shipit con shipit.on. Añada las escuchas de eventos a su shipitfile.js, e insértelos conforme al marcador de posición de comentarios de la configuración inicial // Our tasks will go here:

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

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

Estos dos métodos escuchan los eventos updated y published que se emiten como parte del ciclo de vida de implementación de Shipit. Cuando se reciba el evento, cada uno iniciará tareas usando el método shipit.start, en un proceso similar al de la tarea de ejemplo.

Ahora que programó las escuchas, agregará la tarea correspondiente. Añada la siguiente tarea a su shipitfile.js; insértelas después de las escuchas de eventos:

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);
});

Primero declara una tarea llamada copy-config. En esta tarea se crea un archivo local llamado ecosystem.config.js y luego se copia ese archivo a su servidor de app remoto. En PM2, este archivo se utiliza para administrar su aplicación de Node.js. Proporciona a PM2 la información necesaria sobre rutas de archivos para garantizar que se ejecuten los últimos archivos que implementó. Más adelante, en el proceso de compilación, creará una tarea que ejecuta PM2 con ecosystem.config.js como configuración.

Si en su aplicación se necesitan variables de entorno (como una cadena de conexión de base de datos), puede declararlas de forma local, en env:, o en el servidor remoto, en env_production:, aplicando el mismo método con el que estableció la variable Node_ENV en estos objetos.

Añada la siguiente tarea a su shipitfile.js después de la tarea copy-config:

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

A continuación, declare una tarea llamada npm-install. En esta tarea se utiliza una terminal bash remota (a través de shipit.remote) para instalar las dependencias de la aplicación (paquetes npm).

Añada la última tarea a su shipitfile.js después de la tarea 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`
  );
});

Por último, declare una tarea llamada pm2-server. En esta tarea, también se utiliza una terminal bash remota para primero evitar que PM2 administre su implementación anterior a través del comando delete y luego iniciar una nueva instancia de su servidor Node.js proporcionando el archivo ecosystem.config.js como una variable. También se notifica a PM2 que debe usar variables de entorno del bloque production en su configuración inicial y se solicita, también a PM2, que controle la aplicación y la reinicie si falla.

El archivo shipitfile.js completo:

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`
    );
  });
};

Guarde y cierre el archivo cuando esté listo.

Con su shipitfile.js configurado, las escuchas de eventos y las tareas asociadas completadas, puede proceder con la implementación en el servidor app.

Paso 5: Implementar su aplicación

En este paso, implementará su aplicación de forma remota y verificará que la implementación haya permitido la disponibilidad de su aplicación en Internet.

Debido a que en Shipit se clonan los archivos de proyecto del repositorio remoto de Git, debe mover los archivos locales de su aplicación de Node.js de su máquina local a Github. Diríjase al directorio de la aplicación de su proyecto de Node.js (donde se ubican hello.js y shiptitfile.js) y ejecute el siguiente comando:

  • git status

Con el comando git status se muestra el estado del directorio de trabajo y el área de ensayos. Le permite ver los cambios que se prepararon o no, y los archivos que no se sometieron a seguimiento a través de Git. Sus archivos no se encuentran bajo seguimiento y aparecen en rojo en el resultado:

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)

Puede añadir estos archivos a su repositorio con el siguiente comando:

  • git add --all

Con este comando no se produce ningún resultado, pero si ejecutara git status de nuevo los archivos se mostrarían en verde con una nota que señalaría la necesidad de confirmar cambios.

Puede crear una confirmación ejecutando el siguiente comando:

  • git commit -m "Our first commit"

En el resultado de este comando se proporciona información específica de Git sobre los archivos.

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

Lo único que queda por hacer ahora es enviar su confirmación al repositorio remoto para que Shipit realice una clonación a su servidor app durante la implementación. Ejecute el siguiente comando:

  • git push origin master

En el resultado, se incluye información acerca de la sincronización con el repositorio remoto:

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

Para implementar su aplicación, ejecute el siguiente comando:

  • npx shipit production deploy

En el resultado de este comando (que es demasiado largo para incluirlo en su totalidad) se proporcionan detalles sobre las tareas que se ejecutan y el resultado de la función específica. En el resultado que se observa a continuación para la tarea pm2-server se muestra que la aplicación Node.js se ha iniciado:

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 ]

Para ver su aplicación como la vería un usuario, puede ingresar la URL de su sitio web your-domain en su navegador a fin de acceder a su servidor web. Esto proporcionará la aplicación de Node.js, a través de un proxy inverso, en el servidor app en el que se implementaron sus archivos.

Verá un saludo Hello World.

Nota: Después de la primera implementación, en su repositorio de Git se hará un seguimiento de un archivo nuevo llamado ecosystem.config.js. Debido a que este archivo se reconstruye en cada implementación y puede contener secretos de la aplicación compilados, se debe añadir al archivo .gitignore en el directorio root de la aplicación de su máquina local antes de su próxima confirmación de git.

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

Implementó su aplicación Node.js en el servidor app, que hace referencia a su nueva implementación. Con todo configurado y en funcionamiento, puede proceder con la supervisión de los procesos de su aplicación.

Paso 6: Controlar su aplicación

PM2 es una excelente herramienta para administrar sus procesos remotos, pero también incluye funciones para controlar el rendimiento de estos procesos de aplicación.

Establezca conexión con su servidor app remoto mediante SSH con el siguiente comando:

  • ssh deployer@your_app_server_ip

Para obtener información específica relacionada con los procesos administrados de PM2, ejecute lo siguiente:

  • pm2 list

Verá un resultado similar a lo siguiente:

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 │ └─────────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴──────┴───────────┴──────────┴──────────┘

Verá un resumen de la información recopilada por PM2. Para ver información detallada, puede ejecutar lo siguiente:

  • pm2 show hello

En el resultado, se amplía la información del resumen proporcionada por el comando pm2 list. También proporciona información sobre varios comandos suplementarios y también la ubicación de los archivos de registro:

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 │ └───────────────────────────┴───────────────────────────────────────┘ . . .

Además, PM2 proporciona una herramienta de supervisión en terminal a la que es posible acceder con lo siguiente:

  • pm2 monit

Como resultado de este comando se obtiene un panel interactivo, en el cual pm2 proporciona registros, métricas, metadatos e información sobre procesos en tiempo real. Este panel puede ser útil para controlar los recursos y registros de errores:

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 │ └───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘

Al comprender la forma en la que puede supervisar sus procesos con PM2, ahora puede considerar la forma en la que Shipit puede asistir en la reversión a una implementación funcional anterior.

Finalice su sesión ssh en su servidor app ejecutando exit.

Paso 7: Revertir una implementación defectuosa

En las implementaciones, de tanto en tanto se exhiben errores imprevistos o problemas que pueden causar fallas en su sitio. Los desarrolladores y los encargados de mantenimiento de Shipit previeron esto y proporcionaron la capacidad de restablecer la implementación (funcional) anterior de su aplicación.

Para garantizar que su configuración de PM2 persista, añada otra escucha de eventos a shipitfile.js en el evento rollback.

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

Debe añadir una escucha al evento rollback para ejecutar sus tareas npm-install y copy-config. Esto se requiere porque, a diferencia del evento published, el evento updated no se ejecuta a través del ciclo de vida de Shipit cuando se revierte una implementación. Añadir esta escucha garantiza que su administrador de procesos PM2 se oriente hacia la implementación más reciente, incluso en caso de una reversión.

Este proceso es similar a la implementación, con un pequeño cambio de comando. Para intentar restablecer a una implementación anterior, puede ejecutar lo siguiente:

  • npx shipit production rollback

Al igual que el comando deploy, rollback proporciona detalles sobre el proceso de reversión y las tareas que se ejecutan:

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 ]

Configuró Shipit para mantener 5 versiones a través del ajuste keepReleases: 5 en shipitfile.js. Shipit realiza un seguimiento interno de estas versiones para garantizar que la reversión sea posible cuando se necesite. Shipit también proporciona una alternativa práctica para identificar las versiones creando un directorio con el nombre de una marca de tiempo (AAAAMMDDHHmmss; por ejemplo, /home/deployer/your-domain/releases/20190420210548).

Si desea personalizar aún más el proceso de reversión, puede escuchar eventos específicos de la operación de reversión. Luego, puede utilizarlos para ejecutar tareas que complementarán su reversión. Puede consultar la lista de eventos proporcionada en el desglose del ciclo de vida de Shipit, y configurar las tareas y escuchas dentro de su shipitfile.js.

La capacidad de reversión implica que siempre puede proporcionar a sus usuarios una versión funcional de su aplicación, incluso si en una implementación se producen errores o problemas inesperados.

Conclusión

A lo largo de este tutorial, configuró un flujo de trabajo que le permite crear una alternativa sumamente personalizable a las plataformas como servicio, todo ello desde algunos servidores. Este flujo de trabajo permite personalizar la implementación y la configuración, controlar procesos con PM2, escalar y agregar servicios, o contar con servidores o entornos adicionales en la implementación cuando sea necesario.

Si está interesado en continuar desarrollando sus aptitudes para Node.js, consulte el contenido de Node.js de DigtalOcean y la serie Cómo producir código en Node.js.

0 Comments

Creative Commons License