Tutorial

Como automatizar suas implantações Node.js para produção com o Shipit no CentOS 7

CentOSNode.jsGitJavaScript

O autor selecionou a Fundação Electronic Frontier para receber uma doação como parte do programa Write for DOnations.

Introdução

O Shipit é uma ferramenta de automação e implantação universal para desenvolvedores do Node.js. Ela possui um fluxo de tarefas baseado no pacote popular Orchestrator, comandos de login e SSH interativo através do OpenSSH, além de uma API extensível. Os desenvolvimentos podem usar o Shipit para automatizar os fluxos de trabalho de compilação e DE implantação para uma ampla gama de aplicativos Node.js.

O fluxo de trabalho do Shipit permite que os desenvolvedores não apenas configurem tarefas, mas também especifiquem a ordem na qual são executadas; se devem ser executadas de maneira sincronizada ou não e em qual ambiente.

Neste tutorial, você instalará e configurará o Shipit para implantar um aplicativo Node.js a partir do seu ambiente de desenvolvimento local para o seu ambiente de produção. Você usará o Shipit para implantar seu aplicativo e configurar o servidor remoto desta forma:

  • transferindo os arquivos do aplicativo Node.js do seu ambiente local para o ambiente de produção (usando o rsync, git e ssh).
  • instalando as dependências do seu aplicativo (módulos de nó)
  • configurando e gerenciando os processos Node.js em execução no servidor remoto com o PM2.

Pré-requisitos

Antes de iniciar este tutorial, você precisará do seguinte:

Nota: os usuários do Windows terão que instalar o Subsistema Windows para o Linux para executar os comandos neste guia.

Passo 1 — Configurando o repositório remoto

O Shipit exige um repositório Git para a sincronização entre a máquina de desenvolvimento local e o servidor remoto. Neste passo, você criará um repositório remoto no Github.com. Embora cada provedor seja ligeiramente diferente, os comandos são de certo modo transferíveis.

Para criar um repositório, abra o Github.com em seu navegador Web e faça login. Você notará que, no canto superior de todas as páginas, existe um símbolo de adição +. Clique no + e, em seguida, clique em Novo repositório.

Github-novo-repositório

Digite um nome curto e fácil de lembrar para o seu repositório como ,por exemplo, hello-world. Note que, independentemente do nome que escolher aqui, ele será replicado como a pasta do projeto a partir da qual você irá trabalhar em sua máquina local.

Github-nome-repositório

De maneira opcional, adicione uma descrição do seu repositório.

Github-descrição-repositório

Defina a visibilidade do seu repositório de acordo com sua preferência, como sendo pública ou privada.

Certifique-se de que o repositório seja inicializado com um .gitignore, selecionando Node na lista suspensa Add .gitignore. Este passo é importante para evitar que arquivos desnecessários (como a pasta node_modules) sejam adicionados ao seu repositório.

Github-nó-gitignore

Clique no botão Criar repositório.

Agora, o repositório precisa ser clonado do Github.com para sua máquina local.

Abra seu terminal e navegue até o local onde quer armazenar todos os seus arquivos do projeto Node.js. Note que este processo criará uma subpasta dentro do diretório atual. Para clonar o repositório para sua máquina local, execute o seguinte comando:

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

Você precisará substituir o your-github-username e your-github-repository-name para que reflitam seu nome de usuário do Github e o nome do repositório anteriormente fornecido.

Nota: caso tenha habilitado a autenticação de dois fatores (2FA) no Github.com, ao acessar o Github na linha de comando, você deverá usar um token de acesso pessoal ou uma chave SSH, em vez de sua senha. A página de ajuda do Github relacionada à 2FA fornece mais informações.

Você verá um resultado parecido com este:

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.

Vá até o repositório, executando o seguinte comando:

  • cd your-github-repository-name

Dentro do repositório, há um arquivo e uma pasta únicos, sendo ambos arquivos usados pelo Git para gerenciar o repositório. Você pode verificar isso com:

  • ls -la

Você verá um resultado parecido com este:

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

Agora que você configurou um repositório git funcional, irá criar o arquivo shipit.js que gerencia o seu processo de implantação.

Passo 2 — Integrando o Shipit a um projeto Node.js

