One place for hosting & domains

      March 2020

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


      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:

      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:

      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 Worldn');
      }).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:

      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:

      Confirme la instalación con lo siguiente:

      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:

      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:

      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:

      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:

      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:

      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:

      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:

      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.



      Source link

      Cómo importar recursos existentes de DigitalOcean a Terraform


      El autor seleccionó la Free and Open Source Fund para recibir una donación como parte del programa Write for DOnations.

      Introducción

      Terraform es una herramienta de infraestructura como código creada por HashiCorp que permite a los desarrolladores a implementar, actualizar y eliminar diferentes recursos de su infraestructura de manera eficiente y más escalable.

      Los desarrolladores pueden usar Terraform para organizar diferentes entornos, realizar un seguimiento de los cambios a través del control de versiones y automatizar el trabajo repetitivo para reducir los errores humanos. La herramienta ofrece una alternativa para que los equipos colaboren en la mejora de su infraestructura a través de configuraciones compartidas.

      A través de este turorial, importará infraestructura existente de DigitalOcean a Terraform. Al finalizar, podrá utilizar Terraform para toda su infraestructura existente además de crear nuevos recursos.

      Requisitos previos

      Paso 1: Instalar Terraform de forma local

      En este primer paso, instalará Terraform en su máquina local. En este paso, se detalla la instalación del binario de Linux. Si utiliza Windows o Mac, puede revisar la página de Descarga de Terraform en el sitio web de Terraform.

      Diríjase a la carpeta en la que desee descargar Terraform en su máquina local y luego utilice la herramienta wget para descargar el binario 0.12.12 de Terraform:

      • cd /tmp
      • wget https://releases.hashicorp.com/terraform/0.12.12/terraform_0.12.12_linux_amd64.zip

      Para verificar si la suma de comprobación sha256 es el mismo valor que se proporciona en el sitio web de Terraform, descargará el archivo de suma de comprobación con el siguiente comando:

      • wget -q https://releases.hashicorp.com/terraform/0.12.12/terraform_0.12.12_SHA256SUMS

      Luego ejecute el siguiente comando para verificar las sumas de comprobación:

      • sha256sum -c --ignore-missing terraform_0.12.12_SHA256SUMS

      En el archivo SHA256SUMS que descargó se enumeran los nombres de archivos y sus hash. Con este comando se buscará el mismo archivo terraform_0.12.12_SHA256SUMS de forma local y luego se verificará que los hash coincidan usando el indicador -c. Debido a que en este archivo se incluye más de un nombre de archivo y su plataforma indicada, utilice el indicador --ignore-missing para evitar errores en el resultado, ya que no tiene copias de los demás archivos.

      Verá un resultado como el siguiente:

      Output

      terraform_0.12.12_linux_amd64.zip: OK

      Utilice unzip para extraer el binario:

      • sudo unzip terraform_0.12.12_linux_amd64.zip -d /usr/local/bin/

      Ahora verifique si Terraform está correctamente instalado revisando la versión:

      Visualizará un resultado similar al siguiente:

      Output

      Terraform v0.12.12

      Instaló Terraform en su máquina local. Ahora, preparará los archivos de configuración.

      Paso 2: Preparar los archivos de configuración de Terraform

      En este paso, importará sus activos existentes a Terraform creando un directorio de proyecto y escribiendo archivos de configuración. Debido a que Terraform por el momento no admite la generación de configuraciones a partir del comando import, debe crearlas de forma manual.

      Ejecute el siguiente comando para crear el directorio de su proyecto:

      • mkdir -p do_terraform_import

      Posiciónese en ese directorio con lo siguiente:

      Durante este paso, creará tres archivos adicionales que contendrán las configuraciones necesarias. Su estructura de directorios para este proyecto tendrá el siguiente aspecto:

      ├── digitalocean_droplet.tf
      ├── digitalocean_firewall.tf
      └── provider.tf
      

      Para comenzar, creará el archivo provider.tf a fin de definir su Token de acceso de DigitalOcean como una variable de entorno en lugar de codificarlo de forma rígida en su configuración.

      Advertencia: Con su token de acceso se le proporciona acceso a toda su infraestructura sin restricciones; considérelo como tal. Asegúrese de ser la única persona que tenga acceso a la máquina en la que se almacene ese token.

      Además de su token de acceso, también especificará el proveedor que desee usar. En este tutorial, es digitalocean. Si desea acceder a una lista completa de las fuentes y los recursos de datos disponibles para DigitalOcean con Terraform, consulte la página de proveedores en el sitio web.

      Cree y edite provider.tf con el siguiente comando:

      Añada el siguiente contenido al archivo provider.tf:

      provider.tf

      variable "do_token" {}
      
      provider "digitalocean" {
          token   = "${var.do_token}"
          version = "1.9.1"
          }
      

      En este archivo, se agrega el Token de acceso de DigitalOcean como una variable que Terraform usará como identificación para la API de DigitalOcean. También se especifica la versión del complemento del proveedor de DigitalOcean. Desde Terraform, se recomienda especificar la versión del proveedor que usará para que las actualizaciones futuras no puedan dañar su configuración actual.

      Ahora creará el archivo digitalocean_droplet.tf. Aquí, especificará el recurso que usará; en este caso, droplet.

      Cree el archivo con el siguiente comando:

      • nano digitalocean_droplet.tf

      Añada la siguiente configuración:

      digitalocean_droplet.tf

      resource "digitalocean_droplet" "do_droplet" {
          name   = "testing-terraform"
          region = "fra1"
          tags   = ["terraform-testing"]
          count  = "1"
      }
      

      Aquí, especifique cuatro parámetros:

      • name: nombre del Droplet.

      • region: región en la que se ubica el Droplet.

      • tags: lista de las etiquetas que se aplican a este Droplet.

      • count: número de recursos necesarios para esta configuración.

      A continuación, creará un archivo de configuración para su firewall. Cree el archivo digitalocean_firewall.tf con el siguiente comando:

      • nano digitalocean_firewall.tf

      Añada el siguiente contenido al archivo:

      digitalocean_firewall.tf

      resource "digitalocean_firewall" "do_firewall" {
        name  = "testing-terraform-firewall"
        tags  = ["terraform-testing"]
        count = "1"
      }
      

      Aquí especifica el nombre del firewall que desea importar y las etiquetas de los Droplets a las que se aplican las reglas del firewall. Por último, en el valor count de 1 se define el número requerido del recurso específico.

      Nota: También puede incluir recursos del firewall en el archivo digitalocean_droplet.tf. Sin embargo, si dispone de varios entornos en los cuales varios Droplets comparten el mismo firewall, se recomienda separarlo en caso de querer eliminar un solo Droplet. Esto dejará el firewall intacto.

      Ahora, es momento de inicializar esos cambios para que en Terraform se puedan descargar las dependencias necesarias. Para esto utilizará el comando terraform init, el cual le permitirá inicializar un directorio de trabajo que contenga archivos de configuración de Terraform.

      Ejecute el siguiente comando desde el directorio de su proyecto:

      Verá el siguiente resultado:

      Output

      Terraform has been successfully initialized!

      Terraform preparó de forma correcta el directorio de trabajo descargando complementos y buscando módulos, entre otras acciones. A continuación, comenzará a importar sus recursos a Terraform.

      Paso 3: Importar sus activos a Terraform

      Durante este paso, importará sus activos de DigitalOcean a Terraform. Usará doctl para encontrar los números de ID de sus Droplets antes de importar sus recursos. Luego, verificará la configuración de importación con los comandos terraform show y terraform plan.

      Para comenzar, exportará su Token de acceso de DigitalOcean como una variable de entorno que luego insertará en Terraform durante el tiempo de ejecución.

      Expórtelo como una variable de entorno a su sesión de shell actual con el siguiente comando:

      • export DO_TOKEN="YOUR_TOKEN"

      Para poder importar su Droplet y firewall existentes, necesitará los números de ID de estos. Puede usar doctl, la interfaz de línea de comandos de la API de DigitalOcean. Ejecute el siguiente comando para listar sus Droplets y acceder a sus IDs:

      • doctl compute droplet list

      Visualizará un resultado similar al siguiente:

      Output

      ID Name Public IPv4 Private IPv4 Public IPv6 Memory VCPUs Disk Region Image Status Tags Features Volumes DROPLET-ID DROPLET-NAME DROPLET-IPv4 1024 1 25 fra1 Ubuntu 18.04.3 (LTS) x64 active DROPLET-ID DROPLET-NAME DROPLET-IPv4 2048 1 50 fra1 Ubuntu 18.04.3 (LTS) x64 active DROPLET-ID DROPLET-NAME DROPLET-IPv4 1024 1 25 fra1 Ubuntu 18.04.3 (LTS) x64

      Ahora, importará su Droplet y firewall existentes a Terraform:

      • terraform import -var "do_token=${DO_TOKEN}" digitalocean_droplet.do_droplet DROPLET_ID

      Se utiliza el indicador -var para especificar el valor de su Token de acceso de DigitalOcean, previamente exportado a su sesión de shell. Esto es necesario para que en la API de DigitalOcean se verifique su identidad y se apliquen cambios en su infraestructura.

      Ahora, ejecute el mismo comando para su firewall:

      • terraform import -var "do_token=${DO_TOKEN}" digitalocean_firewall.do_firewall FIREWALL_ID

      Compruebe que la importación se haya realizado correctamente usando el comando terraform show. Este comando proporciona un resultado legible para humanos del estado de su infraestructura. Puede utilizarse para inspeccionar un plan a fin de garantizar que los cambios requeridos se ejecuten o inspeccionar el estado actual tal como se ve en Terraform.

      En este contexto, el estado hace referencia a la asignación de sus recursos de DigitalOcean en la configuración de Terraform que escribió y al seguimiento de los metadatos. Esto le permite confirmar que no existe diferencia entre los recursos existentes de DigitalOcean que desea importar y los recursos que Terraform somete a seguimiento:

      Verá un resultado similar a este:

      Output

      . . . # digitalocean_droplet.do_droplet: resource "digitalocean_droplet" "do_droplet" { backups = false created_at = "2020-02-03T16:12:02Z" disk = 25 id = "DROPLET-ID" image = "DROPLET-IMAGE" ipv4_address = "DROPLET-IP" ipv6 = false locked = false memory = 1024 monitoring = false name = "testing-terraform-0" price_hourly = 0.00744 price_monthly = 5 private_networking = false region = "fra1" resize_disk = true size = "s-1vcpu-1gb" status = "active" tags = [ "terraform-testing", ] urn = "DROPLET-URN" vcpus = 1 volume_ids = [] . . . }

      Verá dos recursos en el resultado junto con sus atributos.

      Después de importar su Droplet y firewall al estado de Terraform, debe asegurarse que las configuraciones representen el estado actual de los recursos importados. Para hacer esto, especificará la image de su Droplet y su size. Puede encontrar estos dos valores en el resultado de terraform show relacionado con el recurso digitalocean_droplet.do_droplet.

      Abra el archivo digitalocean_droplet.tf:

      • nano digitalocean_droplet.tf

      En este tutorial:

      • La imagen del sistema operativo empleada para nuestro Droplet existente es ubuntu-16-04-x64.
      • La región en la que se ubica su Droplet es fra1.
      • La etiqueta para su Droplet existente es terraform-testing.

      El Droplet que importó usando la configuración en digitalocean_droplet.tf tendrá el siguiente aspecto:

      digitalocean_droplet.tf

      resource "digitalocean_droplet" "do_droplet" {
          image   = "ubuntu-16-04-x64"
          name    = "testing-terraform"
          region  = "fra1"
          size    = "s-1vcpu-1gb"
          tags    = ["terraform-testing"]
      }
      

      A continuación, añadirá las reglas del firewall. En nuestro ejemplo, los puertos abiertos para el tráfico entrante son 22, 80 y 443. Todos los puertos están abiertos para el tráfico saliente. Puede ajustar esta configuración de manera correspondiente para sus puertos abiertos.

      Abra digitalocean_firewall.tf:

      • nano digitalocean_firewall.tf

      Añada la siguiente configuración:

      digitalocean_firewall.tf

      resource "digitalocean_firewall" "do_firewall" {
        name  = "testing-terraform-firewall"
        tags  = ["terraform-testing"]
        count = "1"
      
        inbound_rule {
            protocol                = "tcp"
            port_range              = "22"
            source_addresses        = ["0.0.0.0/0", "::/0"]
          }
        inbound_rule {
            protocol                = "tcp"
            port_range              = "80"
            source_addresses        = ["0.0.0.0/0", "::/0"]
          }
        inbound_rule {
            protocol                = "tcp"
            port_range              = "443"
            source_addresses        = ["0.0.0.0/0", "::/0"]
          }
      
        outbound_rule {
            protocol                = "tcp"
            port_range              = "all"
            destination_addresses   = ["0.0.0.0/0", "::/0"]
          }
        outbound_rule {
            protocol                = "udp"
            port_range              = "all"
            destination_addresses   = ["0.0.0.0/0", "::/0"]
          }
        outbound_rule {
            protocol                = "icmp"
            destination_addresses   = ["0.0.0.0/0", "::/0"]
          }
      }
      

      En estas reglas se replica el estado del firewall de ejemplo existente. Si desea limitar el tráfico a diferentes direcciones IP, puertos o protocolos, puede ajustar el archivo para replicar su firewall existente.

      Una vez que haya actualizado sus archivos de Terraform, usará el comando plan para ver si en los cambios realizados se replica el estado de los activos existentes en DigitalOcean.

      El comando terraform plan se utiliza a modo de simulacro. Con este comando, puede verificar si los cambios que se realizarán en Terraform son los cambios que quiere hacer. Es recomendable ejecutar siempre este comando para confirmarlo antes de aplicar los cambios.

      Ejecute terraform plan con lo siguiente:

      • terraform plan -var "do_token=$DO_TOKEN"

      Verá un resultado similar al siguiente:

      Output

      No changes. Infrastructure is up-to-date.

      Importó de forma correcta los recursos de DigitalOcean existentes a Terraform y ahora podrá realizar cambios en su infraestructura mediante Terraform sin el riesgo de eliminar o modificar los recursos existentes.

      En este paso, agregará dos Droplets adicionales a su infraestructura existente. Añadir recursos de esta manera a su infraestructura existente puede ser útil, por ejemplo, si tiene un sitio web activo y no quiere realizar cambios que puedan ocasionar perjuicios en dicho sitio mientras realiza tareas en él. En su lugar, puede añadir un Droplet adicional para usarlo como entorno de desarrollo y trabajar en su proyecto en el mismo entorno que el Droplet de producción sin riesgos.

      Ahora, abra digitalocean_droplet.tf para añadir las reglas de sus nuevos Droplets:

      • nano digitalocean_droplet.tf

      Añada las siguientes líneas a su archivo:

      digitalocean_droplet.tf

      resource "digitalocean_droplet" "do_droplet" {
          image   = "ubuntu-16-04-x64"
          name    = "testing-terraform"
          region  = "fra1"
          size    = "s-1vcpu-1gb"
          tags    = ["terraform-testing"]
          count   = "1"
      }
      
      resource "digitalocean_droplet" "do_droplet_new" {
          image   = "ubuntu-18-04-x64"
          name    = "testing-terraform-${count.index}"
          region  = "fra1"
          size    = "s-1vcpu-1gb"
          tags    = ["terraform-testing"]
          count   = "2"
      }
      

      Utilizará el metargumento count para indicar a Terraform la cantidad de Droplets con las mismas especificaciones que desea. Estos nuevos Droplets también se agregarán a su firewall existente a medida que especifique la misma etiqueta que en su firewall.

      Aplique estas reglas para verificar los cambios que especifique en DigitalOcean_droplet.tf:

      • terraform plan -var "do_token=$DO_TOKEN"

      Verifique que los cambios que desea realizar se repliquen en el resultado de este comando.

      Visualizará un resultado similar al siguiente:

      Output

      . . . # digitalocean_droplet.do_droplet_new[1] will be created + resource "digitalocean_droplet" "do_droplet_new" { + backups = false + created_at = (known after apply) + disk = (known after apply) + id = (known after apply) + image = "ubuntu-18-04-x64" + ipv4_address = (known after apply) + ipv4_address_private = (known after apply) + ipv6 = false + ipv6_address = (known after apply) + ipv6_address_private = (known after apply) + locked = (known after apply) + memory = (known after apply) + monitoring = false + name = "testing-terraform-1" + price_hourly = (known after apply) + price_monthly = (known after apply) + private_networking = true + region = "fra1" + resize_disk = true + size = "s-1vcpu-1gb" + status = (known after apply) + tags = [ + "terraform-testing", ] + urn = (known after apply) + vcpus = (known after apply) + volume_ids = (known after apply) } Plan: 2 to add, 1 to change, 0 to destroy.

      Una vez que esté satisfecho con el resultado, utilice el comando terraform apply para aplicar los cambios que especificó al estado de la configuración:

      • terraform apply -var "do_token=$DO_TOKEN"

      Confirme los cambios ingresando yes en la línea de comandos. Cuando la ejecución sea exitosa, verá un resultado similar al siguiente:

      Output

      . . . digitalocean_droplet.do_droplet_new[1]: Creating... digitalocean_droplet.do_droplet_new[0]: Creating... digitalocean_firewall.do_firewall[0]: Modifying... [id=FIREWALL-ID] digitalocean_firewall.do_firewall[0]: Modifications complete after 1s [id=FIREWALL-ID] digitalocean_droplet.do_droplet_new[0]: Still creating... [10s elapsed] digitalocean_droplet.do_droplet_new[1]: Still creating... [10s elapsed] digitalocean_droplet.do_droplet_new[0]: Creation complete after 16s [id=DROPLET-ID] digitalocean_droplet.do_droplet_new[1]: Still creating... [20s elapsed] digitalocean_droplet.do_droplet_new[1]: Creation complete after 22s [id=DROPLET-ID] Apply complete! Resources: 2 added, 1 changed, 0 destroyed.

      Visualizará dos nuevos Droplets en su panel web de DigitalOcean: Nuevos Droplets

      También los verá adjuntos a su firewall existente: Firewall existente

      Creó nuevos recursos con Terraform usando sus activos existentes. Para aprender a destruir estos recursos, opcionalmente puede completar el paso siguiente.

      Paso 5: Destruir activos importados y creados (opcional)

      En este paso, destruirá los activos que importó y creó ajustando la configuración.

      Comience abriendo digitalocean_droplet.tf:

      • nano digitalocean_droplet.tf

      En el archivo, fije count en 0 como se muestra a continuación:

      digitalocean_droplet.tf

      resource "digitalocean_droplet" "do_droplet" {
          image   = "ubuntu-16-04-x64"
          name    = "testing-terraform"
          region  = "fra1"
          size    = "s-1vcpu-1gb"
          tags    = ["terraform-testing"]
          count   = "0"
      }
      
      resource "digitalocean_droplet" "do_droplet_new" {
          image   = "ubuntu-18-04-x64"
          name    = "testing-terraform-${count.index}"
          region  = "fra1"
          size    = "s-1vcpu-1gb"
          tags    = ["terraform-testing"]
          count   = "0"
      }
      

      Guarde el archivo y ciérrelo.

      Abra su archivo de configuración de firewall para modificar count también:

      • nano digitalocean_firewall.tf

      Fije count en 0 como en la siguiente línea resaltada:

      digitalocean_firewall.tf

      resource "digitalocean_firewall" "do_firewall" {
        name  = "testing-terraform-firewall"
        tags  = ["terraform-testing"]
        count = "0"
      
        inbound_rule {
            protocol                = "tcp"
            port_range              = "22"
            source_addresses        = ["0.0.0.0/0", "::/0"]
          }
        inbound_rule {
            protocol                = "tcp"
            port_range              = "80"
            source_addresses        = ["0.0.0.0/0", "::/0"]
          }
        inbound_rule {
            protocol                = "tcp"
            port_range              = "443"
            source_addresses        = ["0.0.0.0/0", "::/0"]
          }
      
        outbound_rule {
            protocol                = "tcp"
            port_range              = "all"
            destination_addresses   = ["0.0.0.0/0", "::/0"]
          }
        outbound_rule {
            protocol                = "udp"
            port_range              = "all"
            destination_addresses   = ["0.0.0.0/0", "::/0"]
          }
        outbound_rule {
            protocol                = "icmp"
            destination_addresses   = ["0.0.0.0/0", "::/0"]
          }
      }
      

      Guarde el archivo y ciérrelo.

      Ahora, aplique esos cambios con el siguiente comando:

      • terraform apply -var "do_token=${DO_TOKEN}"

      Terraform le solicitará confirmar si desea destruir los Droplets y el firewall. Con esto se eliminarán todos los activos que importó y creó mediante Terraform. Por lo tanto, asegúrese de verificar que desee proceder antes de escribir yes.

      Verá un resultado similar a lo siguiente:

      Output

      . . . digitalocean_droplet.do_droplet[0]: Destroying... [id=YOUR-DROPLET-ID]] digitalocean_droplet.do_droplet_new[0]: Destroying... [id=YOUR-DROPLET-ID] digitalocean_droplet.do_droplet_new[1]: Destroying... [id=YOUR-DROPLET-ID] digitalocean_firewall.do_firewall[0]: Destroying... [id=YOUR-FIREWALL-ID] digitalocean_firewall.do_firewall[0]: Destruction complete after 1s digitalocean_droplet.do_droplet_new[1]: Still destroying... [id=YOUR-DROPLET-ID, 10s elapsed] digitalocean_droplet.do_droplet[0]: Still destroying... [id=YOUR-DROPLET-ID, 10s elapsed] digitalocean_droplet.do_droplet_new[0]: Still destroying... [id=YOUR-DROPLET-ID, 10s elapsed] digitalocean_droplet.do_droplet_new[1]: Still destroying... [id=YOUR-DROPLET-ID, 20s elapsed] digitalocean_droplet.do_droplet_new[0]: Still destroying... [id=YOUR-DROPLET-ID, 20s elapsed] digitalocean_droplet.do_droplet[0]: Still destroying... [id=YOUR-DROPLET-ID, 20s elapsed] digitalocean_droplet.do_droplet_new[1]: Destruction complete after 22s digitalocean_droplet.do_droplet[0]: Destruction complete after 22s digitalocean_droplet.do_droplet_new[0]: Destruction complete after 22s Apply complete! Resources: 0 added, 0 changed, 4 destroyed.

      Eliminó todos los activos administrados por Terraform. Este es un flujo de trabajo útil si ya no necesita un recurso o realiza una reducción.

      Conclusión

      A lo largo de este tutorial, instaló Terraform, importó los recursos existentes, creó recursos nuevos y, opcionalmente, los destruyó. Puede escalar este flujo de trabajo para un proyecto más grande, como la implementación de un clúster de Kubernetes listo para la producción. A través de Terraform, puede administrar los nodos, las entradas de DNS, los firewalls, el almacenamiento y otros recurss, además de usar el control de versiones para supervisar cambios y colaborar con un equipo.

      Para explorar más características de Terraform, lea la documentación pertinente. También puede leer contenido de Terraform de DigitalOcean para acceder a más tutoriales y preguntas y respuestas.



      Source link

      Cómo instalar la pila Linux, Nginx, MySQL, PHP (LEMP) en CentOS 8 [Guía de inicio rápido]


      Introducción

      A través de este tutorial, instalará una pila LEMP en un servidor de CentOS 8. Aunque MySQL está disponible en los repositorios predeterminados en CentOS 8, en esta guía se mostrará el proceso de configuración de una pila LEMP con MariaDB como sistema de administración de bases de datos.

      Para ver una versión más detallada de este tutorial, con más explicaciones de cada paso, consulte Cómo instalar la pila Linux, Nginx, MySQL, PHP (LEMP) en CentOS 8.

      Requisitos previos

      Para completar esta guía, necesitará acceso a un servidor de CentOS 8 como usuario sudo.

      Paso 1: Instalar Nginx

      Instale el paquete nginx con:

      Cuando finalice la instalación, ejecute el siguiente comando para habilitar e iniciar el servidor:

      • sudo systemctl start nginx

      Si firewalld está activo, deberá ejecutar el siguiente comando para permitir el acceso externo en el puerto 80 (HTTP):

      • sudo firewall-cmd --permanent --add-service=http

      Vuelva a cargar la configuración del firewall para que los cambios surtan efecto:

      • sudo firewall-cmd --reload

      Una vez añadida la nueva regla de firewall, puede verificar si su servidor está activo accediendo a la dirección IP pública o al nombre del dominio de este desde su navegador web. Verá una página como la siguiente:

      Página predeterminada de Nginx, CentOS 8

      Paso 2: Instalar MariaDB

      Ahora instalaremos MariaDB, una ramificación del servidor MySQL original de Oracle desarrollada por la comunidad. Para instalar este software, ejecute lo siguiente:

      • sudo dnf install mariadb-server

      Cuando termine la instalación, habilite e inicie el servidor MariaDB con lo siguiente:

      • sudo systemctl start mariadb

      Par mejorar la seguridad del servidor de su base de datos, se recomienda que ejecute una secuencia de comandos de seguridad que se incluye con MariaDB. Inicie la secuencia de comandos interactiva con lo siguiente:

      • sudo mysql_secure_installation

      En la primera solicitud se pedirá que introduzca la contraseña root de la base de datos actual. Debido a que acaba de instalar MariaDB y aún no realizó aún cambios en la configuración, el espacio de esta contraseña estará en blanco. Por ello, pulse ENTER en la solicitud.

      En la siguiente solicitud se pregunta si desea configurar una contraseña root de la base de datos. Debido a que MariaDB usa un método de autenticación especial para el usuario root que normalmente proporciona más seguridad que una contraseña, no es necesario que la configure ahora. Escriba N y pulse ENTER.

      Desde allí, puede pulsar Y y luego ENTER para aceptar los valores predeterminados para todas las preguntas siguientes.

      Cuando termine, inicie sesión en la consola de MariaDB escribiendo lo siguiente:

      Esto permitirá establecer conexión con el servidor de MariaDB como usuario root de la base de datos administrativa, lo que se infiere del uso de sudo cuando se ejecuta este comando. Debería ver el siguiente resultado:

      Output

      Welcome to the MariaDB monitor. Commands end with ; or g. Your MariaDB connection id is 9 Server version: 10.3.17-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or 'h' for help. Type 'c' to clear the current input statement. MariaDB [(none)]>

      Para crear una nueva base de datos, ejecute el siguiente comando desde su consola de MariaDB:

      • CREATE DATABASE example_database;

      Ahora puede crear un nuevo usuario y concederle privilegios completos sobre la base de datos personalizada que acaba de crear:

      • GRANT ALL ON example_database.* TO 'example_user'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION;

      Vacíe los privilegios para garantizar que se guarden y estén disponibles en la sesión actual:

      Después de esto, cierre el shell de MariaDB:

      Paso 3: Instalar PHP-FPM

      Para instalar los paquetes php-fpm y php-mysql, ejecute lo siguiente:

      • sudo dnf install php-fpm php-mysqlnd

      Cuando finalice la instalación, deberá editar el archivo /etc/php-fpm.d/www.conf para regular algunos ajustes. Instalaremos nano para facilitar la edición de estos archivos:

      Ahora, abra el archivo de configuración /etc/php-fpm.d/www.conf usando nano o el editor que prefiera:

      • sudo nano /etc/php-fpm.d/www.conf

      Busque las directivas user y group. Si usa nano, puede pulsar CTRL+W para buscar estos términos dentro del archivo abierto. Asegúrese de cambiar ambos valores de apache a nginx:

      /etc/php-fpm.d/www.conf

      …
      ; RPM: apache user chosen to provide access to the same directories as httpd
      user = nginx
      ; RPM: Keep a group allowed to write in log dir.
      group = nginx

      Guarde y cierre el archivo cuando finalice la edición.

      Para habilitar e iniciar el servicio php-fpm, ejecute lo siguiente:

      • sudo systemctl start php-fpm

      Finalmente, reinicie el servidor web Nginx de modo que cargue los archivos de configuración creados por la instalación de php-fmp:

      • sudo systemctl restart nginx

      Paso 4: Probar PHP con Nginx

      En CentOS 8, la instalación predeterminada de php-fpm crea automáticamente archivos de configuración que ahora permitirán que su servidor web Nginx gestione los archivos .php en la raíz de documento predeterminada ubicada en /usr/share/nginx/html. No necesitará realizar cambios en la configuración de Nginx para que PHP funcione correctamente en su servidor web.

      Solo tendremos que modificar el propietario y grupo predeterminados en la raíz del documento de Nginx, para que pueda crear y modificar archivos en esa ubicación empleando su usuario de sistema no root regular.

      • sudo chown -R sammy.sammy /usr/share/nginx/html/

      Cree un nuevo archivo PHP llamado info.php en el directorio /usr/share/nginx/html:

      • nano /usr/share/nginx/html/info.php

      El siguiente código PHP mostrará información sobre el entorno PHP actual que se ejecuta en el servidor:

      /usr/share/nginx/html/info.php

      <?php
      
      phpinfo();
      

      Copie este contenido a su archivo info.php y no olvide guardarlo cuando termine.

      Ahora, podemos probar si nuestro servidor web puede mostrar correctamente el contenido generado por una secuencia de comandos PHP. Vaya a su navegador y acceda al nombre de host o la dirección IP de su servidor; agregue /info.php al final:

      http://server_host_or_IP/info.php
      

      Verá una página similar a la siguiente:

      Información PHP predeterminada de CentOS 8

      Tutoriales relacionados

      A continuación, se ofrecen los enlaces a más guías detalladas relacionadas con este tutorial:



      Source link