Neste passo, você criará um projeto Node.js como exemplo e, depois, adicionará os pacotes do Shipit. Este tutorial fornece um app exemplo — o servidor web Node.js que aceita solicitações HTTP e responde com um Hello World em texto simples. Para criar o aplicativo, execute o seguinte comando:

  • nano hello.js

Adicione o seguinte código de aplicativo exemplo ao hello.js (atualizando a variável APP_PRIVATE_IP_ADDRESS com o endereço IP da rede privada do servidor do seu 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/');

Agora, crie seu arquivo package.json para seu aplicativo:

  • npm init -y

Esse comando cria um arquivo package.json, que você usará para configurar seu aplicativo Node.js. No próximo passo, você adicionará dependências a esse arquivo com a interface de linha de comando 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" }

Em seguida, instale os pacotes npm necessários com o seguinte comando:

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

Aqui, você usará o sinalizador --save-dev, uma vez que os pacotes do Shipit somente são necessários em sua máquina local. Você verá um resultado parecido com este:

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

Isso também adicionou os três pacotes ao seu arquivo package.json como dependências de desenvolvimento:

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

Com seu ambiente local configurado, agora você pode prosseguir com a preparação do servidor app remoto para implantações baseadas no Shipit.

Passo 3 — Preparando o servidor app remoto

Neste passo, você usará o ssh para se conectar ao seu servidor app e instalar sua dependência remota rsync. O Rsync é um utilitário para transferir e sincronizar arquivos de modo eficiente entre os discos do computador local e os computadores em rede, comparando os tempos de modificação e os tamanhos dos arquivos.

O Shipit usa o rsync para transferir e sincronizar arquivos entre seu computador local e o servidor app remoto. Você não emitirá qualquer comando diretamente no rsync; o Shipit fará isso por você.

Nota: o tutorial Como configurar um aplicativo Node.js para produção no CentOS 7 possibilitou que você ficasse com dois servidores, app e web. Esses comandos devem ser executados apenas no app.

Conecte-se ao seu servidor app remoto via ssh:

  • ssh deployer@your_app_server_ip

Instale o rsync no seu servidor, executando o seguinte comando:

  • sudo yum install rsync

Confirme a instalação com:

  • rsync --version

Você verá uma linha semelhante no resultado deste comando:

Output
rsync version 3.1.2 protocol version 31 . . .

Você pode encerrar sua sessão ssh, digitando exit.

Com o rsync instalado e disponível na linha de comando, você pode prosseguir com as tarefas de implantação e sua relação com eventos.

Passo 4 — Configurando e executando tarefas de implantação

Tanto events quanto tasks são componentes chave das implantações Shipit. É importante entender como eles complementam a implantação do seu aplicativo. Os eventos desencadeados pelo Shipit representam pontos específicos no ciclo de vida da implantação. Suas tarefas executarão em reposta a esses eventos, com base na sequência do clico de vida do Shipit.

Um exemplo comum de onde esse sistema de tarefa/evento é útil em um aplicativo Node.js é na instalação das dependências do app (node_modules), no servidor remoto. Mais adiante neste passo, você fará o Shipit escutar para o evento updated (que é emitido depois que os arquivos do aplicativo são transferidos) e executar uma tarefa para instalar as dependências do aplicativo (npm install) no servidor remoto.

Para escutar eventos e executar tarefas, o Shipit precisa de um arquivo de configuração que possua informações sobre seu servidor remoto (o servidor app) e registre ouvintes de eventos e os comandos a serem executados por essas tarefas. Esse arquivo fica no seu computador de desenvolvimento local, no diretório do seu aplicativo Node.js.

Para começar, crie esse arquivo, incluindo informações sobre seu servidor remoto, os ouvintes de eventos nos quais quer se inscrever e algumas definições das suas tarefas. Crie o shipitfile.js no diretório raiz do seu aplicativo, em sua máquina local, executando o seguinte comando:

  • nano shipitfile.js

Agora que você criou um arquivo, ele precisa ser preenchido com as informações iniciais do ambiente que o Shipit precisa. Basicamente, esse é o local do seu repositório Git remoto e, mais importante que tudo, do endereço IP público e da conta de usuário SSH do seu servidor app.

Adicione essa configuração inicial e atualize as linhas destacadas para que correspondam ao seu ambiente:

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

};

Atualizando as variables no seu método shipit.initConfig dá ao Shipit uma configuração específica para sua implantação. Essas variáveis representam o seguinte para o Shipit:

  • deployTo: é o diretório onde o Shipit implantará o código do seu aplicativo no servidor remoto. Aqui, você usa a pasta /home/ para um usuário não raiz com privilégios sudo (/home/sammy) uma vez que é segura e evitará problemas de permissão. O componente /your-domain é uma convenção de nomenclatura para distinguir a pasta das demais na pasta inicial do usuário.
  • repositoryUrl: é a URL do repositório completo do Git. O Shipit usará essa URL para garantir que os arquivos do projeto estejam em sincronia antes da implantação.
  • keepReleases: é o número de lançamentos a ser mantido no servidor remoto. Um release (lançamento) é uma pasta com data que contém os arquivos do seu aplicativo no momento do lançamento. Eles podem ser úteis para rollback (reverter) uma implantação.
  • shared: é a configuração que corresponde aos keepReleases que permite que os diretórios sejam shared (compartilhados) entre os lançamentos. Nessa instância, temos uma única pasta node_modules, que é compartilhada entre todos os lançamentos.
  • production: representa um servidor remoto para o qual implantar seu aplicativo. Nessa instância, você tem um servidor (servidor app) único, ao qual você dá o nome de production, com o servers: configuração que correspondendo ao seu user SSH e ao public ip address do SSH. O nome production corresponde ao comando de implantação do Shipit usado ao final deste tutorial (npx shipit server name deploy ou, no seu caso, npx shipit production deploy).

No repositório Github para o Shipit, você pode encontrar mais informações sobre a o objeto de Configuração da implantação do Shipit.

Antes de continuar a atualizar seu shipitfile.js, vamos analisar o seguinte exemplo de trecho de código para entender as tarefas do Shipit:

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

Esse é um exemplo de tarefa que utiliza o método shipit.on para se inscrever no evento deploy (implantar). Essa tarefa esperará que o evento deploy seja emitido pelo ciclo de vida do Shipit. Depois, quando o evento é recebido, a tarefa executa o método shipit.start, que diz ao Shipit para start (iniciar) a tarefa say-hello.

O método shipit.on aceita dois parâmetros, o nome do evento para escutar e a função de callback a ser executada quando o evento for recebido.

Sob a declaração do método shipit.on, a tarefa é definida com o método shipit.blTask. Isso cria uma tarefa do Shipit que irá bloquear outras tarefas durante sua execução (é uma tarefa síncrona). O método shipit.blTask também aceita dois parâmetros, o nome da tarefa que está definindo e uma função de callback para ser executada quando a tarefa for ativada pelo shipit.start.

Dentro da função de callback dessa tarefa exemplo (say-hello), o método shipit.local executa um comando na máquina local. O comando local ecoa "hello from your local computer" no resultado do terminal.

Se quisesse executar um comando no servidor remoto, usaria o método shipit.remote. Os dois métodos, shipit.local e shipit.remote, fornecem uma API para emitir comandos tanto localmente quanto remotamente como parte de uma implantação.

Agora, atualize o shipitfile.js para incluir ouvintes de eventos para se inscrever no ciclo de vida do Shipit com shipit.on. Adicione os ouvintes de eventos ao seu shipitfile.js, inserindo-os após o espaço reservado para comentário da configuração inicial // Our tasks will go here:

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

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

Esses dois métodos estão escutando os eventos updated e published que são emitidos como parte do ciclo de vida da implantação do Shipit. Quando os eventos forem recebidos, cada qual irá iniciar tarefas usando o método shipit.start, assim como na tarefa exemplo.

Agora que você agendou os ouvintes, adicionará a tarefa correspondente. Adicione a seguinte tarefa ao seu shipitfile.js, inserindo-a após seus ouvintes 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);
});

Primeiro, você declara uma tarefa chamada copy-config. Essa tarefa cria um arquivo local chamado ecosystem.config.js e, depois, copia esse arquivo para o seu servidor remoto app. O PM2 usa esse arquivo para gerenciar seu aplicativo Node.js. Ela fornece as informações necessárias do caminho do arquivo para o PM2 para garantir que ele esteja executando seus arquivos mais recentemente implantados. Mais adiante no processo de compilação, você criará uma tarefa que executa o PM2 com o ecosystem.config.js como configuração.

Caso seu aplicativo precise de variáveis de ambiente (como uma string de conexão com banco de dados), você pode declará-las tanto localmente em env: quanto no servidor remoto em env_production: da mesma maneira que você definiu a variável NODE_ENV nesses objetos.

Adicione a próxima tarefa ao seu shipitfile.js após a tarefa copy-config:

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

Em seguida, declare uma tarefa chamada npm-install. Essa tarefa usa um terminal bash remoto (via shipit.remote) para instalar as dependências do app (pacotes npm).

Adicione a última tarefa ao seu shipitfile.js depois da tarefa 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 fim, declare uma tarefa chamada pm2-server. Essa tarefa também usa um terminal bash remoto para primeiro impedir o PM2 de gerenciar sua implantação anterior pelo comando delete e, em seguida, iniciar uma nova instância do seu servidor Node.js, fornecendo o arquivo ecosystem.config.js como uma variável. Além disso, você também avisa o PM2 que ele deve usar variáveis de ambiente a partir do bloco production na sua configuração inicial e pede ao PM2 para monitorar o aplicativo, reiniciando-o caso falhe.

O arquivo completo do shipitfile.js:

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

Salve e saia do arquivo quando estiver pronto.

Com seu shipitfile.js configurado, ouvintes de eventos e as tarefas finalizadas associadas, você pode prosseguir com a implantação para o servidor app.

Passo 5 — Implantando seu aplicativo

Neste passo, você implantará seu aplicativo remotamente e testará se a implantação disponibilizou seu aplicativo na internet.

Como o Shipit clona os arquivos do projeto do repositório remoto do Git, você precisa mandar seus arquivos do aplicativo local Node.js da sua máquina local para o Github. Navegue até o diretório do seu aplicativo do projeto Node.js (onde seu hello.js e shipitfile.js estão localizados) e execute o seguinte comando:

  • git status

O comando git status mostra o estado do diretório de trabalho e a área de preparação. Ele permite que você veja quais alterações foram preparadas, quais não foram e quais arquivos o Git não está rastreando. Seus arquivos não estão rastreados e aparecem em vermelho no 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)

Você pode adicionar esses arquivos ao seu repositório com o seguinte comando:

  • git add --all

Esse comando não gera nenhum resultado, embora caso fosse executar o git status novamente, os arquivos apareceriam em verde, com uma nota avisando que existem alterações a serem confirmadas.

Você pode criar uma confirmação, executando o seguinte comando:

  • git commit -m "Our first commit"

O resultado desse comando fornece algumas informações específicas do Git sobre os arquivos.

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

Agora, tudo o que resta é mandar sua confirmação para o repositório remoto, para que o Shipit clonar para o seu servidor app durante a implantação. Execute o seguinte comando:

  • git push origin master

O resultado inclui informações sobre a sincronização com o repositório 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 implantar seu aplicativo, execute o seguinte comando:

  • npx shipit production deploy

O resultado desse comando (que é grande demais para ser incluído por completo) fornece detalhes sobre as tarefas que estão sendo executadas e o resultado da função específica. O resultado que se segue à tarefa pm2-server mostra que o app Node.js foi 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 visualizar seu aplicativo como um usuário visualizaria, você pode digitar a URL your-domain do seu site em seu navegador para acessar o servidor web. Isso servirá o aplicativo Node.js, por proxy reverso, no servidor app, onde seus arquivos foram implantados.

Você verá uma saudação Hello World.

Nota: após a primeira implantação, seu repositório Git irá rastrear um arquivo recém-criado, chamado ecosystem.config.js. Como esse arquivo será recompilado a cada implantação, podendo conter segredos do aplicativo compilado, ele deve ser adicionado ao arquivo .gitignore, no diretório raiz do aplicativo em sua máquina local, antes da sua próxima confirmação do git.

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

Você implantou seu aplicativo Node.js em seu servidor app, que se refere à sua nova implantação. Com tudo em funcionamento, você pode prosseguir com o monitoramento dos processos do seu aplicativo.

Passo 6 — Monitorando seu aplicativo

O PM2 é uma ótima ferramenta para gerenciar seus processos remotos, mas também fornece recursos para monitorar o desempenho desses processos do aplicativo.

Conecte-se ao seu servidor app remoto via SSH com este comando:

  • ssh deployer@your_app_server_ip

Para obter informações específicas relacionadas aos seus processos gerenciados pelo PM2, execute o seguinte:

  • pm2 list

Você verá um resultado parecido com este:

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

Você verá um resumo das informações que o PM2 coletou. Para ver informações detalhadas, execute:

  • pm2 show hello

O resultado dá mais detalhes sobre as informações do resumo fornecidas pelo comando pm2 list. Ele também fornece informações sobre vários comandos auxiliares e fornece os locais dos arquivos 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 │ └───────────────────────────┴───────────────────────────────────────┘ . . .

O PM2 também fornece uma ferramenta de monitoramento dentro do terminal, que pode ser acessada com:

  • pm2 monit

O resultado desse comando é um painel interativo, onde o pm2 fornece informações de processo, registros, métricas e metadados em tempo real. Este painel pode ajudar no monitoramento de recursos e registros de erro:

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

Com uma compreensão sobre como você pode monitorar seus processos com o PM2, você pode prosseguir e ver como o Shipit pode ajudar na reversão para uma implantação anterior em funcionamento.

Termine sua sessão ssh no seu servidor app executando exit.

Passo 7 — Revertendo uma implantação problemática

Às vezes, as implantações revelam bugs imprevistos, ou problemas que fazem com que seu site falhe. Os desenvolvedores e mantenedores do Shipit previram esse problema e proporcionaram a capacidade de se fazer a reversão para implantações anteriores (em funcionamento) do seu aplicativo.

Para garantir que sua configuração PM2 permaneça, adicione outro ouvinte de eventos ao shipitfile.js no evento rollback (reversão):

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

Adicione um ouvinte ao evento rollback para executar suas tarefas npm-install e copy-config. Isso é necessário, pois, ao contrário do evento published, o evento updated não é executado pelo ciclo de vida do Shipit quando se reverte uma implantação. Adicionar esse ouvinte de eventos garante que seu gerenciador de processos PM2 apontará para a implantação mais recente, mesmo no caso de uma reversão.

Esse processo é semelhante ao da implantação, com uma pequena alteração no comando. Para tentar reverter para uma implantação anterior, execute o seguinte:

  • npx shipit production rollback

Assim como o comando deploy, o rollback fornece detalhes sobre o processo de reversão e as tarefas que estão sendo executadas:

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 ]

Você configurou o Shipit para manter 5 versões de lançamento, através da configuração de keepReleases: 5 no shipitfile.js. O Shipit monitora essas versões internamente para garantir a capacidade de reverter quando necessário. O Shipit também fornece uma maneira conveniente de identificar as versões, criando um diretório nomeado na forma de um carimbo de data/hora (YYYYMMDDHHmmss - Exemplo: /home/deployer/your-domain/releases/20190420210548).

Se quisesse personalizar ainda mais o processo de reversão, você poderia ouvir eventos específicos para a operação de reversão. Na sequência, você poderá usar esses eventos para executar tarefas que irão complementar sua reversão. Você pode consultar a lista de eventos fornecida no detalhamento do ciclo de vida do Shipit e configurar as tarefas/ouvintes dentro do seu shipitfile.js.

Capacidade de reversão significa que sempre será possível oferecer aos seus usuários uma versão do seu aplicativo que funcione, mesmo se uma implantação introduzir erros/problemas inesperados.

Conclusão

Neste tutorial, você configurou um fluxo de trabalho que permite que crie uma alternativa altamente personalizável da Plataforma como um Serviço, tudo a partir de alguns servidores. Esse fluxo de trabalho leva em consideração implantações e configurações personalizadas, o monitoramento de processos com o PM2, a possibilidade de dimensionar e adicionar serviços, servidores adicionais ou ambientes à implantação, quando necessário.

Se estiver interessado em continuar no desenvolvimento de suas habilidades com o Node.js, confira o material sobre Node.js da DigitalOcean, bem como a série sobre Como programar no Node.js.

0 Comments

Creative Commons License